This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] Support inferior events in python


This patch contains changes requested by Eli and Tom, and includes documentation for the new features.

Instead of evregpy_get_nlisteners checking the list size, I think it
would be better to have "evregpy_any_listeners_p" return a boolean, and
then check whether the list is empty.  This may be more efficient and is
what you want to do anyhow.


How about evregpy_no_listeners_p ? Fits better with the way the code was written.


Sami>  +event_object *
Sami>  +create_event_object (PyTypeObject *py_type)
Sami>  +{
Sami>  +  event_object *event_obj;
Sami>  +
Sami>  +  event_obj = PyObject_New (event_object, py_type);
Sami>  +  if (!event_obj)
Sami>  +    goto fail;
Sami>  +
Sami>  +  event_obj->dict = PyDict_New ();
Sami>  +  if (!event_obj->dict)
Sami>  +    goto fail;
Sami>  +
Sami>  +  return event_obj;
Sami>  +
Sami>  + fail:
Sami>  +  Py_XDECREF (event_obj);
Sami>  +  Py_XDECREF (event_obj->dict);

Won't decrefing event_obj automatically free the dict when needed?
I didn't look closely but maybe other create_* functions have this issue.


I fixed all the create_* functions and made sure the dealloc functions are using Py_XDECREF.


Sami>  +static int
Sami>  +add_new_registry (eventregistry_object **registryp, char *name)
Sami>  +{
Sami>  +  *registryp = create_eventregistry_object ();
Sami>  +  if(*registryp == NULL)

Newline between these lines.
Space before open paren.

Why not just return the new registry, or NULL on error?
That would be simpler.


Adding the registry, and doing the needed error checking here, makes the calling code simpler. The calling code is what will be extended in future development.



Sami> +static void Sami> +python_inferior_exit (struct inferior *inf) Sami> +{ Sami> + struct cleanup *cleanup; Sami> + LONGEST exitcode_val; Sami> + LONGEST *exit_code; Sami> + Sami> + cleanup = ensure_python_env (get_current_arch (), current_language); Sami> + Sami> + if (get_internalvar_integer (lookup_internalvar ("_exitcode"),&exitcode_val)) Sami> + exit_code =&exitcode_val; Sami> + Sami> + if (exit_code Sami> +&& emit_exited_event (exit_code)< 0)

You have to initialize exit_code to NULL for this to work properly.


Done.


However, I think this is pretty ugly.
It seems like there should be a better way to get this than looking up
a convenience variable.


Hmm I looked through the code to find another way but could not. handle_inferior_event which sets the convenience variable uses execution_control_state which I don't have access to.


I think we need an event representing a thread exit.
It is ok by me if this comes in a separate patch.
(FWIW I have a few new events on my branch; I'll update those once this
patch goes in.)


In the original patch this event was halfway between thread exit and inferior exit. So I decided to make it inferior exit with the intention on adding thread exited/created events in a future patch.


Sami>  +  signal_event_obj->stop_signal =
Sami>  +      (PyStringObject *) PyString_FromString (stop_signal);

It is more usual to just use PyObject* everywhere, and not cast to the
more specific types.

This change should let you eliminate other casts in the patch.


Done. I also, updated breakpoint_event_object. I was going with the oposite mindset of keeping the type information until a cast is required.


Sami>  +stop_event_object *
Sami>  +create_stop_event_object (PyTypeObject *py_type, thread_object *thread)
Sami>  +{
Sami>  +  stop_event_object *stop_event_obj =
Sami>  +      (stop_event_object *) create_event_object (py_type);
Sami>  +
Sami>  +  if (!stop_event_obj)
Sami>  +    goto fail;
Sami>  +
Sami>  +  stop_event_obj->inferior_thread = (PyObject *) thread;
Sami>  +
Sami>  +  if (evpy_add_attribute ((event_object *) stop_event_obj,
Sami>  +                          "inferior_thread",
Sami>  +                          stop_event_obj->inferior_thread)<  0)
Sami>  +    goto fail;
Sami>  +
Sami>  +
Sami>  +  return stop_event_obj;

I think it would be better to just have one cast at the end, instead of
lots of casts in the body.


Hmm if I change stop_event_object* to event_object it would eliminate two casts but also add two. One when setting the inferior thread and one for returning. Same goes for all the create_* functions or should I change all of those to return more generic objects ?


Sami>  +  if (bs&&  bs->breakpoint_at
Sami>  +&&  bs->breakpoint_at->type == bp_breakpoint)
Sami>  +    {
Sami>  +      if (evregpy_get_nlisteners (gdb_py_events.breakpoint) == 0)
Sami>  +	return 0;

I think the short-circuiting logic should be hoisted to the top of the
function.  This is more efficient and also lets you avoid having to
deal with reference counting problems involving objects made earlier.


I moved the thread creation after the short circuiting, but I cannot be moved up further because we have to figure out the type of event.


Sami>  +  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
Sami>  +  if ((strcmp (stop_signal, "0") != 0)
Sami>  +&&  (strcmp (stop_signal, "SIGTRAP") != 0))

I didn't look this up, but this seems questionable.
Is this really how this is done?


I improved this by using enum target_signal and target_signal_to_name to convert the signal to a string when notifying python listeners. That looks OK IMO, but we can also create a module gdb.signal, create a pyhon Signal type, add Signal types for all signals to gdb.signal, and use a Signal object to notify python listeners.



Sami>  +typedef struct
Sami>  +{
Sami>  +  PyObject *inferior_thread;
Sami>  +  event_object event;
Sami>  +} stop_event_object;

For the inheritance scheme to work, the 'event' field has to come first.
I didn't audit the other event object types, but please make sure they
are all correct.


Corrected and checked other objects.



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..7e80dd4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,31 @@
+2010-12-22  Sami Wagiaalla  <swagiaal@redhat.com>
+                Oguz Kayral <oguzkayral@gmail.com>
+
+	* python/py-inferior.c (python_on_normal_stop): New function.
+	(python_on_resume): New function.
+	(python_inferior_exit): New function.
+	(gdbpy_initialize_inferior): Add normal_stop, target_resumed, and
+	inferior_exit observers.
+	* python/py-eventregistry.c: New file.
+	* python/py-event.c: New file.
+	* python/py-events.c: New file.
+	* python/py-continueevent.c: New file.
+	* python/py-breakpointevent.c : New file.
+	* python/py-signalevent.c : New file.
+	* python/py-exetiedevent.c : New file.
+	* python/py-breakpoint.c (gdbpy_breakpoint_from_bpstats): New function.
+	Move struct breakpoint_object from here...
+	* python/python-internal.h: ... to here.
+	* python/py-event.h: New file.
+	* python/py-events.h: New file.
+	* Makefile.in (SUBDIR_PYTHON_OBS): Add py-breakpointstopevent.o,
+	py-continueevent.o, py-event.o, py-eventregistry.o, py-events.o,
+	py-exitedevent.o, py-signalstopevent.o, and py-stopevent.o.
+	(SUBDIR_PYTHON_SRCS): Add py-breakpointstopevent.c,
+	py-continueevent.c, py-event.c, py-eventregistry.c, py-events.c,
+	py-exitedevent.c, py-signalstopevent.c, and py-stopevent.c.
+	Add build rules for all the above.
+
 2010-12-14  Ken Werner  <ken.werner@de.ibm.com>
 
 	* valops.c (value_one): Use get_array_bounds to compute the number
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ff10039..ec309ff 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -272,8 +272,14 @@ SUBDIR_PYTHON_OBS = \
 	python.o \
 	py-auto-load.o \
 	py-block.o \
+	py-bpevent.o \
 	py-breakpoint.o \
 	py-cmd.o \
+	py-continueevent.o \
+	py-event.o \
+	py-evtregistry.o \
+	py-evts.o \
+	py-exitedevent.o \
 	py-frame.o \
 	py-function.o \
 	py-inferior.o \
@@ -283,17 +289,26 @@ SUBDIR_PYTHON_OBS = \
 	py-param.o \
 	py-prettyprint.o \
 	py-progspace.o \
+	py-signalevent.o \
+	py-stopevent.o \
 	py-symbol.o \
 	py-symtab.o \
 	py-type.o \
 	py-utils.o \
 	py-value.o
+
 SUBDIR_PYTHON_SRCS = \
 	python/python.c \
 	python/py-auto-load.c \
 	python/py-block.c \
+	python/py-bpevent.c \
 	python/py-breakpoint.c \
 	python/py-cmd.c \
+	python/py-continueevent.c \
+	python/py-event.c \
+	python/py-evtregistry.c \
+	python/py-evts.c \
+	python/py-exitedevent.c \
 	python/py-frame.c \
 	python/py-function.c \
 	python/py-inferior.c \
@@ -303,6 +318,8 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-param.c \
 	python/py-prettyprint.c \
 	python/py-progspace.c \
+	python/py-signalevent.c \
+	python/py-stopevent.c \
 	python/py-symbol.c \
 	python/py-symtab.c \
 	python/py-type.c \
@@ -1992,6 +2009,10 @@ py-block.o: $(srcdir)/python/py-block.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
 	$(POSTCOMPILE)
 
+py-bpevent.o: $(srcdir)/python/py-bpevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-bpevent.c
+	$(POSTCOMPILE)
+
 py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
 	$(POSTCOMPILE)
@@ -2000,6 +2021,26 @@ py-cmd.o: $(srcdir)/python/py-cmd.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
 	$(POSTCOMPILE)
 
+py-continueevent.o: $(srcdir)/python/py-continueevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-continueevent.c
+	$(POSTCOMPILE)
+
+py-event.o: $(srcdir)/python/py-event.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-event.c
+	$(POSTCOMPILE)
+
+py-evtregistry.o: $(srcdir)/python/py-evtregistry.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-evtregistry.c
+	$(POSTCOMPILE)
+
+py-evts.o: $(srcdir)/python/py-evts.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-evts.c
+	$(POSTCOMPILE)
+
+py-exitedevent.o: $(srcdir)/python/py-exitedevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-exitedevent.c
+	$(POSTCOMPILE)
+
 py-frame.o: $(srcdir)/python/py-frame.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c
 	$(POSTCOMPILE)
@@ -2036,6 +2077,14 @@ py-progspace.o: $(srcdir)/python/py-progspace.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-progspace.c
 	$(POSTCOMPILE)
 
+py-signalevent.o: $(srcdir)/python/py-signalevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-signalevent.c
+	$(POSTCOMPILE)
+
+py-stopevent.o: $(srcdir)/python/py-stopevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-stopevent.c
+	$(POSTCOMPILE)
+
 py-symbol.o: $(srcdir)/python/py-symbol.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symbol.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 559609b..a51740e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,15 @@
 
 *** Changes since GDB 7.2
 
+* Python Support for Inferior events.
+  Python scripts can add observers to be notified of events
+  occurring the in process being debugged.
+  The following events are currently supported:
+  - gdb.events.breakpoint Breakpoint hit event.
+  - gdb.events.cont Continue event.
+  - gdb.events.signal Signal received event.
+  - gdb.events.exited Inferior exited event.
+
 * New command line options
 
 -data-directory DIR	Specify DIR as the "data-directory".
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dc9630a..31dea4c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -20700,6 +20700,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
 * Selecting Pretty-Printers::   How GDB chooses a pretty-printer.
 * Writing a Pretty-Printer::    Writing a Pretty-Printer.
 * Inferiors In Python::         Python representation of inferiors (processes)
+* Inferior Events In Python::   Listening for events from the process being debugged.
 * Threads In Python::           Accessing inferior threads from Python.
 * Commands In Python::          Implementing new commands in Python.
 * Parameters In Python::        Adding new @value{GDBN} parameters.
@@ -21863,6 +21864,70 @@ the pattern could not be found.
 @end defmethod
 @end table
 
+@node Inferior Events In Python
+@subsubsection Inferior Events In Python
+@cindex inferior events in python
+
+The Python API allows scripts to listen for events coming from the inferior process
+and its threads. In order to listen for events the script must register an observer
+by connecting it to the appropriate event registry. Event registries can be accessed
+through the @code{gdb.events} module.
+
+Here is an example:
+
+@smallexample
+def exit_handler (event):
+    if (isinstance (event, gdb.ExitedEvent)):
+        print "event type: exit"
+        print "exit code: %d" % (event.exit_code)
+
+gdb.events.exited.connect (exit_handler)
+@end smallexample
+
+The following is a listing of the event registries that are available and details
+of the events they emit:
+
+@table @code
+@item events.breakpoint
+@item events.cont
+@item events.exited
+@item events.signal
+@end table
+
+These registries emit the following events in respective order:
+
+@table @code
+@item events.BreakpointEvent
+Indicates that a breakpoint was hit and has the following attributes
+@defivar BreakpointEvent breakpoint
+Reference to the breakpoint of type @code{gdb.Breakpoint} that was hit.
+@xref{Breakpoints In Python}, for details of the @code{gdb.Breakpoint}
+object.
+@end defivar
+@defivar BreakpointEvent inferior_thread
+In non-stop mode breakpoints only stop the thread that has hit them. If
+@value{GDBN} is running in non-stop mode this attribute will hold a reference
+to the thread that has stopped. This object will be of type @code{gdb.InferiorThread}
+@xref{Threads In Python}, for details of the @code{gdb.Breakpoint} object.
+If all threads are stopped the value of this attribute will be @code{None}.
+@end defivar
+@item events.ContinueEvent
+Indicates that the inferior has been continued.
+@item events.ExitedEvent
+Indicates that the inferior has exited.
+@defivar ExitedEvent exit_code
+The exit code that the inferior has returned.
+@end defivar
+@item events.SignalEvent
+@defivar SignalEvent inferior_thread
+In non-stop mode this attribute will be set to the specific thread that received the signal
+and @code{None} otherwise.
+@end defivar
+@defivar SignalEvent stop_signal
+The signal received by the inferior
+@end defivar
+@end table
+
 @node Threads In Python
 @subsubsection Threads In Python
 @cindex threads in python
@@ -23256,10 +23321,31 @@ top of the source tree to the source search path.
 @value{GDBN} comes with a module to assist writing Python code.
 
 @menu
+* gdb.events::         Registering observers to listen to inferior events.
 * gdb.printing::       Building and registering pretty-printers.
 * gdb.types::          Utilities for working with types.
 @end menu
 
+@node gdb.events
+@subsubsection gdb.events
+@cindex gdb.events
+
+This module provides access to inferior event registries. Add observers
+to these registries to receive notification about inferior events.
+
+The available registries are:
+
+@table @code
+@item events.breakpoint
+Notifies listeners of breakpoints being hit.
+@item events.cont
+Notifies listeners whenever the inferior, or one of its threads, is continued.
+@item events.exited
+Notifies listeners when the inferior exits.
+@item events.signal
+Notifies listeners of the inferior, or one of its threads,receiving a signal.
+@end table
+
 @node gdb.printing
 @subsubsection gdb.printing
 @cindex gdb.printing
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644
index 0000000..7dbef53
--- /dev/null
+++ b/gdb/python/py-bpevent.c
@@ -0,0 +1,65 @@
+/* Python interface to inferior breakpoint stop events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "py-stopevent.h"
+
+static PyTypeObject breakpoint_event_object_type;
+
+static void
+breakpoint_evpy_dealloc (PyObject *self)
+{
+  Py_XDECREF (((breakpoint_event_object *) self)->breakpoint);
+  stop_evpy_dealloc (self);
+}
+
+/* Create and initialize a BreakpointEvent object.  */
+
+breakpoint_event_object *
+create_breakpoint_event_object (struct bpstats *bs,
+                                PyObject *stopped_thread)
+{
+  breakpoint_event_object *breakpoint_event_obj =
+      (breakpoint_event_object *)
+      create_stop_event_object (&breakpoint_event_object_type,
+                                stopped_thread);
+
+  if (!breakpoint_event_obj)
+    goto fail;
+
+  breakpoint_event_obj->breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+  Py_INCREF (breakpoint_event_obj->breakpoint);
+
+  if (evpy_add_attribute ((event_object *) breakpoint_event_obj,
+                          "breakpoint",
+                          breakpoint_event_obj->breakpoint) < 0)
+    goto fail;
+
+  return breakpoint_event_obj;
+
+ fail:
+  Py_XDECREF (breakpoint_event_obj);
+  return NULL;
+}
+
+GDBPY_NEW_EVENT_TYPE (breakpoint,
+                      "gdb.BreakpointEvent",
+                      "BreakpointEvent",
+                      "GDB breakpoint stop event object",
+                      stop_event_object_type,
+                      static);
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 88d9930..35203e4 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -29,9 +29,6 @@
 #include "cli/cli-script.h"
 #include "ada-lang.h"
 
-/* From breakpoint.c.  */
-typedef struct breakpoint_object breakpoint_object;
-
 static PyTypeObject breakpoint_object_type;
 
 /* Number of live breakpoints.  */
@@ -283,6 +280,15 @@ bppy_set_task (PyObject *self, PyObject *newvalue, void *closure)
   return 0;
 }
 
+/* Function to get the corresponding breakpoint object for the given
+   bpstats.  */
+
+PyObject *
+gdbpy_breakpoint_from_bpstats (struct bpstats *bs)
+{
+  return (PyObject *) bs->breakpoint_at->py_bp_object;
+}
+
 /* Python function which deletes the underlying GDB breakpoint.  This
    triggers the breakpoint_deleted observer which will call
    gdbpy_breakpoint_deleted; that function cleans up the Python
diff --git a/gdb/python/py-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..320c969
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,65 @@
+/* Python interface to inferior continue events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "py-event.h"
+
+static PyTypeObject continue_event_object_type;
+
+typedef struct
+{
+  event_object event;
+} continue_event_object;
+
+static void
+continue_evpy_dealloc (PyObject *self)
+{
+  evpy_dealloc (self);
+}
+
+continue_event_object *
+create_continue_event_object (void)
+{
+  return (continue_event_object *)
+      create_event_object (&continue_event_object_type);
+}
+
+/* Callback function which notifies observers when a continue event occurs.
+   This function will create a new Python continue event object.
+   Return -1 if emit fails.  */
+
+int
+emit_continue_event (ptid_t ptid)
+{
+  event_object *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.cont))
+    return 0;
+
+  event = (event_object *) create_continue_event_object ();
+  if (event)
+    return evpy_emit_event (event, gdb_py_events.cont);
+  return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (continue,
+                      "gdb.ContinueEvent",
+                      "ContinueEvent",
+                      "GDB continue event object",
+                      event_object_type,
+                      static);
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..99dd7bc
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,178 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "py-event.h"
+
+void
+evpy_dealloc (PyObject *self)
+{
+  Py_XDECREF (((event_object *) self)->dict);
+  self->ob_type->tp_free (self);
+}
+
+event_object *
+create_event_object (PyTypeObject *py_type)
+{
+  event_object *event_obj;
+
+  event_obj = PyObject_New (event_object, py_type);
+  if (!event_obj)
+    goto fail;
+
+  event_obj->dict = PyDict_New ();
+  if (!event_obj->dict)
+    goto fail;
+
+  return event_obj;
+
+ fail:
+  Py_XDECREF (event_obj);
+  return NULL;
+}
+
+/* Add the attribute ATTR to the event object EVENT.  In
+   python this attribute will be accessible by the name NAME.
+   returns 0 if the operation succeeds and -1 otherwise.  */
+
+int
+evpy_add_attribute (event_object *event, char *name, PyObject *attr)
+{
+  return PyObject_SetAttrString ((PyObject *) event, name, attr);
+}
+
+/* Initialize the Python event code.  */
+
+void
+gdbpy_initialize_event (void)
+{
+  gdbpy_initialize_event_generic (&event_object_type,
+                                  "Event");
+}
+
+/* Initialize the given event type.  If BASE is not NULL it will
+  be set as the types base.
+  Returns 0 if initialization was successful -1 otherwise.  */
+
+int
+gdbpy_initialize_event_generic (PyTypeObject *type,
+                                char *name)
+{
+  if (PyType_Ready (type) < 0)
+    goto fail;
+
+  Py_INCREF (type);
+  if (PyModule_AddObject (gdb_module, name, (PyObject *) type) < 0)
+    goto fail;
+
+  return 0;
+
+  fail:
+    Py_XDECREF (type);
+    return -1;
+}
+
+
+/* Notify the list of listens that the given EVENT has occurred.
+   returns 0 if emit is successful -1 otherwise.  */
+
+int
+evpy_emit_event (event_object *event,
+                 eventregistry_object *registry)
+{
+  PyObject *callback_list, *event_obj = (PyObject *) event;
+  PyObject *callback_list_copy = NULL;
+  Py_ssize_t i;
+
+  callback_list = (PyObject *) registry->callbacks;
+
+  /* Create a copy of call back list and use that for
+     notifying listeners to avoid skipping callbacks
+     in the case of a callback being disconnected during
+     a notification.  */
+  callback_list_copy = PySequence_List (callback_list);
+  if (!callback_list_copy)
+    goto fail;
+
+  for (i = 0; i < PyList_Size (callback_list_copy); i++)
+    {
+      PyObject *func = PyList_GetItem (callback_list_copy, i);
+
+      if (func == NULL)
+	goto fail;
+
+      if (!PyObject_CallFunctionObjArgs (func, event_obj, NULL))
+	{
+	  /* Print the trace here, but keep going -- we want to try to
+	     call all of the callbacks even if one is broken.  */
+	  gdbpy_print_stack ();
+	}
+    }
+
+  Py_XDECREF (callback_list_copy);
+  Py_XDECREF (event_obj);
+  return 0;
+
+ fail:
+  gdbpy_print_stack ();
+  Py_XDECREF (callback_list_copy);
+  Py_XDECREF (event_obj);
+  return -1;
+}
+
+PyTypeObject event_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,                                          /* ob_size */
+  "gdb.Event",                                /* tp_name */
+  sizeof (event_object),                      /* tp_basicsize */
+  0,                                          /* tp_itemsize */
+  evpy_dealloc,                               /* tp_dealloc */
+  0,                                          /* tp_print */
+  0,                                          /* tp_getattr */
+  0,                                          /* tp_setattr */
+  0,                                          /* tp_compare */
+  0,                                          /* tp_repr */
+  0,                                          /* tp_as_number */
+  0,                                          /* tp_as_sequence */
+  0,                                          /* tp_as_mapping */
+  0,                                          /* tp_hash  */
+  0,                                          /* tp_call */
+  0,                                          /* tp_str */
+  0,                                          /* tp_getattro */
+  0,                                          /* tp_setattro */
+  0,                                          /* tp_as_buffer */
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
+  "GDB event object",                         /* tp_doc */
+  0,                                          /* tp_traverse */
+  0,                                          /* tp_clear */
+  0,                                          /* tp_richcompare */
+  0,                                          /* tp_weaklistoffset */
+  0,                                          /* tp_iter */
+  0,                                          /* tp_iternext */
+  0,                                          /* tp_methods */
+  0,                                          /* tp_members */
+  0,                                          /* tp_getset */
+  0,                                          /* tp_base */
+  0,                                          /* tp_dict */
+  0,                                          /* tp_descr_get */
+  0,                                          /* tp_descr_set */
+  offsetof (event_object, dict),              /* tp_dictoffset */
+  0,                                          /* tp_init */
+  0                                           /* tp_alloc */
+};
diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h
new file mode 100644
index 0000000..8d7af2a
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,119 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_PY_EVENT_H
+#define GDB_PY_EVENT_H
+
+#include "defs.h"
+#include "py-events.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+/* This macro creates the following functions:
+
+     gdbpy_initialize_{NAME}_event
+     Used to add the newly created event type to the gdb module.
+
+   and the python type data structure for the event:
+
+     struct PyTypeObject {NAME}_event_object_type
+
+  NAME is the name of the event.
+  PY_PATH is a string representing the module and python name of
+    the event.
+  PY_NAME a string representing what the event should be called in
+    python.
+  DOC Python documentation for the new event type
+  BASE the base event for this event usually just event_object_type.
+  QUAL qualification for the create event usually 'static'
+*/
+
+#define GDBPY_NEW_EVENT_TYPE(name, py_path, py_name, doc, base, qual) \
+\
+    qual PyTypeObject name##_event_object_type = \
+    { \
+      PyObject_HEAD_INIT (NULL) \
+      0,                                          /* ob_size */ \
+      py_path,                                    /* tp_name */ \
+      sizeof (name##_event_object),               /* tp_basicsize */ \
+      0,                                          /* tp_itemsize */ \
+      name##_evpy_dealloc,                        /* tp_dealloc */ \
+      0,                                          /* tp_print */ \
+      0,                                          /* tp_getattr */ \
+      0,                                          /* tp_setattr */ \
+      0,                                          /* tp_compare */ \
+      0,                                          /* tp_repr */ \
+      0,                                          /* tp_as_number */ \
+      0,                                          /* tp_as_sequence */ \
+      0,                                          /* tp_as_mapping */ \
+      0,                                          /* tp_hash  */ \
+      0,                                          /* tp_call */ \
+      0,                                          /* tp_str */ \
+      0,                                          /* tp_getattro */ \
+      0,                                          /* tp_setattro */ \
+      0,                                          /* tp_as_buffer */ \
+      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */ \
+      doc,                                        /* tp_doc */ \
+      0,                                          /* tp_traverse */ \
+      0,                                          /* tp_clear */ \
+      0,                                          /* tp_richcompare */ \
+      0,                                          /* tp_weaklistoffset */ \
+      0,                                          /* tp_iter */ \
+      0,                                          /* tp_iternext */ \
+      0,                                          /* tp_methods */ \
+      0,                                          /* tp_members */ \
+      0,                                          /* tp_getset */ \
+      &base,                                      /* tp_base */ \
+      0,                                          /* tp_dict */ \
+      0,                                          /* tp_descr_get */ \
+      0,                                          /* tp_descr_set */ \
+      0,                                          /* tp_dictoffset */ \
+      0,                                          /* tp_init */ \
+      0                                           /* tp_alloc */ \
+    }; \
+\
+void \
+gdbpy_initialize_##name##_event (void) \
+{ \
+  gdbpy_initialize_event_generic (&name##_event_object_type, \
+                                  py_name); \
+}
+
+typedef struct
+{
+  PyObject_HEAD
+
+  PyObject *dict;
+} event_object;
+
+extern int emit_stop_event (struct bpstats *bs, enum target_signal stop_signal);
+extern int emit_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST *exit_code);
+
+extern int evpy_emit_event (event_object *event,
+                            eventregistry_object *registry);
+extern event_object * create_event_object (PyTypeObject *py_type);
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (event_object *event,
+                               char *name, PyObject *attr);
+int gdbpy_initialize_event_generic (PyTypeObject *type, char *name);
+
+
+#endif /* GDB_PY_EVENT_H */
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
new file mode 100644
index 0000000..31e5604
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,60 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_PY_EVENTS_H
+#define GDB_PY_EVENTS_H
+
+#include "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+
+/* Stores a list of objects to be notified when the event for which this
+   registry tracks occurs.  */
+
+typedef struct
+{
+  PyObject_HEAD
+
+  PyListObject *callbacks;
+} eventregistry_object;
+
+/* Struct holding references to event registries both in python and c.
+   This is meant to be a singleton.  */
+
+typedef struct
+{
+  eventregistry_object *stop;
+  eventregistry_object *breakpoint;
+  eventregistry_object *signal;
+  eventregistry_object *cont;
+  eventregistry_object *exited;
+
+  PyObject *module;
+
+} events_object;
+
+/* Python events singleton.  */
+events_object gdb_py_events;
+
+extern eventregistry_object *create_eventregistry_object (void);
+extern int evregpy_no_listeners_p (eventregistry_object *registry);
+
+#endif /* GDB_PY_EVENTS_H */
diff --git a/gdb/python/py-evtregistry.c b/gdb/python/py-evtregistry.c
new file mode 100644
index 0000000..e85e483
--- /dev/null
+++ b/gdb/python/py-evtregistry.c
@@ -0,0 +1,180 @@
+/* Python interface to inferior thread event registries.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "command.h"
+#include "py-events.h"
+
+static PyTypeObject eventregistry_object_type;
+
+/* Implementation of EventRegistry.connect () -> NULL.
+   Add FUNCTION to the list of listeners.  */
+
+static PyObject *
+evregpy_connect (PyObject *self, PyObject *function)
+{
+  PyObject *func;
+  PyObject *callback_list = (PyObject *)
+    (((eventregistry_object *) self)->callbacks);
+
+  if (!PyArg_ParseTuple (function, "O", &func))
+    return NULL;
+
+  if (!PyCallable_Check (func))
+    {
+      PyErr_SetString (PyExc_RuntimeError, "Function is not callable");
+      return NULL;
+    }
+
+  PyList_Append (callback_list, func);
+
+  Py_RETURN_NONE;
+}
+
+/* Implementation of EventRegistry.disconnect () -> NULL.
+   Remove FUNCTION from the list of listeners.  */
+
+static PyObject *
+evregpy_disconnect (PyObject *self, PyObject *function)
+{
+  PyObject *func;
+  int index;
+  PyObject *callback_list = (PyObject *)
+    (((eventregistry_object *) self)->callbacks);
+
+  if (!PyArg_ParseTuple (function, "O", &func))
+    return NULL;
+
+  if (!PyCallable_Check (func))
+    {
+      PyErr_SetString (PyExc_RuntimeError, "Function is not callable");
+      return NULL;
+    }
+
+  index = PySequence_Index (callback_list, func);
+  if (index < 0)
+    {
+      PyErr_SetString (PyExc_RuntimeError, "Function not found");
+      return NULL;
+    }
+
+  if (PySequence_DelItem (callback_list, index) < 0)
+    return NULL;
+
+  Py_RETURN_NONE;
+}
+
+/* Create a new event registry.  This function uses PyObject_New
+   and therefore returns a new reference that callers must handle.  */
+
+eventregistry_object *
+create_eventregistry_object (void)
+{
+  eventregistry_object *eventregistry_obj;
+
+  eventregistry_obj = PyObject_New (eventregistry_object,
+                                    &eventregistry_object_type);
+
+  if (!eventregistry_obj)
+    return NULL;
+
+  eventregistry_obj->callbacks = (PyListObject *) PyList_New (0);
+  if (!eventregistry_obj->callbacks)
+    return NULL;
+
+  return eventregistry_obj;
+}
+
+static void
+evregpy_dealloc (PyObject *self)
+{
+  Py_XDECREF (((eventregistry_object *) self)->callbacks);
+  self->ob_type->tp_free (self);
+}
+
+/* Initialize the Python event registry code.  */
+
+void
+gdbpy_initialize_eventregistry (void)
+{
+  if (PyType_Ready (&eventregistry_object_type) < 0)
+    return;
+
+  Py_INCREF (&eventregistry_object_type);
+  PyModule_AddObject (gdb_module, "EventRegistry",
+                      (PyObject *) &eventregistry_object_type);
+}
+
+/* Retern the number of listeners currently connected to this
+   registry.  */
+
+int
+evregpy_no_listeners_p (eventregistry_object *registry)
+{
+  return PyList_Size ((PyObject *) registry->callbacks) == 0;
+}
+
+static PyMethodDef eventregistry_object_methods[] =
+{
+  { "connect", evregpy_connect, METH_VARARGS, "Add function" },
+  { "disconnect", evregpy_disconnect, METH_VARARGS, "Remove function" },
+  { NULL } /* Sentinel.  */
+};
+
+static PyTypeObject eventregistry_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,                                          /* ob_size */
+  "gdb.EventRegistry",                        /* tp_name */
+  sizeof (eventregistry_object),              /* tp_basicsize */
+  0,                                          /* tp_itemsize */
+  evregpy_dealloc,                            /* tp_dealloc */
+  0,                                          /* tp_print */
+  0,                                          /* tp_getattr */
+  0,                                          /* tp_setattr */
+  0,                                          /* tp_compare */
+  0,                                          /* tp_repr */
+  0,                                          /* tp_as_number */
+  0,                                          /* tp_as_sequence */
+  0,                                          /* tp_as_mapping */
+  0,                                          /* tp_hash  */
+  0,                                          /* tp_call */
+  0,                                          /* tp_str */
+  0,                                          /* tp_getattro */
+  0,                                          /* tp_setattro */
+  0,                                          /* tp_as_buffer */
+  Py_TPFLAGS_DEFAULT,                         /* tp_flags */
+  "GDB event registry object",                /* tp_doc */
+  0,                                          /* tp_traverse */
+  0,                                          /* tp_clear */
+  0,                                          /* tp_richcompare */
+  0,                                          /* tp_weaklistoffset */
+  0,                                          /* tp_iter */
+  0,                                          /* tp_iternext */
+  eventregistry_object_methods,               /* tp_methods */
+  0,                                          /* tp_members */
+  0,                                          /* tp_getset */
+  0,                                          /* tp_base */
+  0,                                          /* tp_dict */
+  0,                                          /* tp_descr_get */
+  0,                                          /* tp_descr_set */
+  0,                                          /* tp_dictoffset */
+  0,                                          /* tp_init */
+  0                                           /* tp_alloc */
+};
diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c
new file mode 100644
index 0000000..8301b99
--- /dev/null
+++ b/gdb/python/py-evts.c
@@ -0,0 +1,77 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "py-events.h"
+
+/* Initialize python events.  */
+
+static int
+add_new_registry (eventregistry_object **registryp, char *name)
+{
+  *registryp = create_eventregistry_object ();
+
+  if (*registryp == NULL)
+    goto fail;
+
+  if (PyModule_AddObject (gdb_py_events.module,
+                             name,
+                             (PyObject *)(*registryp)) < 0)
+    goto fail;
+
+  return 0;
+
+  fail:
+   Py_XDECREF (*registryp);
+   return -1;
+}
+
+void
+gdbpy_initialize_py_events ()
+{
+  gdb_py_events.module = Py_InitModule ("events", NULL);
+
+  if (!gdb_py_events.module)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.stop, "stop") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.breakpoint, "breakpoint") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.cont, "cont") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.exited, "exited") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.signal, "signal") < 0)
+    goto fail;
+
+  Py_INCREF (gdb_py_events.module);
+  if (PyModule_AddObject (gdb_module,
+                          "events",
+                          (PyObject *) gdb_py_events.module) < 0)
+    goto fail;
+
+  return;
+
+  fail:
+   gdbpy_print_stack ();
+}
diff --git a/gdb/python/py-exitedevent.c b/gdb/python/py-exitedevent.c
new file mode 100644
index 0000000..357508c
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,86 @@
+/* Python interface to inferior exit events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "py-event.h"
+
+static PyTypeObject exited_event_object_type;
+
+typedef struct
+{
+  event_object event;
+  PyObject *exit_code;
+} exited_event_object;
+
+static void
+exited_evpy_dealloc (PyObject *self)
+{
+  Py_XDECREF (((exited_event_object *) self)->exit_code);
+  evpy_dealloc (self);
+}
+
+exited_event_object *
+create_exited_event_object (LONGEST *exit_code)
+{
+  exited_event_object *exited_event;
+
+  exited_event = (exited_event_object *)
+      create_event_object (&exited_event_object_type);
+
+  if (!exited_event)
+    goto fail;
+
+  exited_event->exit_code = PyLong_FromLongLong (*exit_code);
+  if (evpy_add_attribute ((event_object *) exited_event,
+                          "exit_code",
+                          exited_event->exit_code) < 0)
+    goto fail;
+
+  return exited_event;
+
+  fail:
+   Py_XDECREF (exited_event);
+   return NULL;
+}
+
+/* Callback that is used when an exit event occurs.  This function
+   will create a new Python exited event object.  */
+
+int
+emit_exited_event (LONGEST *exit_code)
+{
+  event_object *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.exited))
+    return 0;
+
+  event = (event_object *) create_exited_event_object (exit_code);
+
+  if (event)
+    return evpy_emit_event (event, gdb_py_events.exited);
+
+  return -1;
+}
+
+
+GDBPY_NEW_EVENT_TYPE (exited,
+                      "gdb.ExitedEvent",
+                      "ExitedEvent",
+                      "GDB exited event object",
+                      event_object_type,
+                      static);
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 6382dab..240c257 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -26,6 +26,9 @@
 #include "python-internal.h"
 #include "arch-utils.h"
 #include "language.h"
+#include "gdb_signals.h"
+#include "py-event.h"
+#include "py-stopevent.h"
 
 struct threadlist_entry {
   thread_object *thread_obj;
@@ -73,6 +76,57 @@ static PyTypeObject membuf_object_type;
       }								\
   } while (0)
 
+static void
+python_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+  struct cleanup *cleanup;
+  enum target_signal stop_signal;
+
+  if (!find_thread_ptid (inferior_ptid))
+      return;
+
+  stop_signal = inferior_thread ()->suspend.stop_signal;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  if (emit_stop_event (bs, stop_signal) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_on_resume (ptid_t ptid)
+{
+  struct cleanup *cleanup;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  if (emit_continue_event (ptid) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
+static void
+python_inferior_exit (struct inferior *inf)
+{
+  struct cleanup *cleanup;
+  LONGEST exitcode_val;
+  LONGEST *exit_code = NULL;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  if (get_internalvar_integer (lookup_internalvar ("_exitcode"), &exitcode_val))
+    exit_code = &exitcode_val;
+
+  if (exit_code
+      && emit_exited_event (exit_code) < 0)
+    gdbpy_print_stack ();
+
+  do_cleanups (cleanup);
+}
+
 /* Return a borrowed reference to the Python object of type Inferior
    representing INFERIOR.  If the object has already been created,
    return it,  otherwise, create it.  Return NULL on failure.  */
@@ -108,8 +162,8 @@ inferior_to_inferior_object (struct inferior *inferior)
 
 /* Finds the Python Inferior object for the given PID.  Returns a
    borrowed reference, or NULL if PID does not match any inferior
-   obect.
-  */
+   object.  */
+
 PyObject *
 find_inferior_object (int pid)
 {
@@ -590,6 +644,9 @@ gdbpy_initialize_inferior (void)
 
   observer_attach_new_thread (add_thread_object);
   observer_attach_thread_exit (delete_thread_object);
+  observer_attach_normal_stop (python_on_normal_stop);
+  observer_attach_target_resumed (python_on_resume);
+  observer_attach_inferior_exit (python_inferior_exit);
 
   if (PyType_Ready (&membuf_object_type) < 0)
     return;
diff --git a/gdb/python/py-signalevent.c b/gdb/python/py-signalevent.c
new file mode 100644
index 0000000..3bf2fa9
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,64 @@
+/* Python interface to inferior signal stop events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "py-stopevent.h"
+
+static PyTypeObject signal_event_object_type;
+
+static void
+signal_evpy_dealloc (PyObject *self)
+{
+  Py_XDECREF (((signal_event_object *) self)->stop_signal);
+  stop_evpy_dealloc (self);
+}
+
+signal_event_object *
+create_signal_event_object (enum target_signal stop_signal,
+                            PyObject *stopped_thread)
+{
+  char *signal_name;
+  signal_event_object *signal_event_obj =
+      (signal_event_object *)
+      create_stop_event_object (&signal_event_object_type,
+                                stopped_thread);
+
+  if (!signal_event_obj)
+    goto fail;
+
+  signal_name = (char *) target_signal_to_name (stop_signal);
+  signal_event_obj->stop_signal = PyString_FromString (signal_name);
+
+  if (evpy_add_attribute ((event_object *) signal_event_obj,
+                          "stop_signal",
+                          signal_event_obj->stop_signal) < 0)
+    goto fail;
+
+  return signal_event_obj;
+
+  fail:
+   Py_XDECREF (signal_event_obj);
+   return NULL;
+}
+
+GDBPY_NEW_EVENT_TYPE (signal,
+                      "gdb.SignalEvent",
+                      "SignalEvent",
+                      "GDB signal event object",
+                      stop_event_object_type,
+                      static);
diff --git a/gdb/python/py-stopevent.c b/gdb/python/py-stopevent.c
new file mode 100644
index 0000000..d5a1ec9
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,161 @@
+/* Python interface to inferior stop events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "py-stopevent.h"
+
+void
+stop_evpy_dealloc (PyObject *self)
+{
+  Py_XDECREF (((stop_event_object *) self)->inferior_thread);
+  evpy_dealloc (self);
+}
+
+stop_event_object *
+create_stop_event_object (PyTypeObject *py_type, PyObject *thread)
+{
+  stop_event_object *stop_event_obj =
+      (stop_event_object *) create_event_object (py_type);
+
+  if (!stop_event_obj)
+    goto fail;
+
+  stop_event_obj->inferior_thread = thread;
+
+  if (evpy_add_attribute ((event_object *) stop_event_obj,
+                          "inferior_thread",
+                          stop_event_obj->inferior_thread) < 0)
+    goto fail;
+
+  return stop_event_obj;
+
+  fail:
+   Py_XDECREF (stop_event_obj);
+   return NULL;
+
+}
+
+/* Stop events can either be thread specific or process wide.  If gdb is
+   running in non-stop mode then the event is thread specific, otherwise
+   it is process wide.
+   This function returns the currently stopped thread in non-stop mode and
+   Py_None otherwise.  */
+
+PyObject *
+get_stopped_thread ()
+{
+  PyObject *stopped_thread = NULL;
+
+  if (non_stop)
+    stopped_thread = (PyObject *) find_thread_object (inferior_ptid);
+  else
+    stopped_thread = Py_None;
+
+  if (!stopped_thread)
+    return NULL;
+
+  Py_INCREF (stopped_thread);
+
+  return stopped_thread;
+}
+
+/* Callback observers when a stop event occurs.  This function will create a new
+   Python stop event object.  If only a specific thread is stopped the thread
+   object of the event will be set to that thread.  Otherwise, if all threads
+   are stopped thread object will be set to None.
+   return 0 if the event was created and emitted successfully otherwise
+   returns -1.  */
+
+int
+emit_stop_event (struct bpstats *bs, enum target_signal stop_signal)
+{
+  stop_event_object *stop_event_obj = NULL; /* Appease GCC warning.  */
+  eventregistry_object *registry = NULL;
+  PyObject* stopped_thread = NULL;
+
+  if (bs && bs->breakpoint_at
+      && bs->breakpoint_at->type == bp_breakpoint)
+    {
+      if (evregpy_no_listeners_p (gdb_py_events.breakpoint))
+	return 0;
+
+      stopped_thread = get_stopped_thread();
+      if (!stopped_thread)
+	goto fail;
+
+      stop_event_obj =
+	  (stop_event_object *)
+	  create_breakpoint_event_object (bs, stopped_thread);
+      if (!stop_event_obj)
+	goto fail;
+
+      registry = gdb_py_events.breakpoint;
+    }
+
+  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
+  if (stop_signal != TARGET_SIGNAL_0
+      && stop_signal != TARGET_SIGNAL_TRAP)
+    {
+      if (evregpy_no_listeners_p (gdb_py_events.signal))
+	return 0;
+
+      stopped_thread = get_stopped_thread();
+      if (!stopped_thread)
+	goto fail;
+
+      stop_event_obj =
+	  (stop_event_object *)
+	  create_signal_event_object (stop_signal, stopped_thread);
+      if (!stop_event_obj)
+	goto fail;
+
+      registry = gdb_py_events.signal;
+    }
+
+  /* If all fails emit an unknown stop event.  All event types should
+     be known and this should eventually be unused.  */
+  if (!stop_event_obj)
+    {
+      if (evregpy_no_listeners_p (gdb_py_events.stop))
+	return 0;
+
+      stopped_thread = get_stopped_thread();
+      if (!stopped_thread)
+	goto fail;
+
+      stop_event_obj = create_stop_event_object (&stop_event_object_type,
+                                                 stopped_thread);
+      if (!stop_event_obj)
+	goto fail;
+
+      registry = gdb_py_events.stop;
+    }
+
+  return evpy_emit_event ((event_object *) stop_event_obj, registry);
+
+  fail:
+   Py_XDECREF(stopped_thread);
+   return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (stop,
+                      "gdb.StopEvent",
+                      "StopEvent",
+                      "GDB stop event object",
+                      event_object_type,
+                      /*no qual*/);
diff --git a/gdb/python/py-stopevent.h b/gdb/python/py-stopevent.h
new file mode 100644
index 0000000..bf0b526
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,58 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_PY_STOPEVENT_H
+#define GDB_PY_STOPEVENT_H
+
+#include "py-event.h"
+
+typedef struct
+{
+  event_object event;
+  PyObject *inferior_thread;
+} stop_event_object;
+
+typedef struct
+{
+  stop_event_object stop_event;
+  PyObject *breakpoint;
+} breakpoint_event_object;
+
+typedef struct
+{
+  stop_event_object stop_event;
+  PyObject *stop_signal;
+} signal_event_object;
+
+extern stop_event_object * create_stop_event_object (PyTypeObject *py_type,
+                                                     PyObject *thread);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+                            enum target_signal stop_signal);
+
+extern breakpoint_event_object *
+create_breakpoint_event_object (struct bpstats *bs,
+                                PyObject *stopped_thread);
+
+extern signal_event_object *
+create_signal_event_object (enum target_signal stop_signal,
+                            PyObject *stopped_thread);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..4e141d1 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -79,6 +79,7 @@ typedef int Py_ssize_t;
 
 /* Also needed to parse enum var_types. */
 #include "command.h"
+#include "breakpoint.h"
 
 #include "exceptions.h"
 
@@ -86,11 +87,18 @@ struct block;
 struct value;
 struct language_defn;
 struct program_space;
+struct bpstats;
 
 extern PyObject *gdb_module;
 extern PyTypeObject value_object_type;
 extern PyTypeObject block_object_type;
 extern PyTypeObject symbol_object_type;
+extern PyTypeObject event_object_type;
+extern PyTypeObject events_object_type;
+extern PyTypeObject stop_event_object_type;
+
+/* Defined in py-breakpoint.c */
+typedef struct breakpoint_object breakpoint_object;
 
 typedef struct
 {
@@ -141,6 +149,8 @@ PyObject *objfpy_get_printers (PyObject *, void *);
 thread_object *create_thread_object (struct thread_info *tp);
 thread_object *find_thread_object (ptid_t ptid);
 PyObject *find_inferior_object (int pid);
+PyObject *inferior_to_inferior_object (struct inferior *inferior);
+PyObject *gdbpy_breakpoint_from_bpstats (struct bpstats *bs);
 
 struct block *block_object_to_block (PyObject *obj);
 struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -167,6 +177,14 @@ void gdbpy_initialize_lazy_string (void);
 void gdbpy_initialize_parameters (void);
 void gdbpy_initialize_thread (void);
 void gdbpy_initialize_inferior (void);
+void gdbpy_initialize_eventregistry (void);
+void gdbpy_initialize_event (void);
+void gdbpy_initialize_py_events (void);
+void gdbpy_initialize_stop_event (void);
+void gdbpy_initialize_signal_event (void);
+void gdbpy_initialize_breakpoint_event (void);
+void gdbpy_initialize_continue_event (void);
+void gdbpy_initialize_exited_event (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 
diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..04c072a 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1001,6 +1001,15 @@ Enables or disables printing of Python stack traces."),
   gdbpy_initialize_inferior ();
   gdbpy_initialize_events ();
 
+  gdbpy_initialize_eventregistry ();
+  gdbpy_initialize_py_events ();
+  gdbpy_initialize_event ();
+  gdbpy_initialize_stop_event ();
+  gdbpy_initialize_signal_event ();
+  gdbpy_initialize_breakpoint_event ();
+  gdbpy_initialize_continue_event ();
+  gdbpy_initialize_exited_event ();
+
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = []");
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0417538..2e9f64b 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2010-12-23  Sami Wagiaalla  <swagiaal@redhat.com>
+
+	* gdb.python/py-events-threads.c: New file.
+	* gdb.python/py-events-threads.exp: New file.
+	* gdb.python/py-events.py: New file.
+	* gdb.python/py-events.exp: New file.
+	* gdb.python/py-events.c: New file.
+
 2010-12-12  Stan Shebs  <stan@codesourcery.com>
 
 	* gdb.trace/tsv.exp: Test print command on trace state variables.
diff --git a/gdb/testsuite/gdb.python/py-events.c b/gdb/testsuite/gdb.python/py-events.c
new file mode 100644
index 0000000..ceb697e
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2010, 2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see  <http://www.gnu.org/licenses/>.
+*/
+
+int second(){
+  return 12;
+}
+
+int first(){
+  return second();
+}
+
+int main (){
+  return first();
+}
diff --git a/gdb/testsuite/gdb.python/py-events.exp b/gdb/testsuite/gdb.python/py-events.exp
new file mode 100644
index 0000000..e5d6daf
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -0,0 +1,59 @@
+# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests Python-based
+# pretty-printing for the CLI.
+
+# Skip all tests if Python scripting is not enabled.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-events"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set pyfile ${srcdir}/${subdir}/${testfile}.py
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    return -1
+}
+
+if { [skip_python_tests] } { continue }
+
+gdb_test_no_output "python execfile ('${pyfile}')" ""
+
+if ![runto_main ] then {
+    fail "Can't run to main"
+    return -1
+}
+
+gdb_test "Test_Events" "Event testers registered."
+
+gdb_breakpoint "first"
+
+# Test continue event and breakpoint stop event
+gdb_test "continue" ".*event type: continue.*
+.*event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 2.*
+all threads stopped"
+
+#test exited event.
+gdb_test "continue" ".*event type: continue.*
+.*event type: exit.*
+.*exit code: 12.*"
diff --git a/gdb/testsuite/gdb.python/py-events.py b/gdb/testsuite/gdb.python/py-events.py
new file mode 100644
index 0000000..57d8842
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests python pretty
+# printers.
+import gdb
+
+def signal_stop_handler (event):
+    if (isinstance (event, gdb.StopEvent)):
+        print "event type: stop"
+    if (isinstance (event, gdb.SignalEvent)):
+        print "stop reason: signal"
+        print "stop signal: %s" % (event.stop_signal)
+        if ( event.inferior_thread is not None) :
+            print "thread num: %s" % (event.inferior_thread.num);
+
+def breakpoint_stop_handler (event):
+    if (isinstance (event, gdb.StopEvent)):
+        print "event type: stop"
+    if (isinstance (event, gdb.BreakpointEvent)):
+        print "stop reason: breakpoint"
+        print "breakpoint number: %s" % (event.breakpoint.number)
+        if ( event.inferior_thread is not None) :
+            print "thread num: %s" % (event.inferior_thread.num);
+        else:
+            print "all threads stopped"
+
+def exit_handler (event):
+    if (isinstance (event, gdb.ExitedEvent)):
+        print "event type: exit"
+    print "exit code: %d" % (event.exit_code)
+
+def continue_handler (event):
+    if (isinstance (event, gdb.ContinueEvent)):
+        print "event type: continue"
+
+class test_events (gdb.Command):
+    """Test events."""
+
+    def __init__ (self):
+        gdb.Command.__init__ (self, "test_events", gdb.COMMAND_STACK)
+
+    def invoke (self, arg, from_tty):
+        gdb.events.signal.connect (signal_stop_handler)
+        gdb.events.breakpoint.connect (breakpoint_stop_handler)
+        gdb.events.exited.connect (exit_handler)
+        gdb.events.cont.connect (continue_handler)
+        print "Event testers registered."
+
+test_events ()
diff --git a/gdb/testsuite/gdb.python/py-evthreads.c b/gdb/testsuite/gdb.python/py-evthreads.c
new file mode 100644
index 0000000..28124fa
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -0,0 +1,54 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2010, 2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see  <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+
+pthread_t thread2_id;
+pthread_t thread3_id;
+
+void* thread3 (void* d)
+{
+  int count3 = 0;
+  count3++;
+
+  int *bad;
+  *bad = 1;
+
+  return NULL;
+}
+
+void* thread2 (void* d)
+{
+  int count2 = 0;
+  count2++;
+  return NULL;
+}
+
+int main (){
+
+  pthread_create (&thread2_id, NULL, thread2, NULL);
+  pthread_create (&thread3_id, NULL, thread3, NULL);
+
+  int count1 = 0; // stop1
+  count1++;
+
+  pthread_join (thread3_id, NULL);
+  return 12;
+}
diff --git a/gdb/testsuite/gdb.python/py-evthreads.exp b/gdb/testsuite/gdb.python/py-evthreads.exp
new file mode 100644
index 0000000..eb1ecc0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -0,0 +1,89 @@
+# Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests Python-based
+# pretty-printing for the CLI.
+
+# Skip all tests if Python scripting is not enabled.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-evthreads"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set pyfile ${srcdir}/${subdir}/py-events.py
+
+gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}
+clean_restart $testfile
+
+if { [skip_python_tests] } { continue }
+
+gdb_test_no_output "python execfile ('${pyfile}')" ""
+
+gdb_test "Test_Events" "Event testers registered."
+gdb_test_no_output "set non-stop on"
+gdb_test_no_output "set target-async on"
+
+gdb_breakpoint "main"
+gdb_breakpoint "thread2"
+gdb_breakpoint "thread3"
+
+send_gdb "run\n"
+gdb_expect {
+    -re "event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 1.*
+.*thread num: 1.*" {
+        pass "reached breakpoint 1"
+    }
+    timeout {
+	    fail "did not reach breakpoint 1"
+	}
+}
+
+send_gdb "next\n"
+gdb_expect {
+    -re "event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 2.*
+.*thread num: 2.*" {
+        pass "reached breakpoint 2"
+    }
+    timeout {
+	    fail "did not reach breakpoint 2"
+	}
+}
+
+send_gdb "next\n"
+gdb_expect {
+    -re "event type: stop.*
+.*stop reason: breakpoint.*
+.*breakpoint number: 3.*
+.*thread num: 3.*" {
+        pass "reached breakpoint 3"
+    }
+    timeout {
+	    fail "did not reach breakpoint 3"
+	}
+}
+
+gdb_test "continue -a" ".*event type: stop.*
+.*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*"

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]