public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [patch] Support inferior events in python
@ 2011-01-04 15:54 sami wagiaalla
  2011-01-04 18:22 ` Eli Zaretskii
  2011-01-04 20:09 ` Tom Tromey
  0 siblings, 2 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-01-04 15:54 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 607 bytes --]

This patch is base on the work done by Oguz Kayral in the summer of 
2009. Tom Tromey and Phil Muldoon also provided a lot of help and 
guidance on this.

It adds to the python API the module 'gdb.events'. The events module 
contains references to event registries that one can add observers to. 
Namely,
    events.breakpoint
    events.signal
    events.cont
    events.exited

I have also taken the example that Oguz provided and turned that into a 
test case.

This has been tested on Fedora 13 X8664 with gcc 4.4.4-f13

A documentation patch will follow soon.

Thanks in advance for the review.

Sami


[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 59618 bytes --]

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..c291ee2 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -273,7 +273,13 @@ SUBDIR_PYTHON_OBS = \
 	py-auto-load.o \
 	py-block.o \
 	py-breakpoint.o \
+	py-breakpointevent.o \
 	py-cmd.o \
+	py-continueevent.o \
+	py-event.o \
+	py-eventregistry.o \
+	py-events.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-breakpoint.c \
+	python/py-breakpointevent.c \
 	python/py-cmd.c \
+	python/py-continueevent.c \
+	python/py-event.c \
+	python/py-eventregistry.c \
+	python/py-events.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 \
@@ -1996,10 +2013,34 @@ py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
 	$(POSTCOMPILE)
 
+py-breakpointevent.o: $(srcdir)/python/py-breakpointevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpointevent.c
+	$(POSTCOMPILE)
+
 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-eventregistry.o: $(srcdir)/python/py-eventregistry.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-eventregistry.c
+	$(POSTCOMPILE)
+
+py-events.o: $(srcdir)/python/py-events.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-events.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/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 88d9930..f85a99b 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.  */
+
+breakpoint_object *
+gdbpy_breakpoint_from_bpstats (struct bpstats *bs)
+{
+  return (breakpoint_object *) 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-breakpointevent.c b/gdb/python/py-breakpointevent.c
new file mode 100644
index 0000000..5e68ec0
--- /dev/null
+++ b/gdb/python/py-breakpointevent.c
@@ -0,0 +1,65 @@
+/* Python interface to inferior breakpoint stop events.
+
+   Copyright (C) 2009, 2010 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_DECREF (((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, thread_object *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",
+                          (PyObject *) breakpoint_event_obj->breakpoint) < 0)
+    goto fail;
+
+  return breakpoint_event_obj;
+
+ fail:
+  Py_XDECREF (breakpoint_event_obj);
+  Py_XDECREF (breakpoint_event_obj->breakpoint);
+  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-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..9c702b6
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,65 @@
+/* Python interface to inferior continue events.
+
+   Copyright (C) 2009, 2010 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 ()
+{
+  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_get_nlisteners (gdb_py_events.cont) == 0)
+    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..cd9af34
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,179 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010 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);
+  Py_XDECREF (event_obj->dict);
+  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 = copy_py_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..e46f1fe
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,119 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010 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, const char *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-eventregistry.c b/gdb/python/py-eventregistry.c
new file mode 100644
index 0000000..9cdc19b
--- /dev/null
+++ b/gdb/python/py-eventregistry.c
@@ -0,0 +1,169 @@
+/* Python interface to inferior thread event registries.
+
+   Copyright (C) 2009, 2010 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 to the list of listeners.  */
+
+static PyObject *
+evregpy_disconnect (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;
+    }
+
+  PySequence_DelItem (callback_list, PySequence_Index (callback_list, func));
+
+  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);
+
+  return eventregistry_obj;
+}
+
+static void
+evregpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((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_get_nlisteners (eventregistry_object *registry)
+{
+  return PyList_Size ((PyObject *) registry->callbacks);
+}
+
+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-events.c b/gdb/python/py-events.c
new file mode 100644
index 0000000..5881851
--- /dev/null
+++ b/gdb/python/py-events.c
@@ -0,0 +1,76 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010 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-events.h b/gdb/python/py-events.h
new file mode 100644
index 0000000..57e3f07
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,60 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010 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_get_nlisteners (eventregistry_object *registry);
+
+#endif /* GDB_PY_EVENTS_H */
diff --git a/gdb/python/py-exitedevent.c b/gdb/python/py-exitedevent.c
new file mode 100644
index 0000000..6d1dcb6
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,88 @@
+/* Python interface to inferior exit events.
+
+   Copyright (C) 2009, 2010 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;
+  PyLongObject *exit_code;
+} exited_event_object;
+
+static void
+exited_evpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((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 = (PyLongObject *) PyLong_FromLongLong (* exit_code);
+  if (evpy_add_attribute ((event_object *) exited_event,
+                          "exit_code",
+                          (PyObject *)exited_event->exit_code) < 0)
+    goto fail;
+
+  return exited_event;
+
+  fail:
+   Py_XDECREF (exited_event);
+   Py_XDECREF (exited_event->exit_code);
+   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_get_nlisteners (gdb_py_events.exited) == 0)
+    return 0;
+
+  event = (event_object *) create_exited_event_object (exit_code);
+
+  if (event)
+    return evpy_emit_event ((event_object *)
+                            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..681bcd1 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;
+  char *stop_signal;
+
+  if (!find_thread_ptid (inferior_ptid))
+      return;
+
+  stop_signal = (char *) target_signal_to_name (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;
+
+  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..af5566f
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,64 @@
+/* Python interface to inferior signal stop events.
+
+   Copyright (C) 2009, 2010 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_DECREF (((signal_event_object *) self)->stop_signal);
+  stop_evpy_dealloc (self);
+}
+
+signal_event_object *
+create_signal_event_object (const char *stop_signal,
+                            thread_object *stopped_thread)
+{
+  signal_event_object *signal_event_obj =
+      (signal_event_object *)
+      create_stop_event_object (&signal_event_object_type,
+                                (thread_object *) stopped_thread);
+
+  if (!signal_event_obj)
+    goto fail;
+
+  signal_event_obj->stop_signal =
+      (PyStringObject *) PyString_FromString (stop_signal);
+
+  if (evpy_add_attribute ((event_object *) signal_event_obj,
+                          "stop_signal",
+                          (PyObject *) signal_event_obj->stop_signal) < 0)
+    goto fail;
+
+  return signal_event_obj;
+
+  fail:
+   Py_XDECREF (signal_event_obj);
+   Py_XDECREF (signal_event_obj->stop_signal);
+   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..7d4971e
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,135 @@
+/* Python interface to inferior stop events.
+
+   Copyright (C) 2009, 2010 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, thread_object *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 = (PyObject *) 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);
+   Py_XDECREF (stop_event_obj->inferior_thread);
+   return NULL;
+
+}
+
+/* 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, const char *stop_signal)
+{
+  thread_object *stopped_thread;
+  stop_event_object *stop_event_obj = NULL; /* Appease GCC warning.  */
+  eventregistry_object *registry = 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.  */
+  if (non_stop)
+    stopped_thread = find_thread_object (inferior_ptid);
+  else
+    stopped_thread = (thread_object *) Py_None;
+
+  if (bs && bs->breakpoint_at
+      && bs->breakpoint_at->type == bp_breakpoint)
+    {
+      if (evregpy_get_nlisteners (gdb_py_events.breakpoint) == 0)
+	return 0;
+
+      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 ((strcmp (stop_signal, "0") != 0)
+      && (strcmp (stop_signal, "SIGTRAP") != 0))
+    {
+      if (evregpy_get_nlisteners (gdb_py_events.signal) == 0)
+	return 0;
+
+      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_get_nlisteners (gdb_py_events.stop) == 0)
+	return 0;
+
+      stop_event_obj = create_stop_event_object (&stop_event_object_type,
+                                                 (thread_object *) stopped_thread);
+      if (!stop_event_obj)
+	goto fail;
+
+      registry = gdb_py_events.stop;
+    }
+
+  return evpy_emit_event ((event_object *) stop_event_obj,
+                          registry);
+
+  fail:
+   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..2d73d36
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,58 @@
+/* Python interface to inferior events.
+
+   Copyright (C) 2009, 2010 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
+{
+  PyObject *inferior_thread;
+  event_object event;
+} stop_event_object;
+
+typedef struct
+{
+  stop_event_object stop_event;
+  breakpoint_object *breakpoint;
+} breakpoint_event_object;
+
+typedef struct
+{
+  stop_event_object stop_event;
+  PyStringObject *stop_signal;
+} signal_event_object;
+
+extern stop_event_object * create_stop_event_object (PyTypeObject *py_type,
+                                                     thread_object *thread);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+                            const char *stop_signal);
+
+extern breakpoint_event_object *
+create_breakpoint_event_object (struct bpstats *bs,
+                                thread_object *stopped_thread);
+
+extern signal_event_object *
+create_signal_event_object (const char *stop_signal,
+                            thread_object *stopped_thread);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..a9f9f1f 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);
+breakpoint_object *gdbpy_breakpoint_from_bpstats (struct bpstats *bs);
 
 struct block *block_object_to_block (PyObject *obj);
 struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -167,12 +177,22 @@ 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);
 
 struct cleanup *ensure_python_env (struct gdbarch *gdbarch,
 				   const struct language_defn *language);
 
+PyObject *copy_py_list (PyObject *list);
+
 extern struct gdbarch *python_gdbarch;
 extern const struct language_defn *python_language;
 
diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..da226ad 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -162,6 +162,28 @@ compute_python_string (struct command_line *l)
   return script;
 }
 
+/* Returns a a copy of the give LIST.
+   Creates a new reference which must be handled by the caller.  */
+
+PyObject *
+copy_py_list (PyObject *list)
+{
+  int i;
+
+  PyObject *new_list = PyList_New (0);
+  if (!new_list)
+    return NULL;
+
+  for (i = 0; i < PyList_Size (list); i++)
+    if (PyList_Append (new_list, PyList_GET_ITEM (list, i)) < 0)
+      {
+	Py_DECREF (new_list);
+	return NULL;
+      }
+
+  return new_list;
+}
+
 /* Take a command line structure representing a 'python' command, and
    evaluate its body using the Python interpreter.  */
 
@@ -1001,6 +1023,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-threads.c b/gdb/testsuite/gdb.python/py-events-threads.c
new file mode 100644
index 0000000..63e27f9
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events-threads.c
@@ -0,0 +1,54 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2010 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-events-threads.exp b/gdb/testsuite/gdb.python/py-events-threads.exp
new file mode 100644
index 0000000..ed50d61
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events-threads.exp
@@ -0,0 +1,89 @@
+# Copyright (C) 2010 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-threads"
+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.*"
diff --git a/gdb/testsuite/gdb.python/py-events.c b/gdb/testsuite/gdb.python/py-events.c
new file mode 100644
index 0000000..1a5f2de
--- /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 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..52feb31
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -0,0 +1,59 @@
+# Copyright (C) 2010 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..a12732a
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2010 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 ()


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-01-04 15:54 [patch] Support inferior events in python sami wagiaalla
@ 2011-01-04 18:22 ` Eli Zaretskii
  2011-01-04 20:09 ` Tom Tromey
  1 sibling, 0 replies; 42+ messages in thread
From: Eli Zaretskii @ 2011-01-04 18:22 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

> Date: Tue, 04 Jan 2011 10:54:10 -0500
> From: sami wagiaalla <swagiaal@redhat.com>
> 
> This patch is base on the work done by Oguz Kayral in the summer of 
> 2009. Tom Tromey and Phil Muldoon also provided a lot of help and 
> guidance on this.
> 
> It adds to the python API the module 'gdb.events'. The events module 
> contains references to event registries that one can add observers to. 
> Namely,
>     events.breakpoint
>     events.signal
>     events.cont
>     events.exited

Thanks.

> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -273,7 +273,13 @@ SUBDIR_PYTHON_OBS = \
>  	py-auto-load.o \
>  	py-block.o \
>  	py-breakpoint.o \
> +	py-breakpointevent.o \
>  	py-cmd.o \
> +	py-continueevent.o \
> +	py-event.o \
> +	py-eventregistry.o \
> +	py-events.o \
> +	py-exitedevent.o \

Can we perhaps avoid file-name clashes on DOS 8+3 filesystems, by
naming the new files slightly differently?  For example:

  py-breakpointevent.c => py-bpevent.c
  py-eventregistry.c => py-evtregistry.c
  py-events.c => py-evts.c

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-01-04 15:54 [patch] Support inferior events in python sami wagiaalla
  2011-01-04 18:22 ` Eli Zaretskii
@ 2011-01-04 20:09 ` Tom Tromey
  2011-01-17 22:59   ` sami wagiaalla
  1 sibling, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-01-04 20:09 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> This patch is base on the work done by Oguz Kayral in the summer of
Sami> 2009. Tom Tromey and Phil Muldoon also provided a lot of help and
Sami> guidance on this.

Thanks for doing this.  This is a very important feature.

Sami> A documentation patch will follow soon.

I think it is better for a patch to include documentation and, when
applicable (it is for this patch), a NEWS entry.

Sami> Thanks in advance for the review.

One thing I noticed is that now all the copyright headers should be
updated to include 2011 :-)

Sami> +breakpoint_event_object *
Sami> +create_breakpoint_event_object (struct bpstats *bs, thread_object *stopped_thread)

Wrap this line at the ",".

Sami> +continue_event_object *
Sami> +create_continue_event_object ()

Change to (void).

Sami> +/* Callback function which notifies observers when a continue event occurs.
Sami> +   This function will create a new Python continue event object.
Sami> +   Return -1 if emit fails.  */
Sami> +
Sami> +int
Sami> +emit_continue_event (ptid_t ptid)
Sami> +{
Sami> +  event_object *event;
Sami> +  if (evregpy_get_nlisteners (gdb_py_events.cont) == 0)

Newline between the above 2 lines.

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.

Sami> +    return evpy_emit_event (event,
Sami> +                            gdb_py_events.cont);

I don't think this line needs to be split.

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.

Sami> +/* Implementation of EventRegistry.disconnect () -> NULL.
Sami> +   Remove FUNCTION to the list of listeners.  */

s/to/from/

Sami> +  PySequence_DelItem (callback_list, PySequence_Index (callback_list, func));

I think you have to separate the calls here and then check
the PySequence_Index result.

Sami> +  eventregistry_obj->callbacks = (PyListObject *) PyList_New (0);

This needs a failure check.

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.

Sami> +void
Sami> +gdbpy_initialize_py_events ()
Sami> +{
Sami> +

No blank line here.

Sami> +  Py_INCREF (gdb_py_events.module);
Sami> +  if(PyModule_AddObject (gdb_module,

Space before open paren.

Sami> +  PyLongObject *exit_code;

I think you could remove a lot of casts if this were just a PyObject*.

Sami> +emit_exited_event (LONGEST *exit_code)
Sami> +{
Sami> +  event_object *event;
Sami> +  if (evregpy_get_nlisteners (gdb_py_events.exited) == 0)

Blank line after declarations.

Sami> +  if (event)
Sami> +    return evpy_emit_event ((event_object *)
Sami> +                            event,

I think this cast isn't needed.

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.

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.

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.)

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.

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.

Sami> +  if (non_stop)
Sami> +    stopped_thread = find_thread_object (inferior_ptid);
Sami> +  else
Sami> +    stopped_thread = (thread_object *) Py_None;

This cast is not ok.
Also this code must incref even in this case, since it is decrefed when
the event is destroyed.

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.

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?

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.

Sami> +/* Returns a a copy of the give LIST.
Sami> +   Creates a new reference which must be handled by the caller.  */
Sami> +
Sami> +PyObject *
Sami> +copy_py_list (PyObject *list)

I don't think we need this function.
Just use PySequence_List.

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-01-04 20:09 ` Tom Tromey
@ 2011-01-17 22:59   ` sami wagiaalla
  2011-01-19 16:42     ` Tom Tromey
  0 siblings, 1 reply; 42+ messages in thread
From: sami wagiaalla @ 2011-01-17 22:59 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 6050 bytes --]

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.



[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 64018 bytes --]

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.*"

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-01-17 22:59   ` sami wagiaalla
@ 2011-01-19 16:42     ` Tom Tromey
  2011-01-21 23:06       ` sami wagiaalla
  0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-01-19 16:42 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

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

Thank you very much

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

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

Perfect.

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

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

I looked at this in the new patch, and I see what you mean.
I agree with your approach.

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

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

I don't want to hold up this patch for a detail like this, but I wonder
if we could put the exit code into the struct inferior as well as in the
convenience variable.

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

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

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

Yeah, ordinarily that would be better, but Python pretty much assumes
PyObject* everywhere.

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

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

It seems to me that the callers of the create_* functions then proceed
to downcast anyway:

Sami> +  event = (event_object *) create_continue_event_object ();
Sami> +  if (event)
Sami> +    return evpy_emit_event (event, gdb_py_events.cont);
Sami> +  return -1;

Given this, I think just returning the more generic type is ok.


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

I think it is ok to use strings.

Sami> +* Python Support for Inferior events.
Sami> +  Python scripts can add observers to be notified of events
Sami> +  occurring the in process being debugged.
Sami> +  The following events are currently supported:
Sami> +  - gdb.events.breakpoint Breakpoint hit event.
Sami> +  - gdb.events.cont Continue event.
Sami> +  - gdb.events.signal Signal received event.
Sami> +  - gdb.events.exited Inferior exited event.

There is a "Python scripting" section in NEWS already.  This should be
in that section.

Sami> +* Inferior Events In Python::   Listening for events from the process being debugged.

Line wraps.  I think the node name should not have "Inferior" in it,
since we may well use this facility for events not originating from the
inferior.

Sami> +The Python API allows scripts to listen for events coming from the inferior process
Sami> +and its threads. In order to listen for events the script must register an observer
Sami> +by connecting it to the appropriate event registry. Event registries can be accessed
Sami> +through the @code{gdb.events} module.

All the lines in this paragraph wrap.  This occurs in a few places in
the documentation patch.  Also, we use two spaces after a period.

I think the introduction could be expanded on a bit.
How about something like:

    GDB provides a general event facility so that Python code can be
    notified of various state changes, particularly changes that occur in
    the inferior.

    An @defn{event} is just an object that describes some state change.  The
    type of the object and its attributes will vary depending on the details
    of the change.  All the existing events are described below.

    In order to be notified of an event, you must register an event handler
    with an event registry.  An @defn{event registry} is just an object in
    the @code{gdb.event} module which dispatches particular events.  A
    registry provides methods to register and unregister event handlers.

Sami> +Here is an example:
Sami> +
Sami> +@smallexample
Sami> +def exit_handler (event):
Sami> +    if (isinstance (event, gdb.ExitedEvent)):

We shouldn't use isinstance in an example.  I think that is sort of bad
style, particularly if the `exited' event registry can only ever
dispatch ExitedEvent objects.

Sami> +@table @code
Sami> +@item events.breakpoint
Sami> +@item events.cont
Sami> +@item events.exited
Sami> +@item events.signal
Sami> +@end table

This seems weird.  At least each of these should have a description
indicating what it is good for.

And, before this, there should be a section describing the event
registry class itself.  I didn't see any documentation for the connect
and disconnect methods.

Instead of separate signal and breakpoint registries, why not a general
"stopped" registry that emits different events depending on why the
inferior stopped?

Sami> +These registries emit the following events in respective order:

I think it would be better to use nested tables here.  That is, it
should be pretty easy to read the text and see what a given registry
does and what kind of events it can generate.

Sami> +@defivar SignalEvent stop_signal
Sami> +The signal received by the inferior
Sami> +@end defivar

This should describe the possible values for this attribute.
I think all the attributes should have this sort of documentation.

Sami> +@node gdb.events
Sami> +@subsubsection gdb.events
Sami> +@cindex gdb.events

I understand why you put this here, but I think it isn't the best place
for it.  True, gdb.events is a module -- but I think it would be clearer
for the reader if it were just documented where the discussion of events
takes place.

(This node was really created for modules actually written in Python.
But, that doesn't actually matter to users, either... perhaps this
existing text should be moved, but of course that isn't related to this
patch.)

Sami> +  callback_list = (PyObject *) registry->callbacks;

Right now `callbacks' is a PyListObject*.
If it were a PyObject* then I think all the casts associated with it
would go away.

Sami> +extern int emit_stop_event (struct bpstats *bs, enum target_signal stop_signal);

This line is too long.

Sami> +extern event_object * create_event_object (PyTypeObject *py_type);

Remove space after "*".

Sami> +  PyList_Append (callback_list, func);

Needs an error check.

Sami> +static PyObject *
Sami> +evregpy_disconnect (PyObject *self, PyObject *function)
[...]
Sami> +  if (!PyCallable_Check (func))
Sami> +    {
Sami> +      PyErr_SetString (PyExc_RuntimeError, "Function is not callable");
Sami> +      return NULL;

I don't think we need to bother with this check here.

Sami> +  if (index < 0)
Sami> +    {
Sami> +      PyErr_SetString (PyExc_RuntimeError, "Function not found");
Sami> +      return NULL;

And I think it is ok to just ignore this case.
It seems ok to me to have an attempted removal of an item simply do
nothing if the item isn't on the list.

Sami> +  if (get_internalvar_integer (lookup_internalvar ("_exitcode"), &exitcode_val))

This line is too long.

Sami> +  signal_name = (char *) target_signal_to_name (stop_signal);
Sami> +  signal_event_obj->stop_signal = PyString_FromString (signal_name);

I think you can make signal_name a const char * and avoid the cast here.
Or did we have some problem with this elsewhere?  I can't remember.

Sami> +PyObject *
Sami> +get_stopped_thread ()

`(void)'

Sami> +extern stop_event_object * create_stop_event_object (PyTypeObject *py_type,

Remove space after "*".

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-01-19 16:42     ` Tom Tromey
@ 2011-01-21 23:06       ` sami wagiaalla
  2011-01-28 16:21         ` Tom Tromey
  0 siblings, 1 reply; 42+ messages in thread
From: sami wagiaalla @ 2011-01-21 23:06 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1697 bytes --]

Made all the requested changes.

>
> Tom>  However, I think this is pretty ugly.
> Tom>  It seems like there should be a better way to get this than looking up
> Tom>  a convenience variable.
>
> Sami>  Hmm I looked through the code to find another way but could
> Sami>  not. handle_inferior_event which sets the convenience variable uses
> Sami>  execution_control_state which I don't have access to.
>
> I don't want to hold up this patch for a detail like this, but I wonder
> if we could put the exit code into the struct inferior as well as in the
> convenience variable.
>

Okay, I added exit_code to struct inferior, set it and used it. How does 
that part of the patch look ?

> [create_stop_event_object]
> Tom>  I think it would be better to just have one cast at the end, instead of
> Tom>  lots of casts in the body.
>
> Sami>  Hmm if I change stop_event_object* to event_object it would eliminate
> Sami>  two casts but also add two. One when setting the inferior thread and
> Sami>  one for returning. Same goes for all the create_* functions or should
> Sami>  I change all of those to return more generic objects ?
>
> It seems to me that the callers of the create_* functions then proceed
> to downcast anyway:
>
> Sami>  +  event = (event_object *) create_continue_event_object ();
> Sami>  +  if (event)
> Sami>  +    return evpy_emit_event (event, gdb_py_events.cont);
> Sami>  +  return -1;
>
> Given this, I think just returning the more generic type is ok.
>

Doing this turned my attention to the fact that the individual c types 
were not really needed, and that event_object can be used for all 
events. This resulted in some more clean up. How does it all look now ?



[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 62924 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..d24d0d0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,34 @@
+2011-01-21  Sami Wagiaalla  <swagiaal@redhat.com>
+                Oguz Kayral <oguzkayral@gmail.com>
+
+	* infrun.c (handle_inferior_event): Set exit_code.
+	* inferior.h (struct inferior): Added new attribute exit_code.
+	* inferior.c (add_inferior_silent): Initialize exit_code.
+	* 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-evtregistry.c: New file.
+	* python/py-event.c: New file.
+	* python/py-evts.c: New file.
+	* python/py-continueevent.c: New file.
+	* python/py-bpevent.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..d5bae34 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,14 @@
 
   ** gdb.parameter("directories") is now available.
 
+  ** 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.cont Continue event.
+     - gdb.events.exited Inferior exited event.
+     - gdb.events.stop Signal received, and Breakpoint hit events.
+
 * C++ Improvements:
 
   ** GDB now puts template parameters in scope when debugging in an
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dc9630a..b899370 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)
+* Events In Python::            Listening for events from GDB.
 * 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,110 @@ the pattern could not be found.
 @end defmethod
 @end table
 
+@node Events In Python
+@subsubsection Events In Python
+@cindex inferior events in python
+
+GDB provides a general event facility so that Python code can be
+notified of various state changes, particularly changes that occur in
+the inferior.
+
+An @dfn{event} is just an object that describes some state change.  The
+type of the object and its attributes will vary depending on the details
+of the change.  All the existing events are described below.
+
+In order to be notified of an event, you must register an event handler
+with an event registry.  An @dfn{event registry} is an object in the
+@code{gdb.events} module which dispatches particular events.  A registry
+provides methods to register and unregister event handlers:
+
+@table @code
+@defmethod EventRegistry connect callable
+Add the given callable object to the registry.  This object will be called
+when an event corresponding to this registry occurs.
+@end defmethod
+
+@defmethod EventRegistry disconnect callable
+Remove the given object from the registry.  Once removed the object will no
+longer receive notifications of events.
+@end defmethod
+@end table
+
+Here is an example:
+
+@smallexample
+def exit_handler (event):
+    print "event type: exit"
+    print "exit code: %d" % (event.exit_code)
+
+gdb.events.exited.connect (exit_handler)
+@end smallexample
+
+In the above example we connect our handler @code{exit_handler} to the
+registry @code{events.exited}.  Once connected @code{exit_handler} receives
+notifications of exited events.  The argument @dfn{event} in this example is
+of type @code{gdb.ExitedEvent}.  As you can see in the example the
+@code{ExitedEvent} object has an attribute which indicates the exit code of
+the inferior.
+
+The following is a listing of the event registries that are available and
+details of the events they emit:
+
+@table @code
+
+@item events.cont
+Emits @code{gdb.ContinueEvent}
+Indicates that the inferior has been continued.
+
+@item events.exited
+Emits @code{events.ExitedEvent} which indicates that the inferior has exited.
+@code{events.ExitedEvent} as one attribute:
+@table @code
+@defivar ExitedEvent exit_code
+An integer representing the exit code which the inferior has returned.
+@end defivar
+@end table
+
+@item events.stop
+Emits @code{gdb.SignalEvent} which indicates that the inferior or one of its
+threads has received as signal.  @code{gdb.SignalEvent} has the following
+attributes:
+
+@table @code
+@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
+A string representing the signal received by the inferior.  A list of possible
+signal values can be obtained by running the command @code{info signals} in
+the @value{GDBN} command prompt.
+@end defivar
+
+Also emits  @code{gdb.BreakpointEvent} which indicates that a breakpoint has
+been hit.  A @code{BreakpointEvent} object as the following attributes:
+
+@table @code
+@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
+@end table
+
+@end table
+
+@end table
+
 @node Threads In Python
 @subsubsection Threads In Python
 @cindex threads in python
diff --git a/gdb/inferior.c b/gdb/inferior.c
index cad7e55..3137128 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -133,6 +133,8 @@ add_inferior_silent (int pid)
   inf->environment = make_environ ();
   init_environ (inf->environment);
 
+  inf->exit_code = -1;
+
   inferior_alloc_data (inf);
 
   observer_notify_inferior_added (inf);
diff --git a/gdb/inferior.h b/gdb/inferior.h
index f80ecb5..62f4ea1 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -522,6 +522,10 @@ struct inferior
      if any catching is necessary.  */
   int total_syscalls_count;
 
+  /* If this inferior object represents an inferior that has just exited
+     this value will contain the exit code, otherwise this will be -1.  */
+  LONGEST exit_code;
+
   /* Per inferior data-pointers required by other GDB modules.  */
   void **data;
   unsigned num_data;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 1bc00a4..96c7d18 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3202,6 +3202,7 @@ handle_inferior_event (struct execution_control_state *ecs)
       target_terminal_ours ();	/* Must do this before mourn anyway */
       print_exited_reason (ecs->ws.value.integer);
 
+      current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
       /* Record the exit code in the convenience variable $_exitcode, so
          that the user can inspect this again later.  */
       set_internalvar_integer (lookup_internalvar ("_exitcode"),
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644
index 0000000..daeb1f0
--- /dev/null
+++ b/gdb/python/py-bpevent.c
@@ -0,0 +1,54 @@
+/* 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;
+
+/* Create and initialize a BreakpointEvent object.  */
+
+PyObject *
+create_breakpoint_event_object (struct bpstats *bs,
+                                PyObject *stopped_thread)
+{
+  PyObject *breakpoint_event_obj =
+      create_stop_event_object (&breakpoint_event_object_type,
+                                stopped_thread);
+
+  if (!breakpoint_event_obj)
+    goto fail;
+
+  if (evpy_add_attribute (breakpoint_event_obj,
+                          "breakpoint",
+                          gdbpy_breakpoint_from_bpstats (bs)) < 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..2a00630
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_continue_event_object (void)
+{
+  return 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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.cont))
+    return 0;
+
+  event = 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..88f8db6
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,175 @@
+/* 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);
+}
+
+PyObject *
+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 (PyObject*) 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 (PyObject *event, char *name, PyObject *attr)
+{
+  return PyObject_SetAttrString (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 (PyObject *event,
+                 eventregistry_object *registry)
+{
+  PyObject *callback_list_copy = NULL;
+  Py_ssize_t i;
+
+  /* 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 (registry->callbacks);
+  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, 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);
+  return 0;
+
+ fail:
+  gdbpy_print_stack ();
+  Py_XDECREF (callback_list_copy);
+  Py_XDECREF (event);
+  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..cca19c5
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,118 @@
+/* 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 (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 */ \
+      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_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST exit_code);
+
+extern int evpy_emit_event (PyObject *event,
+                            eventregistry_object *registry);
+extern PyObject *create_event_object (PyTypeObject *py_type);
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (PyObject *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..8dbe12e
--- /dev/null
+++ b/gdb/python/py-events.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_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
+
+  PyObject *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 *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..e1b4346
--- /dev/null
+++ b/gdb/python/py-evtregistry.c
@@ -0,0 +1,170 @@
+/* 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 = (((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;
+    }
+
+  if (PyList_Append (callback_list, func) < 0)
+    return NULL;
+
+  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 = (((eventregistry_object *) self)->callbacks);
+
+  if (!PyArg_ParseTuple (function, "O", &func))
+    return NULL;
+
+  index = PySequence_Index (callback_list, func);
+  if (index < 0)
+    Py_RETURN_NONE;
+
+  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 = 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 (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..446b934
--- /dev/null
+++ b/gdb/python/py-evts.c
@@ -0,0 +1,71 @@
+/* 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.cont, "cont") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.exited, "exited") < 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..457a4fe
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,71 @@
+/* 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;
+
+PyObject *
+create_exited_event_object (LONGEST exit_code)
+{
+  PyObject *exited_event;
+
+  exited_event = create_event_object (&exited_event_object_type);
+
+  if (!exited_event)
+    goto fail;
+
+  if (evpy_add_attribute (exited_event,
+                          "exit_code",
+                          PyLong_FromLongLong (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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.exited))
+    return 0;
+
+  event = 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..f8dd725 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,55 @@ 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 exit_code = -1;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  exit_code = inf->exit_code;
+
+  if (exit_code >= 0
+      && 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 +160,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 +642,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..289a0f7
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,55 @@
+/* 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;
+
+PyObject *
+create_signal_event_object (enum target_signal stop_signal,
+                            PyObject *stopped_thread)
+{
+  const char *signal_name;
+  PyObject *signal_event_obj =
+      create_stop_event_object (&signal_event_object_type,
+                                stopped_thread);
+
+  if (!signal_event_obj)
+    goto fail;
+
+  signal_name = target_signal_to_name (stop_signal);
+
+  if (evpy_add_attribute (signal_event_obj,
+                          "stop_signal",
+                          PyString_FromString (signal_name)) < 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..ba5f0fa
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,136 @@
+/* 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"
+
+PyObject *
+create_stop_event_object (PyTypeObject *py_type, PyObject *thread)
+{
+  PyObject *stop_event_obj = create_event_object (py_type);
+
+  if (!stop_event_obj)
+    goto fail;
+
+  if (evpy_add_attribute (stop_event_obj,
+                          "inferior_thread",
+                          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 (void)
+{
+  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)
+{
+  PyObject *stop_event_obj = NULL; /* Appease GCC warning.  */
+  PyObject* stopped_thread = NULL;
+
+  if (evregpy_no_listeners_p (gdb_py_events.stop))
+    return 0;
+
+  if (bs && bs->breakpoint_at
+      && bs->breakpoint_at->type == bp_breakpoint)
+    {
+      stopped_thread = get_stopped_thread();
+      if (!stopped_thread)
+	goto fail;
+
+      stop_event_obj =
+	  create_breakpoint_event_object (bs, stopped_thread);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
+  if (stop_signal != TARGET_SIGNAL_0
+      && stop_signal != TARGET_SIGNAL_TRAP)
+    {
+      stopped_thread = get_stopped_thread();
+      if (!stopped_thread)
+	goto fail;
+
+      stop_event_obj =
+	  create_signal_event_object (stop_signal, stopped_thread);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* If all fails emit an unknown stop event.  All event types should
+     be known and this should eventually be unused.  */
+  if (!stop_event_obj)
+    {
+      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;
+    }
+
+  return evpy_emit_event (stop_event_obj, gdb_py_events.stop);
+
+  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..a85c43d
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,40 @@
+/* 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"
+
+extern PyObject *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 PyObject *
+create_breakpoint_event_object (struct bpstats *bs,
+                                PyObject *stopped_thread);
+
+extern PyObject *
+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..f285c8c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-21  Sami Wagiaalla  <swagiaal@redhat.com>
+
+	* gdb.python/py-evthreads.c: New file.
+	* gdb.python/py-evthreads.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..c2be5cc
--- /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.stop.connect (signal_stop_handler)
+        gdb.events.stop.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.*"

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-01-21 23:06       ` sami wagiaalla
@ 2011-01-28 16:21         ` Tom Tromey
  2011-02-02 21:04           ` sami wagiaalla
  0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-01-28 16:21 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> Okay, I added exit_code to struct inferior, set it and used it. How
Sami> does that part of the patch look ?

It seems reasonable to me, but while looking I ran across
get_last_target_status.  Can we use that instead?  It isn't super to
rely on globals like this, but existing globals are grandfathered in...

Sami> +      current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;

If we keep this approach then I think you do not need this cast.

Sami> +                          gdbpy_breakpoint_from_bpstats (bs)) < 0)

I think it is possible for gdbpy_breakpoint_from_bpstats to return NULL.
This is not really an error condition; it just means that this
breakpoint has no corresponding Python object.

I am not sure what to do in this case, but we definitely can't do this :-)

Sami> +  event = create_continue_event_object ();

Are continue events symmetric to stop events, meaning that it should
indicate which threads were continued?

This is looking quite good.

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-01-28 16:21         ` Tom Tromey
@ 2011-02-02 21:04           ` sami wagiaalla
  2011-02-02 21:35             ` Tom Tromey
  0 siblings, 1 reply; 42+ messages in thread
From: sami wagiaalla @ 2011-02-02 21:04 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1529 bytes --]


> It seems reasonable to me, but while looking I ran across
> get_last_target_status.  Can we use that instead?  It isn't super to
> rely on globals like this, but existing globals are grandfathered in...
>

Yes. get_last_target_status works. I have updated the patch.

>
> Sami>  +                          gdbpy_breakpoint_from_bpstats (bs))<  0)
>
> I think it is possible for gdbpy_breakpoint_from_bpstats to return NULL.
> This is not really an error condition; it just means that this
> breakpoint has no corresponding Python object.
>
> I am not sure what to do in this case, but we definitely can't do this :-)
>

Hmm... We can just create the corresponding Python object, but shouldn't 
this situation be an error condition since gdbpy_breakpoint_created is 
observing breakpoint creation and creating the needed python objects ?

For now I added an error check, but I can modify 
gdbpy_breakpoint_created to allow us to reuse it and create the object 
if it is missing.

> Sami>  +  event = create_continue_event_object ();
>
> Are continue events symmetric to stop events, meaning that it should
> indicate which threads were continued?
>

Yes that is correct. I created a new event type called ThreadEvent to be 
a parent to all events which can be thread specific. Stop events and 
continue event are now children of thread event.

I also updated the test to test that the continue events are indeed 
being delivered to the intended thread, and that python reflects that. 
The documentation was also updated.

Sami

[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 61543 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..423965f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,32 @@
+2011-01-21  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-evtregistry.c: New file.
+	* python/py-threadevent.c : New file.
+	* python/py-event.c: New file.
+	* python/py-evts.c: New file.
+	* python/py-continueevent.c: New file.
+	* python/py-bpevent.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..f8e6cbb 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,27 @@ 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-threadevent.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,8 +319,11 @@ 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-threadevent.c \
 	python/py-type.c \
 	python/py-utils.c \
 	python/py-value.c
@@ -1992,6 +2011,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 +2023,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 +2079,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)
@@ -2044,6 +2095,10 @@ py-symtab.o: $(srcdir)/python/py-symtab.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
 	$(POSTCOMPILE)
 
+py-threadevent.o: $(srcdir)/python/py-threadevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-threadevent.c
+	$(POSTCOMPILE)
+
 py-type.o: $(srcdir)/python/py-type.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 559609b..d5bae34 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,14 @@
 
   ** gdb.parameter("directories") is now available.
 
+  ** 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.cont Continue event.
+     - gdb.events.exited Inferior exited event.
+     - gdb.events.stop Signal received, and Breakpoint hit events.
+
 * C++ Improvements:
 
   ** GDB now puts template parameters in scope when debugging in an
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dc9630a..6bd62e5 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)
+* Events In Python::            Listening for events from GDB.
 * 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,116 @@ the pattern could not be found.
 @end defmethod
 @end table
 
+@node Events In Python
+@subsubsection Events In Python
+@cindex inferior events in python
+
+GDB provides a general event facility so that Python code can be
+notified of various state changes, particularly changes that occur in
+the inferior.
+
+An @dfn{event} is just an object that describes some state change.  The
+type of the object and its attributes will vary depending on the details
+of the change.  All the existing events are described below.
+
+In order to be notified of an event, you must register an event handler
+with an event registry.  An @dfn{event registry} is an object in the
+@code{gdb.events} module which dispatches particular events.  A registry
+provides methods to register and unregister event handlers:
+
+@table @code
+@defmethod EventRegistry connect callable
+Add the given callable object to the registry.  This object will be called
+when an event corresponding to this registry occurs.
+@end defmethod
+
+@defmethod EventRegistry disconnect callable
+Remove the given object from the registry.  Once removed the object will no
+longer receive notifications of events.
+@end defmethod
+@end table
+
+Here is an example:
+
+@smallexample
+def exit_handler (event):
+    print "event type: exit"
+    print "exit code: %d" % (event.exit_code)
+
+gdb.events.exited.connect (exit_handler)
+@end smallexample
+
+In the above example we connect our handler @code{exit_handler} to the
+registry @code{events.exited}.  Once connected @code{exit_handler} receives
+notifications of exited events.  The argument @dfn{event} in this example is
+of type @code{gdb.ExitedEvent}.  As you can see in the example the
+@code{ExitedEvent} object has an attribute which indicates the exit code of
+the inferior.
+
+The following is a listing of the event registries that are available and
+details of the events they emit:
+
+@table @code
+
+@item events.cont
+Emits @code{gdb.ContinueEvent}
+Indicates that the inferior has been continued.
+@table @code
+@defivar ContinueEvent inferior_thread
+In non-stop mode this attribute will be set to the specific thread that
+was continued and @code{None} otherwise.
+@end defivar
+@end table
+
+@item events.exited
+Emits @code{events.ExitedEvent} which indicates that the inferior has exited.
+@code{events.ExitedEvent} as one attribute:
+@table @code
+@defivar ExitedEvent exit_code
+An integer representing the exit code which the inferior has returned.
+@end defivar
+@end table
+
+@item events.stop
+Emits @code{gdb.SignalEvent} which indicates that the inferior or one of its
+threads has received as signal.  @code{gdb.SignalEvent} has the following
+attributes:
+
+@table @code
+@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
+A string representing the signal received by the inferior.  A list of possible
+signal values can be obtained by running the command @code{info signals} in
+the @value{GDBN} command prompt.
+@end defivar
+
+Also emits  @code{gdb.BreakpointEvent} which indicates that a breakpoint has
+been hit.  A @code{BreakpointEvent} object as the following attributes:
+
+@table @code
+@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
+@end table
+
+@end table
+
+@end table
+
 @node Threads In Python
 @subsubsection Threads In Python
 @cindex threads in python
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644
index 0000000..32ed9f5
--- /dev/null
+++ b/gdb/python/py-bpevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+/* Create and initialize a BreakpointEvent object.  */
+
+PyObject *
+create_breakpoint_event_object (struct bpstats *bs)
+{
+  PyObject *breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+  PyObject *breakpoint_event_obj =
+      create_stop_event_object (&breakpoint_event_object_type);
+
+  if (!breakpoint_event_obj || !breakpoint)
+    goto fail;
+
+  if (evpy_add_attribute (breakpoint_event_obj,
+                          "breakpoint",
+                          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..1338ba6
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_continue_event_object (void)
+{
+  return create_thread_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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.cont))
+    return 0;
+
+  event = 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",
+                      thread_event_object_type,
+                      static);
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..88f8db6
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,175 @@
+/* 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);
+}
+
+PyObject *
+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 (PyObject*) 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 (PyObject *event, char *name, PyObject *attr)
+{
+  return PyObject_SetAttrString (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 (PyObject *event,
+                 eventregistry_object *registry)
+{
+  PyObject *callback_list_copy = NULL;
+  Py_ssize_t i;
+
+  /* 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 (registry->callbacks);
+  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, 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);
+  return 0;
+
+ fail:
+  gdbpy_print_stack ();
+  Py_XDECREF (callback_list_copy);
+  Py_XDECREF (event);
+  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..bc95521
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,121 @@
+/* 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 (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 */ \
+      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_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST exit_code);
+
+extern int evpy_emit_event (PyObject *event,
+                            eventregistry_object *registry);
+
+extern PyObject *create_event_object (PyTypeObject *py_type);
+extern PyObject *create_thread_event_object (PyTypeObject *py_type);
+
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (PyObject *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..6d4dae5
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,59 @@
+/* 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"
+
+extern PyTypeObject thread_event_object_type;
+
+/* Stores a list of objects to be notified when the event for which this
+   registry tracks occurs.  */
+
+typedef struct
+{
+  PyObject_HEAD
+
+  PyObject *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 *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..e1b4346
--- /dev/null
+++ b/gdb/python/py-evtregistry.c
@@ -0,0 +1,170 @@
+/* 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 = (((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;
+    }
+
+  if (PyList_Append (callback_list, func) < 0)
+    return NULL;
+
+  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 = (((eventregistry_object *) self)->callbacks);
+
+  if (!PyArg_ParseTuple (function, "O", &func))
+    return NULL;
+
+  index = PySequence_Index (callback_list, func);
+  if (index < 0)
+    Py_RETURN_NONE;
+
+  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 = 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 (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..446b934
--- /dev/null
+++ b/gdb/python/py-evts.c
@@ -0,0 +1,71 @@
+/* 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.cont, "cont") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.exited, "exited") < 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..457a4fe
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,71 @@
+/* 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;
+
+PyObject *
+create_exited_event_object (LONGEST exit_code)
+{
+  PyObject *exited_event;
+
+  exited_event = create_event_object (&exited_event_object_type);
+
+  if (!exited_event)
+    goto fail;
+
+  if (evpy_add_attribute (exited_event,
+                          "exit_code",
+                          PyLong_FromLongLong (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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.exited))
+    return 0;
+
+  event = 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..ef05dca 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,59 @@ 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 exit_code = -1;
+  ptid_t ptidp;
+  struct target_waitstatus status;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  get_last_target_status (&ptidp, &status);
+
+  exit_code = status.value.integer;
+
+  if (exit_code >= 0
+      && 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 +164,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 +646,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..3d7ce32
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_signal_event_object (enum target_signal stop_signal)
+{
+  const char *signal_name;
+  PyObject *signal_event_obj =
+      create_stop_event_object (&signal_event_object_type);
+
+  if (!signal_event_obj)
+    goto fail;
+
+  signal_name = target_signal_to_name (stop_signal);
+
+  if (evpy_add_attribute (signal_event_obj,
+                          "stop_signal",
+                          PyString_FromString (signal_name)) < 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..4fa62e0
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,92 @@
+/* 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"
+
+PyObject *
+create_stop_event_object (PyTypeObject *py_type)
+{
+  PyObject *stop_event_obj = create_thread_event_object (py_type);
+
+  if (!stop_event_obj)
+    goto fail;
+
+  return stop_event_obj;
+
+  fail:
+   Py_XDECREF (stop_event_obj);
+   return NULL;
+}
+
+/* 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)
+{
+  PyObject *stop_event_obj = NULL; /* Appease GCC warning.  */
+
+  if (evregpy_no_listeners_p (gdb_py_events.stop))
+    return 0;
+
+  if (bs && bs->breakpoint_at
+      && bs->breakpoint_at->type == bp_breakpoint)
+    {
+      stop_event_obj =
+	  create_breakpoint_event_object (bs);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
+  if (stop_signal != TARGET_SIGNAL_0
+      && stop_signal != TARGET_SIGNAL_TRAP)
+    {
+
+      stop_event_obj =
+	  create_signal_event_object (stop_signal);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* If all fails emit an unknown stop event.  All event types should
+     be known and this should eventually be unused.  */
+  if (!stop_event_obj)
+    {
+      stop_event_obj = create_stop_event_object (&stop_event_object_type);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  return evpy_emit_event (stop_event_obj, gdb_py_events.stop);
+
+  fail:
+   return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (stop,
+                      "gdb.StopEvent",
+                      "StopEvent",
+                      "GDB stop event object",
+                      thread_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..498774b
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,37 @@
+/* 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"
+
+extern PyObject *create_stop_event_object (PyTypeObject *py_type);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+                            enum target_signal stop_signal);
+
+extern PyObject *
+create_breakpoint_event_object (struct bpstats *bs);
+
+extern PyObject *
+create_signal_event_object (enum target_signal stop_signal);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..8fcdca2 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,15 @@ 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);
+void gdbpy_initialize_thread_event (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 
diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..46eed8b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1001,6 +1001,16 @@ 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 ();
+  gdbpy_initialize_thread_event ();
+
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = []");
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0417538..f285c8c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-21  Sami Wagiaalla  <swagiaal@redhat.com>
+
+	* gdb.python/py-evthreads.c: New file.
+	* gdb.python/py-evthreads.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..9f05b9f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,64 @@
+# 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"
+    if ( event.inferior_thread is not None) :
+        print "thread num: %s" % (event.inferior_thread.num);
+
+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.stop.connect (signal_stop_handler)
+        gdb.events.stop.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..1464ce6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -0,0 +1,55 @@
+/* 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 (thread2_id, NULL);
+  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..6ea7eb4
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -0,0 +1,119 @@
+# 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"
+	}
+}
+
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 1.*" {
+        pass "continue thread 1"
+    }
+    timeout {
+	    fail "continue thread 1 failed"
+	}
+}
+
+gdb_test "thread 2" ".*Switching to thread 2.*"
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 2.*" {
+        pass "continue thread 2"
+    }
+    timeout {
+	    fail "continue thread 2 failed"
+	}
+}
+
+send_gdb "continue -a\n"
+gdb_expect {
+    -re ".*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*" {
+        pass "thread 3 was signalled"
+    }
+    timeout {
+	    fail "thread 3 was not signalled"
+	}
+}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-02 21:04           ` sami wagiaalla
@ 2011-02-02 21:35             ` Tom Tromey
  2011-02-03 16:41               ` sami wagiaalla
  0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-02-02 21:35 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> Hmm... We can just create the corresponding Python object, but
Sami> shouldn't this situation be an error condition since
Sami> gdbpy_breakpoint_created is observing breakpoint creation and creating
Sami> the needed python objects ?

No, because gdbpy_breakpoint_created filters out some breakpoints,
notably internal ones.

Sami> Yes that is correct. I created a new event type called ThreadEvent
Sami> to be a parent to all events which can be thread specific. Stop
Sami> events and continue event are now children of thread event.

In this case I think ThreadEvent should be in the docs.

Sami> +PyObject *
Sami> +create_breakpoint_event_object (struct bpstats *bs)
Sami> +{
Sami> +  PyObject *breakpoint = gdbpy_breakpoint_from_bpstats (bs);
Sami> +  PyObject *breakpoint_event_obj =
Sami> +      create_stop_event_object (&breakpoint_event_object_type);
Sami> +  if (!breakpoint_event_obj || !breakpoint)
Sami> +    goto fail;

This wouldn't work, since if breakpoint==NULL, we never set an error
message.

I think this code should probably have a way to cause emit_stop_event to
fall through to the "unknown" case.

I didn't see py-threadevent.c in the patch.

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-02 21:35             ` Tom Tromey
@ 2011-02-03 16:41               ` sami wagiaalla
  2011-02-03 18:26                 ` Eli Zaretskii
  2011-02-03 21:42                 ` Tom Tromey
  0 siblings, 2 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-02-03 16:41 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1677 bytes --]

On 02/02/2011 04:35 PM, Tom Tromey wrote:
>>>>>> "Sami" == sami wagiaalla<swagiaal@redhat.com>  writes:
>
> Sami>  Hmm... We can just create the corresponding Python object, but
> Sami>  shouldn't this situation be an error condition since
> Sami>  gdbpy_breakpoint_created is observing breakpoint creation and creating
> Sami>  the needed python objects ?
>
> No, because gdbpy_breakpoint_created filters out some breakpoints,
> notably internal ones.
>

Ah, I see. This case now generates a generic stop event as you suggested 
in a comment below.

> Sami>  Yes that is correct. I created a new event type called ThreadEvent
> Sami>  to be a parent to all events which can be thread specific. Stop
> Sami>  events and continue event are now children of thread event.
>
> In this case I think ThreadEvent should be in the docs.
>

Added. I also, documented StopEvent. In events which inherit from others 
I added a statement asking the reader to refer to the parent. Do you 
think that is enough, or should the inherited attributes be restated ?

> Sami>  +PyObject *
> Sami>  +create_breakpoint_event_object (struct bpstats *bs)
> Sami>  +{
> Sami>  +  PyObject *breakpoint = gdbpy_breakpoint_from_bpstats (bs);
> Sami>  +  PyObject *breakpoint_event_obj =
> Sami>  +      create_stop_event_object (&breakpoint_event_object_type);
> Sami>  +  if (!breakpoint_event_obj || !breakpoint)
> Sami>  +    goto fail;
>
> This wouldn't work, since if breakpoint==NULL, we never set an error
> message.
>
> I think this code should probably have a way to cause emit_stop_event to
> fall through to the "unknown" case.
>

Done.

> I didn't see py-threadevent.c in the patch.
>

Added.

[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 64185 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..423965f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,32 @@
+2011-01-21  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-evtregistry.c: New file.
+	* python/py-threadevent.c : New file.
+	* python/py-event.c: New file.
+	* python/py-evts.c: New file.
+	* python/py-continueevent.c: New file.
+	* python/py-bpevent.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..f8e6cbb 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,27 @@ 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-threadevent.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,8 +319,11 @@ 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-threadevent.c \
 	python/py-type.c \
 	python/py-utils.c \
 	python/py-value.c
@@ -1992,6 +2011,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 +2023,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 +2079,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)
@@ -2044,6 +2095,10 @@ py-symtab.o: $(srcdir)/python/py-symtab.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
 	$(POSTCOMPILE)
 
+py-threadevent.o: $(srcdir)/python/py-threadevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-threadevent.c
+	$(POSTCOMPILE)
+
 py-type.o: $(srcdir)/python/py-type.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 559609b..d5bae34 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,14 @@
 
   ** gdb.parameter("directories") is now available.
 
+  ** 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.cont Continue event.
+     - gdb.events.exited Inferior exited event.
+     - gdb.events.stop Signal received, and Breakpoint hit events.
+
 * C++ Improvements:
 
   ** GDB now puts template parameters in scope when debugging in an
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dc9630a..448d69c 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)
+* Events In Python::            Listening for events from GDB.
 * 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,124 @@ the pattern could not be found.
 @end defmethod
 @end table
 
+@node Events In Python
+@subsubsection Events In Python
+@cindex inferior events in python
+
+GDB provides a general event facility so that Python code can be
+notified of various state changes, particularly changes that occur in
+the inferior.
+
+An @dfn{event} is just an object that describes some state change.  The
+type of the object and its attributes will vary depending on the details
+of the change.  All the existing events are described below.
+
+In order to be notified of an event, you must register an event handler
+with an event registry.  An @dfn{event registry} is an object in the
+@code{gdb.events} module which dispatches particular events.  A registry
+provides methods to register and unregister event handlers:
+
+@table @code
+@defmethod EventRegistry connect callable
+Add the given callable object to the registry.  This object will be called
+when an event corresponding to this registry occurs.
+@end defmethod
+
+@defmethod EventRegistry disconnect callable
+Remove the given object from the registry.  Once removed the object will no
+longer receive notifications of events.
+@end defmethod
+@end table
+
+Here is an example:
+
+@smallexample
+def exit_handler (event):
+    print "event type: exit"
+    print "exit code: %d" % (event.exit_code)
+
+gdb.events.exited.connect (exit_handler)
+@end smallexample
+
+In the above example we connect our handler @code{exit_handler} to the
+registry @code{events.exited}.  Once connected @code{exit_handler} receives
+notifications of exited events.  The argument @dfn{event} in this example is
+of type @code{gdb.ExitedEvent}.  As you can see in the example the
+@code{ExitedEvent} object has an attribute which indicates the exit code of
+the inferior.
+
+The following is a listing of the event registries that are available and
+details of the events they emit:
+
+@table @code
+
+@item events.cont
+Emits @code{gdb.ThreadEvent}
+
+Some events can be thread specific when GDB is running in non-stop mode.  When
+represented in python these events all extend @code{gdb.ThreadEvent}.  Note,
+this event is not emitted directly; instead, events which are emitted by
+this or other modules might extend this event.  Examples of these events are
+@code{gdb.BreakpointEvent} and @code{gdb.ContinueEvent}.
+
+@table @code
+@defivar ThreadEvent inferior_thread
+In non-stop mode this attribute will be set to the specific thread which was
+involved in the emitted event. Otherwise, it will be set to @code{None}.
+@end defivar
+@end table
+
+Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}
+
+This event indicates that the inferior has been continued after a stop. For
+inherited attribute refer to @code{gdb.ThreadEvent} above.
+
+@item events.exited
+Emits @code{events.ExitedEvent} which indicates that the inferior has exited.
+@code{events.ExitedEvent} has one attribute:
+@table @code
+@defivar ExitedEvent exit_code
+An integer representing the exit code which the inferior has returned.
+@end defivar
+@end table
+
+@item events.stop
+Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}
+
+Indicates that the inferior has stopped. All events emitted by this registry
+extend StopEvent. As a child of @code{gdb.ThreadEvent} @code{gdb.StopEvent}
+will indicate the stopped thread when gdb is running in non-stop mode. Refer
+to @code{gdb.ThreadEvent} above for more details.
+
+Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}
+
+This event indicates that the inferior or one of its threads has received as
+signal.  @code{gdb.SignalEvent} has the following attributes:
+
+@table @code
+@defivar SignalEvent stop_signal
+A string representing the signal received by the inferior.  A list of possible
+signal values can be obtained by running the command @code{info signals} in
+the @value{GDBN} command prompt.
+@end defivar
+
+Also emits  @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}
+
+@code{gdb.BreakpointEvent} event indicates that a breakpoint has been hit, and
+has the following attributes:
+
+@table @code
+@defivar BreakpointEvent breakpoint
+A reference to the breakpoint that was hit of type @code{gdb.Breakpoint}.
+@xref{Breakpoints In Python}, for details of the @code{gdb.Breakpoint} object.
+@end defivar
+
+@end table
+
+@end table
+
+@end table
+
 @node Threads In Python
 @subsubsection Threads In Python
 @cindex threads in python
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644
index 0000000..c7f7965
--- /dev/null
+++ b/gdb/python/py-bpevent.c
@@ -0,0 +1,52 @@
+/* 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;
+
+/* Create and initialize a BreakpointEvent object.  */
+
+PyObject *
+create_breakpoint_event_object (PyObject *breakpoint)
+{
+  PyObject *breakpoint_event_obj =
+      create_stop_event_object (&breakpoint_event_object_type);
+
+  if (!breakpoint_event_obj)
+    goto fail;
+
+  if (evpy_add_attribute (breakpoint_event_obj,
+                          "breakpoint",
+                          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..1338ba6
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_continue_event_object (void)
+{
+  return create_thread_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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.cont))
+    return 0;
+
+  event = 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",
+                      thread_event_object_type,
+                      static);
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..88f8db6
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,175 @@
+/* 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);
+}
+
+PyObject *
+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 (PyObject*) 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 (PyObject *event, char *name, PyObject *attr)
+{
+  return PyObject_SetAttrString (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 (PyObject *event,
+                 eventregistry_object *registry)
+{
+  PyObject *callback_list_copy = NULL;
+  Py_ssize_t i;
+
+  /* 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 (registry->callbacks);
+  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, 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);
+  return 0;
+
+ fail:
+  gdbpy_print_stack ();
+  Py_XDECREF (callback_list_copy);
+  Py_XDECREF (event);
+  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..bc95521
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,121 @@
+/* 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 (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 */ \
+      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_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST exit_code);
+
+extern int evpy_emit_event (PyObject *event,
+                            eventregistry_object *registry);
+
+extern PyObject *create_event_object (PyTypeObject *py_type);
+extern PyObject *create_thread_event_object (PyTypeObject *py_type);
+
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (PyObject *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..6d4dae5
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,59 @@
+/* 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"
+
+extern PyTypeObject thread_event_object_type;
+
+/* Stores a list of objects to be notified when the event for which this
+   registry tracks occurs.  */
+
+typedef struct
+{
+  PyObject_HEAD
+
+  PyObject *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 *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..e1b4346
--- /dev/null
+++ b/gdb/python/py-evtregistry.c
@@ -0,0 +1,170 @@
+/* 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 = (((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;
+    }
+
+  if (PyList_Append (callback_list, func) < 0)
+    return NULL;
+
+  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 = (((eventregistry_object *) self)->callbacks);
+
+  if (!PyArg_ParseTuple (function, "O", &func))
+    return NULL;
+
+  index = PySequence_Index (callback_list, func);
+  if (index < 0)
+    Py_RETURN_NONE;
+
+  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 = 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 (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..446b934
--- /dev/null
+++ b/gdb/python/py-evts.c
@@ -0,0 +1,71 @@
+/* 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.cont, "cont") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.exited, "exited") < 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..457a4fe
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,71 @@
+/* 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;
+
+PyObject *
+create_exited_event_object (LONGEST exit_code)
+{
+  PyObject *exited_event;
+
+  exited_event = create_event_object (&exited_event_object_type);
+
+  if (!exited_event)
+    goto fail;
+
+  if (evpy_add_attribute (exited_event,
+                          "exit_code",
+                          PyLong_FromLongLong (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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.exited))
+    return 0;
+
+  event = 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..ef05dca 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,59 @@ 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 exit_code = -1;
+  ptid_t ptidp;
+  struct target_waitstatus status;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  get_last_target_status (&ptidp, &status);
+
+  exit_code = status.value.integer;
+
+  if (exit_code >= 0
+      && 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 +164,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 +646,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..3d7ce32
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_signal_event_object (enum target_signal stop_signal)
+{
+  const char *signal_name;
+  PyObject *signal_event_obj =
+      create_stop_event_object (&signal_event_object_type);
+
+  if (!signal_event_obj)
+    goto fail;
+
+  signal_name = target_signal_to_name (stop_signal);
+
+  if (evpy_add_attribute (signal_event_obj,
+                          "stop_signal",
+                          PyString_FromString (signal_name)) < 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..7faed39
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,94 @@
+/* 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"
+
+PyObject *
+create_stop_event_object (PyTypeObject *py_type)
+{
+  PyObject *stop_event_obj = create_thread_event_object (py_type);
+
+  if (!stop_event_obj)
+    goto fail;
+
+  return stop_event_obj;
+
+  fail:
+   Py_XDECREF (stop_event_obj);
+   return NULL;
+}
+
+/* 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)
+{
+  PyObject *stop_event_obj = NULL; /* Appease GCC warning.  */
+
+  if (evregpy_no_listeners_p (gdb_py_events.stop))
+    return 0;
+
+  if (bs && bs->breakpoint_at
+      && bs->breakpoint_at->type == bp_breakpoint)
+    {
+      PyObject *breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+      if (breakpoint != NULL)
+      stop_event_obj =
+	  create_breakpoint_event_object (breakpoint);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
+  if (stop_signal != TARGET_SIGNAL_0
+      && stop_signal != TARGET_SIGNAL_TRAP)
+    {
+
+      stop_event_obj =
+	  create_signal_event_object (stop_signal);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* If all fails emit an unknown stop event.  All event types should
+     be known and this should eventually be unused.  */
+  if (!stop_event_obj)
+    {
+      stop_event_obj = create_stop_event_object (&stop_event_object_type);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  return evpy_emit_event (stop_event_obj, gdb_py_events.stop);
+
+  fail:
+   return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (stop,
+                      "gdb.StopEvent",
+                      "StopEvent",
+                      "GDB stop event object",
+                      thread_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..690cbbd
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,37 @@
+/* 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"
+
+extern PyObject *create_stop_event_object (PyTypeObject *py_type);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+                            enum target_signal stop_signal);
+
+extern PyObject *
+create_breakpoint_event_object (PyObject *breakpoint);
+
+extern PyObject *
+create_signal_event_object (enum target_signal stop_signal);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/py-threadevent.c b/gdb/python/py-threadevent.c
new file mode 100644
index 0000000..1123706
--- /dev/null
+++ b/gdb/python/py-threadevent.c
@@ -0,0 +1,71 @@
+/* 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"
+
+/* thread 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.  */
+
+static PyObject *
+get_event_thread (void)
+{
+  PyObject *thread = NULL;
+
+  if (non_stop)
+    thread = (PyObject *) find_thread_object (inferior_ptid);
+  else
+    thread = Py_None;
+
+  if (!thread)
+    return NULL;
+
+  Py_INCREF (thread);
+
+  return thread;
+}
+
+PyObject *
+create_thread_event_object (PyTypeObject *py_type)
+{
+  PyObject *thread_event_obj = create_event_object (py_type);
+  PyObject *thread = get_event_thread();
+
+  if (!thread_event_obj || !thread)
+    goto fail;
+
+  if (evpy_add_attribute (thread_event_obj,
+                          "inferior_thread",
+                          thread) < 0)
+    goto fail;
+
+  return thread_event_obj;
+
+  fail:
+   Py_XDECREF (thread_event_obj);
+   return NULL;
+
+}
+
+GDBPY_NEW_EVENT_TYPE (thread,
+                      "gdb.ThreadEvent",
+                      "ThreadEvent",
+                      "GDB thread event object",
+                      event_object_type,
+                      /*no qual*/);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..8fcdca2 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,15 @@ 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);
+void gdbpy_initialize_thread_event (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 
diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..46eed8b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1001,6 +1001,16 @@ 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 ();
+  gdbpy_initialize_thread_event ();
+
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = []");
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0417538..f285c8c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-21  Sami Wagiaalla  <swagiaal@redhat.com>
+
+	* gdb.python/py-evthreads.c: New file.
+	* gdb.python/py-evthreads.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..9f05b9f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,64 @@
+# 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"
+    if ( event.inferior_thread is not None) :
+        print "thread num: %s" % (event.inferior_thread.num);
+
+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.stop.connect (signal_stop_handler)
+        gdb.events.stop.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..1464ce6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -0,0 +1,55 @@
+/* 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 (thread2_id, NULL);
+  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..6ea7eb4
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -0,0 +1,119 @@
+# 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"
+	}
+}
+
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 1.*" {
+        pass "continue thread 1"
+    }
+    timeout {
+	    fail "continue thread 1 failed"
+	}
+}
+
+gdb_test "thread 2" ".*Switching to thread 2.*"
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 2.*" {
+        pass "continue thread 2"
+    }
+    timeout {
+	    fail "continue thread 2 failed"
+	}
+}
+
+send_gdb "continue -a\n"
+gdb_expect {
+    -re ".*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*" {
+        pass "thread 3 was signalled"
+    }
+    timeout {
+	    fail "thread 3 was not signalled"
+	}
+}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-03 16:41               ` sami wagiaalla
@ 2011-02-03 18:26                 ` Eli Zaretskii
  2011-02-03 19:45                   ` sami wagiaalla
  2011-02-03 21:42                 ` Tom Tromey
  1 sibling, 1 reply; 42+ messages in thread
From: Eli Zaretskii @ 2011-02-03 18:26 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: tromey, gdb-patches

> Date: Thu, 03 Feb 2011 11:40:42 -0500
> From: sami wagiaalla <swagiaal@redhat.com>
> CC: gdb-patches@sourceware.org
> 
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -40,6 +40,14 @@
>  
>    ** gdb.parameter("directories") is now available.
>  
> +  ** 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.cont Continue event.
> +     - gdb.events.exited Inferior exited event.
> +     - gdb.events.stop Signal received, and Breakpoint hit events.
> +

OK for this part.

> +* Events In Python::            Listening for events from GDB.
                                                             ^^^
"@value{GDBN}" instead of a literal "GDB".

> +GDB provides a general event facility so that Python code can be
   ^^^
Ditto.

> +In order to be notified of an event, you must register an event handler
> +with an event registry.  An @dfn{event registry} is an object in the
           ^^^^^^^^^^^^^^      ^^^^^^^^^^^^^^^^^^^^
Please use @dfn when you first use the new term.  In this case, in the
previous sentence.

> +@defmethod EventRegistry connect callable
> +Add the given callable object to the registry.  This object will be called
> +when an event corresponding to this registry occurs.

"callable" should have the @var markup.

> +@defmethod EventRegistry disconnect callable
> +Remove the given object from the registry.  Once removed the object will no
                                                          ^^^
Same here.  And please add the missing comma after "removed".

Also, isn't it better to use "object" as the argument instead of
"callable"?  How about this:

  @defmethod EventRegistry connect object
  Add the given callable @var{object} to the registry.  This object will
  be called when an event corresponding to this registry occurs.
  @end defmethod

> +registry @code{events.exited}.  Once connected @code{exit_handler} receives
                                                ^^
A missing comma.

> +notifications of exited events.  The argument @dfn{event} in this example is

Hmm... "receives notifications" is not really true, is it?  It gets
called when exit events happen, right?

> +@item events.cont
> +Emits @code{gdb.ThreadEvent}

Please add a period at the end of this sentence.

> +Some events can be thread specific when GDB is running in non-stop mode.  When
                                           ^^^
"@value{GDBN}"

> +represented in python these events all extend @code{gdb.ThreadEvent}.  Note,
                  ^^^^^^
Should be "Python", right?  And please add a comma after it.

> +Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}

A period at the end, please.

> +Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}

Likewise.

> +Indicates that the inferior has stopped. All events emitted by this registry
> +extend StopEvent. As a child of @code{gdb.ThreadEvent} @code{gdb.StopEvent}
> +will indicate the stopped thread when gdb is running in non-stop mode. Refer
> +to @code{gdb.ThreadEvent} above for more details.

This paragraph needs two spaces after each sentence, not one.

Also, a comma is missing here:

> +extend StopEvent. As a child of @code{gdb.ThreadEvent} @code{gdb.StopEvent}
                                                        ^^^
And you need to use "@value{GDBN}" again here:

> +will indicate the stopped thread when gdb is running in non-stop mode. Refer
                                         ^^^

> +Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}

Period.

> +Also emits  @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}

Period.

> +@end table

This "@end table" is misplaced, it should have been after this:

> +@table @code
> +@defivar SignalEvent stop_signal
> +A string representing the signal received by the inferior.  A list of possible
> +signal values can be obtained by running the command @code{info signals} in
> +the @value{GDBN} command prompt.
> +@end defivar

OK with those changes.

Thanks.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-03 18:26                 ` Eli Zaretskii
@ 2011-02-03 19:45                   ` sami wagiaalla
  0 siblings, 0 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-02-03 19:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tromey, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 4430 bytes --]

Made requested modifications and some other formatting fixes.
Thanks for the review.

On 02/03/2011 01:26 PM, Eli Zaretskii wrote:
>> Date: Thu, 03 Feb 2011 11:40:42 -0500
>> From: sami wagiaalla<swagiaal@redhat.com>
>> CC: gdb-patches@sourceware.org
>>
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -40,6 +40,14 @@
>>
>>     ** gdb.parameter("directories") is now available.
>>
>> +  ** 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.cont Continue event.
>> +     - gdb.events.exited Inferior exited event.
>> +     - gdb.events.stop Signal received, and Breakpoint hit events.
>> +
>
> OK for this part.
>
>> +* Events In Python::            Listening for events from GDB.
>                                                               ^^^
> "@value{GDBN}" instead of a literal "GDB".
>
>> +GDB provides a general event facility so that Python code can be
>     ^^^
> Ditto.
>
>> +In order to be notified of an event, you must register an event handler
>> +with an event registry.  An @dfn{event registry} is an object in the
>             ^^^^^^^^^^^^^^      ^^^^^^^^^^^^^^^^^^^^
> Please use @dfn when you first use the new term.  In this case, in the
> previous sentence.
>
>> +@defmethod EventRegistry connect callable
>> +Add the given callable object to the registry.  This object will be called
>> +when an event corresponding to this registry occurs.
>
> "callable" should have the @var markup.
>
>> +@defmethod EventRegistry disconnect callable
>> +Remove the given object from the registry.  Once removed the object will no
>                                                            ^^^
> Same here.  And please add the missing comma after "removed".
>
> Also, isn't it better to use "object" as the argument instead of
> "callable"?  How about this:
>
>    @defmethod EventRegistry connect object
>    Add the given callable @var{object} to the registry.  This object will
>    be called when an event corresponding to this registry occurs.
>    @end defmethod
>
>> +registry @code{events.exited}.  Once connected @code{exit_handler} receives
>                                                  ^^
> A missing comma.
>
>> +notifications of exited events.  The argument @dfn{event} in this example is
>
> Hmm... "receives notifications" is not really true, is it?  It gets
> called when exit events happen, right?
>
>> +@item events.cont
>> +Emits @code{gdb.ThreadEvent}
>
> Please add a period at the end of this sentence.
>
>> +Some events can be thread specific when GDB is running in non-stop mode.  When
>                                             ^^^
> "@value{GDBN}"
>
>> +represented in python these events all extend @code{gdb.ThreadEvent}.  Note,
>                    ^^^^^^
> Should be "Python", right?  And please add a comma after it.
>
>> +Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}
>
> A period at the end, please.
>
>> +Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}
>
> Likewise.
>
>> +Indicates that the inferior has stopped. All events emitted by this registry
>> +extend StopEvent. As a child of @code{gdb.ThreadEvent} @code{gdb.StopEvent}
>> +will indicate the stopped thread when gdb is running in non-stop mode. Refer
>> +to @code{gdb.ThreadEvent} above for more details.
>
> This paragraph needs two spaces after each sentence, not one.
>
> Also, a comma is missing here:
>
>> +extend StopEvent. As a child of @code{gdb.ThreadEvent} @code{gdb.StopEvent}
>                                                          ^^^
> And you need to use "@value{GDBN}" again here:
>
>> +will indicate the stopped thread when gdb is running in non-stop mode. Refer
>                                           ^^^
>
>> +Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}
>
> Period.
>
>> +Also emits  @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}
>
> Period.
>
>> +@end table
>
> This "@end table" is misplaced, it should have been after this:
>
>> +@table @code
>> +@defivar SignalEvent stop_signal
>> +A string representing the signal received by the inferior.  A list of possible
>> +signal values can be obtained by running the command @code{info signals} in
>> +the @value{GDBN} command prompt.
>> +@end defivar
>
> OK with those changes.
>
> Thanks.


[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 64497 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..423965f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,32 @@
+2011-01-21  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-evtregistry.c: New file.
+	* python/py-threadevent.c : New file.
+	* python/py-event.c: New file.
+	* python/py-evts.c: New file.
+	* python/py-continueevent.c: New file.
+	* python/py-bpevent.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..f8e6cbb 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,27 @@ 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-threadevent.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,8 +319,11 @@ 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-threadevent.c \
 	python/py-type.c \
 	python/py-utils.c \
 	python/py-value.c
@@ -1992,6 +2011,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 +2023,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 +2079,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)
@@ -2044,6 +2095,10 @@ py-symtab.o: $(srcdir)/python/py-symtab.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
 	$(POSTCOMPILE)
 
+py-threadevent.o: $(srcdir)/python/py-threadevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-threadevent.c
+	$(POSTCOMPILE)
+
 py-type.o: $(srcdir)/python/py-type.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 559609b..d5bae34 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,14 @@
 
   ** gdb.parameter("directories") is now available.
 
+  ** 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.cont Continue event.
+     - gdb.events.exited Inferior exited event.
+     - gdb.events.stop Signal received, and Breakpoint hit events.
+
 * C++ Improvements:
 
   ** GDB now puts template parameters in scope when debugging in an
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dc9630a..4ac0560 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)
+* Events In Python::            Listening for events from @value{GDBN}.
 * Threads In Python::           Accessing inferior threads from Python.
 * Commands In Python::          Implementing new commands in Python.
 * Parameters In Python::        Adding new @value{GDBN} parameters.
@@ -21792,7 +21793,7 @@ my_library.so:
 
 @node Inferiors In Python
 @subsubsection Inferiors In Python
-@cindex inferiors in python
+@cindex inferiors in Python
 
 @findex gdb.Inferior
 Programs which are being run under @value{GDBN} are called inferiors
@@ -21863,6 +21864,123 @@ the pattern could not be found.
 @end defmethod
 @end table
 
+@node Events In Python
+@subsubsection Events In Python
+@cindex inferior events in Python
+
+@value{GDBN} provides a general event facility so that Python code can be
+notified of various state changes, particularly changes that occur in
+the inferior.
+
+An @dfn{event} is just an object that describes some state change.  The
+type of the object and its attributes will vary depending on the details
+of the change.  All the existing events are described below.
+
+In order to be notified of an event, you must register an event handler
+with an @dfn{event registry}.  An event registry is an object in the
+@code{gdb.events} module which dispatches particular events.  A registry
+provides methods to register and unregister event handlers:
+
+@table @code
+@defmethod EventRegistry connect object
+Add the given callable @var{object} to the registry.  This object will be
+called when an event corresponding to this registry occurs.
+@end defmethod
+
+@defmethod EventRegistry disconnect object
+Remove the given @var{object} from the registry.  Once removed, the object
+will no longer receive notifications of events.
+@end defmethod
+@end table
+
+Here is an example:
+
+@smallexample
+def exit_handler (event):
+    print "event type: exit"
+    print "exit code: %d" % (event.exit_code)
+
+gdb.events.exited.connect (exit_handler)
+@end smallexample
+
+In the above example we connect our handler @code{exit_handler} to the
+registry @code{events.exited}.  Once connected, @code{exit_handler} gets
+called when the inferior exits.  The argument @dfn{event} in this example is
+of type @code{gdb.ExitedEvent}.  As you can see in the example the
+@code{ExitedEvent} object has an attribute which indicates the exit code of
+the inferior.
+
+The following is a listing of the event registries that are available and
+details of the events they emit:
+
+@table @code
+
+@item events.cont
+Emits @code{gdb.ThreadEvent}.
+
+Some events can be thread specific when @value{GDBN} is running in non-stop
+mode.  When represented in Python, these events all extend
+@code{gdb.ThreadEvent}.  Note, this event is not emitted directly; instead,
+events which are emitted by this or other modules might extend this event.
+Examples of these events are @code{gdb.BreakpointEvent} and
+@code{gdb.ContinueEvent}.
+
+@table @code
+@defivar ThreadEvent inferior_thread
+In non-stop mode this attribute will be set to the specific thread which was
+involved in the emitted event. Otherwise, it will be set to @code{None}.
+@end defivar
+@end table
+
+Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}.
+
+This event indicates that the inferior has been continued after a stop. For
+inherited attribute refer to @code{gdb.ThreadEvent} above.
+
+@item events.exited
+Emits @code{events.ExitedEvent} which indicates that the inferior has exited.
+@code{events.ExitedEvent} has one attribute:
+@table @code
+@defivar ExitedEvent exit_code
+An integer representing the exit code which the inferior has returned.
+@end defivar
+@end table
+
+@item events.stop
+Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}.
+
+Indicates that the inferior has stopped.  All events emitted by this registry
+extend StopEvent.  As a child of @code{gdb.ThreadEvent}, @code{gdb.StopEvent}
+will indicate the stopped thread when @value{GDBN} is running in non-stop
+mode.  Refer to @code{gdb.ThreadEvent} above for more details.
+
+Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}.
+
+This event indicates that the inferior or one of its threads has received as
+signal.  @code{gdb.SignalEvent} has the following attributes:
+
+@table @code
+@defivar SignalEvent stop_signal
+A string representing the signal received by the inferior.  A list of possible
+signal values can be obtained by running the command @code{info signals} in
+the @value{GDBN} command prompt.
+@end defivar
+@end table
+
+Also emits  @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}.
+
+@code{gdb.BreakpointEvent} event indicates that a breakpoint has been hit, and
+has the following attributes:
+
+@table @code
+@defivar BreakpointEvent breakpoint
+A reference to the breakpoint that was hit of type @code{gdb.Breakpoint}.
+@xref{Breakpoints In Python}, for details of the @code{gdb.Breakpoint} object.
+@end defivar
+@end table
+
+@end table
+
 @node Threads In Python
 @subsubsection Threads In Python
 @cindex threads in python
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644
index 0000000..c7f7965
--- /dev/null
+++ b/gdb/python/py-bpevent.c
@@ -0,0 +1,52 @@
+/* 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;
+
+/* Create and initialize a BreakpointEvent object.  */
+
+PyObject *
+create_breakpoint_event_object (PyObject *breakpoint)
+{
+  PyObject *breakpoint_event_obj =
+      create_stop_event_object (&breakpoint_event_object_type);
+
+  if (!breakpoint_event_obj)
+    goto fail;
+
+  if (evpy_add_attribute (breakpoint_event_obj,
+                          "breakpoint",
+                          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..1338ba6
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_continue_event_object (void)
+{
+  return create_thread_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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.cont))
+    return 0;
+
+  event = 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",
+                      thread_event_object_type,
+                      static);
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..88f8db6
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,175 @@
+/* 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);
+}
+
+PyObject *
+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 (PyObject*) 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 (PyObject *event, char *name, PyObject *attr)
+{
+  return PyObject_SetAttrString (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 (PyObject *event,
+                 eventregistry_object *registry)
+{
+  PyObject *callback_list_copy = NULL;
+  Py_ssize_t i;
+
+  /* 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 (registry->callbacks);
+  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, 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);
+  return 0;
+
+ fail:
+  gdbpy_print_stack ();
+  Py_XDECREF (callback_list_copy);
+  Py_XDECREF (event);
+  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..bc95521
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,121 @@
+/* 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 (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 */ \
+      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_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST exit_code);
+
+extern int evpy_emit_event (PyObject *event,
+                            eventregistry_object *registry);
+
+extern PyObject *create_event_object (PyTypeObject *py_type);
+extern PyObject *create_thread_event_object (PyTypeObject *py_type);
+
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (PyObject *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..6d4dae5
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,59 @@
+/* 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"
+
+extern PyTypeObject thread_event_object_type;
+
+/* Stores a list of objects to be notified when the event for which this
+   registry tracks occurs.  */
+
+typedef struct
+{
+  PyObject_HEAD
+
+  PyObject *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 *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..e1b4346
--- /dev/null
+++ b/gdb/python/py-evtregistry.c
@@ -0,0 +1,170 @@
+/* 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 = (((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;
+    }
+
+  if (PyList_Append (callback_list, func) < 0)
+    return NULL;
+
+  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 = (((eventregistry_object *) self)->callbacks);
+
+  if (!PyArg_ParseTuple (function, "O", &func))
+    return NULL;
+
+  index = PySequence_Index (callback_list, func);
+  if (index < 0)
+    Py_RETURN_NONE;
+
+  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 = 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 (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..446b934
--- /dev/null
+++ b/gdb/python/py-evts.c
@@ -0,0 +1,71 @@
+/* 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.cont, "cont") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.exited, "exited") < 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..457a4fe
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,71 @@
+/* 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;
+
+PyObject *
+create_exited_event_object (LONGEST exit_code)
+{
+  PyObject *exited_event;
+
+  exited_event = create_event_object (&exited_event_object_type);
+
+  if (!exited_event)
+    goto fail;
+
+  if (evpy_add_attribute (exited_event,
+                          "exit_code",
+                          PyLong_FromLongLong (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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.exited))
+    return 0;
+
+  event = 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..ef05dca 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,59 @@ 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 exit_code = -1;
+  ptid_t ptidp;
+  struct target_waitstatus status;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  get_last_target_status (&ptidp, &status);
+
+  exit_code = status.value.integer;
+
+  if (exit_code >= 0
+      && 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 +164,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 +646,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..3d7ce32
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_signal_event_object (enum target_signal stop_signal)
+{
+  const char *signal_name;
+  PyObject *signal_event_obj =
+      create_stop_event_object (&signal_event_object_type);
+
+  if (!signal_event_obj)
+    goto fail;
+
+  signal_name = target_signal_to_name (stop_signal);
+
+  if (evpy_add_attribute (signal_event_obj,
+                          "stop_signal",
+                          PyString_FromString (signal_name)) < 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..514dfb3
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,95 @@
+/* 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"
+
+PyObject *
+create_stop_event_object (PyTypeObject *py_type)
+{
+  PyObject *stop_event_obj = create_thread_event_object (py_type);
+
+  if (!stop_event_obj)
+    goto fail;
+
+  return stop_event_obj;
+
+  fail:
+   Py_XDECREF (stop_event_obj);
+   return NULL;
+}
+
+/* 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)
+{
+  PyObject *stop_event_obj = NULL; /* Appease GCC warning.  */
+
+  if (evregpy_no_listeners_p (gdb_py_events.stop))
+    return 0;
+
+  if (bs && bs->breakpoint_at
+      && bs->breakpoint_at->type == bp_breakpoint)
+    {
+      PyObject *breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+      if (breakpoint != NULL)
+	{
+	  stop_event_obj =
+	      create_breakpoint_event_object (breakpoint);
+	  if (!stop_event_obj)
+	    goto fail;
+	}
+    }
+
+  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
+  if (stop_signal != TARGET_SIGNAL_0
+      && stop_signal != TARGET_SIGNAL_TRAP)
+    {
+      stop_event_obj =
+	  create_signal_event_object (stop_signal);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* If all fails emit an unknown stop event.  All event types should
+     be known and this should eventually be unused.  */
+  if (!stop_event_obj)
+    {
+      stop_event_obj = create_stop_event_object (&stop_event_object_type);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  return evpy_emit_event (stop_event_obj, gdb_py_events.stop);
+
+  fail:
+   return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (stop,
+                      "gdb.StopEvent",
+                      "StopEvent",
+                      "GDB stop event object",
+                      thread_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..690cbbd
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,37 @@
+/* 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"
+
+extern PyObject *create_stop_event_object (PyTypeObject *py_type);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+                            enum target_signal stop_signal);
+
+extern PyObject *
+create_breakpoint_event_object (PyObject *breakpoint);
+
+extern PyObject *
+create_signal_event_object (enum target_signal stop_signal);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/py-threadevent.c b/gdb/python/py-threadevent.c
new file mode 100644
index 0000000..1123706
--- /dev/null
+++ b/gdb/python/py-threadevent.c
@@ -0,0 +1,71 @@
+/* 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"
+
+/* thread 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.  */
+
+static PyObject *
+get_event_thread (void)
+{
+  PyObject *thread = NULL;
+
+  if (non_stop)
+    thread = (PyObject *) find_thread_object (inferior_ptid);
+  else
+    thread = Py_None;
+
+  if (!thread)
+    return NULL;
+
+  Py_INCREF (thread);
+
+  return thread;
+}
+
+PyObject *
+create_thread_event_object (PyTypeObject *py_type)
+{
+  PyObject *thread_event_obj = create_event_object (py_type);
+  PyObject *thread = get_event_thread();
+
+  if (!thread_event_obj || !thread)
+    goto fail;
+
+  if (evpy_add_attribute (thread_event_obj,
+                          "inferior_thread",
+                          thread) < 0)
+    goto fail;
+
+  return thread_event_obj;
+
+  fail:
+   Py_XDECREF (thread_event_obj);
+   return NULL;
+
+}
+
+GDBPY_NEW_EVENT_TYPE (thread,
+                      "gdb.ThreadEvent",
+                      "ThreadEvent",
+                      "GDB thread event object",
+                      event_object_type,
+                      /*no qual*/);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..8fcdca2 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,15 @@ 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);
+void gdbpy_initialize_thread_event (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 
diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..46eed8b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1001,6 +1001,16 @@ 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 ();
+  gdbpy_initialize_thread_event ();
+
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = []");
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0417538..f285c8c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-21  Sami Wagiaalla  <swagiaal@redhat.com>
+
+	* gdb.python/py-evthreads.c: New file.
+	* gdb.python/py-evthreads.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..9f05b9f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,64 @@
+# 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"
+    if ( event.inferior_thread is not None) :
+        print "thread num: %s" % (event.inferior_thread.num);
+
+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.stop.connect (signal_stop_handler)
+        gdb.events.stop.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..1464ce6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -0,0 +1,55 @@
+/* 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 (thread2_id, NULL);
+  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..6ea7eb4
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -0,0 +1,119 @@
+# 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"
+	}
+}
+
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 1.*" {
+        pass "continue thread 1"
+    }
+    timeout {
+	    fail "continue thread 1 failed"
+	}
+}
+
+gdb_test "thread 2" ".*Switching to thread 2.*"
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 2.*" {
+        pass "continue thread 2"
+    }
+    timeout {
+	    fail "continue thread 2 failed"
+	}
+}
+
+send_gdb "continue -a\n"
+gdb_expect {
+    -re ".*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*" {
+        pass "thread 3 was signalled"
+    }
+    timeout {
+	    fail "thread 3 was not signalled"
+	}
+}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-03 16:41               ` sami wagiaalla
  2011-02-03 18:26                 ` Eli Zaretskii
@ 2011-02-03 21:42                 ` Tom Tromey
  2011-02-04 20:07                   ` sami wagiaalla
  1 sibling, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-02-03 21:42 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> Added. I also, documented StopEvent. In events which inherit from
Sami> others I added a statement asking the reader to refer to the
Sami> parent. Do you think that is enough, or should the inherited
Sami> attributes be restated ?

I think it is sufficient to mention the superclass.

Sami> +int
Sami> +emit_stop_event (struct bpstats *bs, enum target_signal stop_signal)
Sami> +{
Sami> +  PyObject *stop_event_obj = NULL; /* Appease GCC warning.  */
Sami> +
Sami> +  if (evregpy_no_listeners_p (gdb_py_events.stop))
Sami> +    return 0;

Sami> +  if (bs && bs->breakpoint_at
Sami> +      && bs->breakpoint_at->type == bp_breakpoint)

I think this logic is too restrictive.
What if we change what breakpoints are reflected to Python?
That is, I think the check for bp_breakpoint should be removed.
Instead, you could just have it check ->py_bp_object.
But if you are doing that you should either rearrange, or just get rid
of gdbpy_breakpoint_from_bpstats, to either preserve the abstraction or
remove it.

Sami> +      PyObject *breakpoint = gdbpy_breakpoint_from_bpstats (bs);
Sami> +      if (breakpoint != NULL)
Sami> +      stop_event_obj =
Sami> +	  create_breakpoint_event_object (breakpoint);
Sami> +      if (!stop_event_obj)
Sami> +	goto fail;

This could result in a "fail" without an error being set.
But the above change should eliminate that.

Sami> +PyObject *
Sami> +create_thread_event_object (PyTypeObject *py_type)
Sami> +{
Sami> +  PyObject *thread_event_obj = create_event_object (py_type);
Sami> +  PyObject *thread = get_event_thread();

Missing space.

Sami> +
Sami> +  if (!thread_event_obj || !thread)
Sami> +    goto fail;

You have to do error checks after each Python call, you can't batch them.

Either: create_event_object can fail, in which case it is not ok to call
get_event_thread on failure; or, create_event_object can return NULL but
not set a Python exception, in which case you must set one explicitly.

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-03 21:42                 ` Tom Tromey
@ 2011-02-04 20:07                   ` sami wagiaalla
  2011-02-04 20:29                     ` Tom Tromey
  2011-02-09  7:55                     ` [patch] Support inferior events in python Jan Kratochvil
  0 siblings, 2 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-02-04 20:07 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 749 bytes --]


> Sami>  +
> Sami>  +  if (!thread_event_obj || !thread)
> Sami>  +    goto fail;
>
> You have to do error checks after each Python call, you can't batch them.
>

I have split the error checking.

> Either: create_event_object can fail, in which case it is not ok to call
> get_event_thread on failure; or, create_event_object can return NULL but
> not set a Python exception, in which case you must set one explicitly.
>

Did you mean "or, get_event_thread" here ? I assumed so because 
get_event_thread can indeed return NULL without setting an error. I have 
fixed that be adding a call to PyErr_SetString.  create_event_object on 
the other hand fails only due to failures in calls into the Python api. 
Which, presumably, do set errors.

Sami

[-- Attachment #2: oguz-python-events.patch --]
[-- Type: text/x-patch, Size: 64103 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 002f3d2..423965f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,32 @@
+2011-01-21  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-evtregistry.c: New file.
+	* python/py-threadevent.c : New file.
+	* python/py-event.c: New file.
+	* python/py-evts.c: New file.
+	* python/py-continueevent.c: New file.
+	* python/py-bpevent.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..f8e6cbb 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,27 @@ 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-threadevent.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,8 +319,11 @@ 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-threadevent.c \
 	python/py-type.c \
 	python/py-utils.c \
 	python/py-value.c
@@ -1992,6 +2011,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 +2023,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 +2079,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)
@@ -2044,6 +2095,10 @@ py-symtab.o: $(srcdir)/python/py-symtab.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
 	$(POSTCOMPILE)
 
+py-threadevent.o: $(srcdir)/python/py-threadevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-threadevent.c
+	$(POSTCOMPILE)
+
 py-type.o: $(srcdir)/python/py-type.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c
 	$(POSTCOMPILE)
diff --git a/gdb/NEWS b/gdb/NEWS
index 559609b..d5bae34 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,14 @@
 
   ** gdb.parameter("directories") is now available.
 
+  ** 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.cont Continue event.
+     - gdb.events.exited Inferior exited event.
+     - gdb.events.stop Signal received, and Breakpoint hit events.
+
 * C++ Improvements:
 
   ** GDB now puts template parameters in scope when debugging in an
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dc9630a..4ac0560 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)
+* Events In Python::            Listening for events from @value{GDBN}.
 * Threads In Python::           Accessing inferior threads from Python.
 * Commands In Python::          Implementing new commands in Python.
 * Parameters In Python::        Adding new @value{GDBN} parameters.
@@ -21792,7 +21793,7 @@ my_library.so:
 
 @node Inferiors In Python
 @subsubsection Inferiors In Python
-@cindex inferiors in python
+@cindex inferiors in Python
 
 @findex gdb.Inferior
 Programs which are being run under @value{GDBN} are called inferiors
@@ -21863,6 +21864,123 @@ the pattern could not be found.
 @end defmethod
 @end table
 
+@node Events In Python
+@subsubsection Events In Python
+@cindex inferior events in Python
+
+@value{GDBN} provides a general event facility so that Python code can be
+notified of various state changes, particularly changes that occur in
+the inferior.
+
+An @dfn{event} is just an object that describes some state change.  The
+type of the object and its attributes will vary depending on the details
+of the change.  All the existing events are described below.
+
+In order to be notified of an event, you must register an event handler
+with an @dfn{event registry}.  An event registry is an object in the
+@code{gdb.events} module which dispatches particular events.  A registry
+provides methods to register and unregister event handlers:
+
+@table @code
+@defmethod EventRegistry connect object
+Add the given callable @var{object} to the registry.  This object will be
+called when an event corresponding to this registry occurs.
+@end defmethod
+
+@defmethod EventRegistry disconnect object
+Remove the given @var{object} from the registry.  Once removed, the object
+will no longer receive notifications of events.
+@end defmethod
+@end table
+
+Here is an example:
+
+@smallexample
+def exit_handler (event):
+    print "event type: exit"
+    print "exit code: %d" % (event.exit_code)
+
+gdb.events.exited.connect (exit_handler)
+@end smallexample
+
+In the above example we connect our handler @code{exit_handler} to the
+registry @code{events.exited}.  Once connected, @code{exit_handler} gets
+called when the inferior exits.  The argument @dfn{event} in this example is
+of type @code{gdb.ExitedEvent}.  As you can see in the example the
+@code{ExitedEvent} object has an attribute which indicates the exit code of
+the inferior.
+
+The following is a listing of the event registries that are available and
+details of the events they emit:
+
+@table @code
+
+@item events.cont
+Emits @code{gdb.ThreadEvent}.
+
+Some events can be thread specific when @value{GDBN} is running in non-stop
+mode.  When represented in Python, these events all extend
+@code{gdb.ThreadEvent}.  Note, this event is not emitted directly; instead,
+events which are emitted by this or other modules might extend this event.
+Examples of these events are @code{gdb.BreakpointEvent} and
+@code{gdb.ContinueEvent}.
+
+@table @code
+@defivar ThreadEvent inferior_thread
+In non-stop mode this attribute will be set to the specific thread which was
+involved in the emitted event. Otherwise, it will be set to @code{None}.
+@end defivar
+@end table
+
+Emits @code{gdb.ContinueEvent} which extends @code{gdb.ThreadEvent}.
+
+This event indicates that the inferior has been continued after a stop. For
+inherited attribute refer to @code{gdb.ThreadEvent} above.
+
+@item events.exited
+Emits @code{events.ExitedEvent} which indicates that the inferior has exited.
+@code{events.ExitedEvent} has one attribute:
+@table @code
+@defivar ExitedEvent exit_code
+An integer representing the exit code which the inferior has returned.
+@end defivar
+@end table
+
+@item events.stop
+Emits @code{gdb.StopEvent} which extends @code{gdb.ThreadEvent}.
+
+Indicates that the inferior has stopped.  All events emitted by this registry
+extend StopEvent.  As a child of @code{gdb.ThreadEvent}, @code{gdb.StopEvent}
+will indicate the stopped thread when @value{GDBN} is running in non-stop
+mode.  Refer to @code{gdb.ThreadEvent} above for more details.
+
+Emits @code{gdb.SignalEvent} which extends @code{gdb.StopEvent}.
+
+This event indicates that the inferior or one of its threads has received as
+signal.  @code{gdb.SignalEvent} has the following attributes:
+
+@table @code
+@defivar SignalEvent stop_signal
+A string representing the signal received by the inferior.  A list of possible
+signal values can be obtained by running the command @code{info signals} in
+the @value{GDBN} command prompt.
+@end defivar
+@end table
+
+Also emits  @code{gdb.BreakpointEvent} which extends @code{gdb.StopEvent}.
+
+@code{gdb.BreakpointEvent} event indicates that a breakpoint has been hit, and
+has the following attributes:
+
+@table @code
+@defivar BreakpointEvent breakpoint
+A reference to the breakpoint that was hit of type @code{gdb.Breakpoint}.
+@xref{Breakpoints In Python}, for details of the @code{gdb.Breakpoint} object.
+@end defivar
+@end table
+
+@end table
+
 @node Threads In Python
 @subsubsection Threads In Python
 @cindex threads in python
diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
new file mode 100644
index 0000000..c7f7965
--- /dev/null
+++ b/gdb/python/py-bpevent.c
@@ -0,0 +1,52 @@
+/* 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;
+
+/* Create and initialize a BreakpointEvent object.  */
+
+PyObject *
+create_breakpoint_event_object (PyObject *breakpoint)
+{
+  PyObject *breakpoint_event_obj =
+      create_stop_event_object (&breakpoint_event_object_type);
+
+  if (!breakpoint_event_obj)
+    goto fail;
+
+  if (evpy_add_attribute (breakpoint_event_obj,
+                          "breakpoint",
+                          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..b9009d9 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.  */
diff --git a/gdb/python/py-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..1338ba6
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_continue_event_object (void)
+{
+  return create_thread_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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.cont))
+    return 0;
+
+  event = 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",
+                      thread_event_object_type,
+                      static);
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..88f8db6
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,175 @@
+/* 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);
+}
+
+PyObject *
+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 (PyObject*) 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 (PyObject *event, char *name, PyObject *attr)
+{
+  return PyObject_SetAttrString (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 (PyObject *event,
+                 eventregistry_object *registry)
+{
+  PyObject *callback_list_copy = NULL;
+  Py_ssize_t i;
+
+  /* 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 (registry->callbacks);
+  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, 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);
+  return 0;
+
+ fail:
+  gdbpy_print_stack ();
+  Py_XDECREF (callback_list_copy);
+  Py_XDECREF (event);
+  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..bc95521
--- /dev/null
+++ b/gdb/python/py-event.h
@@ -0,0 +1,121 @@
+/* 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 (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 */ \
+      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_continue_event (ptid_t ptid);
+extern int emit_exited_event (LONGEST exit_code);
+
+extern int evpy_emit_event (PyObject *event,
+                            eventregistry_object *registry);
+
+extern PyObject *create_event_object (PyTypeObject *py_type);
+extern PyObject *create_thread_event_object (PyTypeObject *py_type);
+
+extern void evpy_dealloc (PyObject *self);
+extern int evpy_add_attribute (PyObject *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..6d4dae5
--- /dev/null
+++ b/gdb/python/py-events.h
@@ -0,0 +1,59 @@
+/* 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"
+
+extern PyTypeObject thread_event_object_type;
+
+/* Stores a list of objects to be notified when the event for which this
+   registry tracks occurs.  */
+
+typedef struct
+{
+  PyObject_HEAD
+
+  PyObject *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 *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..e1b4346
--- /dev/null
+++ b/gdb/python/py-evtregistry.c
@@ -0,0 +1,170 @@
+/* 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 = (((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;
+    }
+
+  if (PyList_Append (callback_list, func) < 0)
+    return NULL;
+
+  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 = (((eventregistry_object *) self)->callbacks);
+
+  if (!PyArg_ParseTuple (function, "O", &func))
+    return NULL;
+
+  index = PySequence_Index (callback_list, func);
+  if (index < 0)
+    Py_RETURN_NONE;
+
+  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 = 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 (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..446b934
--- /dev/null
+++ b/gdb/python/py-evts.c
@@ -0,0 +1,71 @@
+/* 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.cont, "cont") < 0)
+    goto fail;
+
+  if (add_new_registry (&gdb_py_events.exited, "exited") < 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..457a4fe
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,71 @@
+/* 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;
+
+PyObject *
+create_exited_event_object (LONGEST exit_code)
+{
+  PyObject *exited_event;
+
+  exited_event = create_event_object (&exited_event_object_type);
+
+  if (!exited_event)
+    goto fail;
+
+  if (evpy_add_attribute (exited_event,
+                          "exit_code",
+                          PyLong_FromLongLong (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)
+{
+  PyObject *event;
+
+  if (evregpy_no_listeners_p (gdb_py_events.exited))
+    return 0;
+
+  event = 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..ef05dca 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,59 @@ 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 exit_code = -1;
+  ptid_t ptidp;
+  struct target_waitstatus status;
+
+  cleanup = ensure_python_env (get_current_arch (), current_language);
+
+  get_last_target_status (&ptidp, &status);
+
+  exit_code = status.value.integer;
+
+  if (exit_code >= 0
+      && 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 +164,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 +646,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..3d7ce32
--- /dev/null
+++ b/gdb/python/py-signalevent.c
@@ -0,0 +1,53 @@
+/* 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;
+
+PyObject *
+create_signal_event_object (enum target_signal stop_signal)
+{
+  const char *signal_name;
+  PyObject *signal_event_obj =
+      create_stop_event_object (&signal_event_object_type);
+
+  if (!signal_event_obj)
+    goto fail;
+
+  signal_name = target_signal_to_name (stop_signal);
+
+  if (evpy_add_attribute (signal_event_obj,
+                          "stop_signal",
+                          PyString_FromString (signal_name)) < 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..122fe6b
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,92 @@
+/* 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"
+
+PyObject *
+create_stop_event_object (PyTypeObject *py_type)
+{
+  PyObject *stop_event_obj = create_thread_event_object (py_type);
+
+  if (!stop_event_obj)
+    goto fail;
+
+  return stop_event_obj;
+
+  fail:
+   Py_XDECREF (stop_event_obj);
+   return NULL;
+}
+
+/* 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)
+{
+  PyObject *stop_event_obj = NULL; /* Appease GCC warning.  */
+
+  if (evregpy_no_listeners_p (gdb_py_events.stop))
+    return 0;
+
+  if (bs && bs->breakpoint_at
+      && bs->breakpoint_at->py_bp_object)
+    {
+      stop_event_obj = create_breakpoint_event_object ((PyObject *) bs
+                                                       ->breakpoint_at
+                                                       ->py_bp_object);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
+  if (stop_signal != TARGET_SIGNAL_0
+      && stop_signal != TARGET_SIGNAL_TRAP)
+    {
+      stop_event_obj =
+	  create_signal_event_object (stop_signal);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  /* If all fails emit an unknown stop event.  All event types should
+     be known and this should eventually be unused.  */
+  if (!stop_event_obj)
+    {
+      stop_event_obj = create_stop_event_object (&stop_event_object_type);
+      if (!stop_event_obj)
+	goto fail;
+    }
+
+  return evpy_emit_event (stop_event_obj, gdb_py_events.stop);
+
+  fail:
+   return -1;
+}
+
+GDBPY_NEW_EVENT_TYPE (stop,
+                      "gdb.StopEvent",
+                      "StopEvent",
+                      "GDB stop event object",
+                      thread_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..690cbbd
--- /dev/null
+++ b/gdb/python/py-stopevent.h
@@ -0,0 +1,37 @@
+/* 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"
+
+extern PyObject *create_stop_event_object (PyTypeObject *py_type);
+extern void stop_evpy_dealloc (PyObject *self);
+
+extern int emit_stop_event (struct bpstats *bs,
+                            enum target_signal stop_signal);
+
+extern PyObject *
+create_breakpoint_event_object (PyObject *breakpoint);
+
+extern PyObject *
+create_signal_event_object (enum target_signal stop_signal);
+
+#endif /* GDB_PY_STOPEVENT_H */
diff --git a/gdb/python/py-threadevent.c b/gdb/python/py-threadevent.c
new file mode 100644
index 0000000..7963412
--- /dev/null
+++ b/gdb/python/py-threadevent.c
@@ -0,0 +1,78 @@
+/* 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"
+
+/* thread 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.  */
+
+static PyObject *
+get_event_thread (void)
+{
+  PyObject *thread = NULL;
+
+  if (non_stop)
+    thread = (PyObject *) find_thread_object (inferior_ptid);
+  else
+    thread = Py_None;
+
+  if (!thread)
+    {
+      PyErr_SetString (PyExc_RuntimeError, "Could not find event thread");
+      return NULL;
+    }
+
+  Py_INCREF (thread);
+
+  return thread;
+}
+
+PyObject *
+create_thread_event_object (PyTypeObject *py_type)
+{
+  PyObject *thread = NULL;
+  PyObject *thread_event_obj = NULL;
+
+  thread_event_obj = create_event_object (py_type);
+  if (!thread_event_obj)
+    goto fail;
+
+  thread = get_event_thread ();
+  if (!thread)
+    goto fail;
+
+  if (evpy_add_attribute (thread_event_obj,
+                          "inferior_thread",
+                          thread) < 0)
+    goto fail;
+
+  return thread_event_obj;
+
+  fail:
+   Py_XDECREF (thread_event_obj);
+   return NULL;
+}
+
+GDBPY_NEW_EVENT_TYPE (thread,
+                      "gdb.ThreadEvent",
+                      "ThreadEvent",
+                      "GDB thread event object",
+                      event_object_type,
+                      /*no qual*/);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 30d7533..6b06412 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,7 @@ 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);
 
 struct block *block_object_to_block (PyObject *obj);
 struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -167,6 +176,15 @@ 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);
+void gdbpy_initialize_thread_event (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 
diff --git a/gdb/python/python.c b/gdb/python/python.c
index d009be9..46eed8b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1001,6 +1001,16 @@ 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 ();
+  gdbpy_initialize_thread_event ();
+
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = []");
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0417538..f285c8c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-21  Sami Wagiaalla  <swagiaal@redhat.com>
+
+	* gdb.python/py-evthreads.c: New file.
+	* gdb.python/py-evthreads.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..9f05b9f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-events.py
@@ -0,0 +1,64 @@
+# 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"
+    if ( event.inferior_thread is not None) :
+        print "thread num: %s" % (event.inferior_thread.num);
+
+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.stop.connect (signal_stop_handler)
+        gdb.events.stop.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..1464ce6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -0,0 +1,55 @@
+/* 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 (thread2_id, NULL);
+  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..6ea7eb4
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -0,0 +1,119 @@
+# 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"
+	}
+}
+
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 1.*" {
+        pass "continue thread 1"
+    }
+    timeout {
+	    fail "continue thread 1 failed"
+	}
+}
+
+gdb_test "thread 2" ".*Switching to thread 2.*"
+send_gdb "continue&\n"
+gdb_expect {
+    -re ".*event type: continue.*
+.*thread num: 2.*" {
+        pass "continue thread 2"
+    }
+    timeout {
+	    fail "continue thread 2 failed"
+	}
+}
+
+send_gdb "continue -a\n"
+gdb_expect {
+    -re ".*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*" {
+        pass "thread 3 was signalled"
+    }
+    timeout {
+	    fail "thread 3 was not signalled"
+	}
+}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-04 20:07                   ` sami wagiaalla
@ 2011-02-04 20:29                     ` Tom Tromey
  2011-02-04 20:35                       ` sami wagiaalla
  2011-02-09  7:55                     ` [patch] Support inferior events in python Jan Kratochvil
  1 sibling, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-02-04 20:29 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: gdb-patches

>>>>> "Sami" == sami wagiaalla <swagiaal@redhat.com> writes:

Sami> Did you mean "or, get_event_thread" here ? I assumed so because
Sami> get_event_thread can indeed return NULL without setting an error. I
Sami> have fixed that be adding a call to PyErr_SetString.
Sami> create_event_object on the other hand fails only due to failures in
Sami> calls into the Python api. Which, presumably, do set errors.

I don't remember :)
But, I read this iteration of the patch and what you did is fine.

Sami> +2011-01-21  Sami Wagiaalla  <swagiaal@redhat.com>
Sami> +                Oguz Kayral <oguzkayral@gmail.com>

This is ok.  Thanks for persevering, and congratulations.

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-04 20:29                     ` Tom Tromey
@ 2011-02-04 20:35                       ` sami wagiaalla
  2011-02-04 23:00                         ` Paul Pluzhnikov
  2011-04-20 20:26                         ` Patch for non-stop remote assertion (was: RE: [patch] Support inferior events in python) Marc Khouzam
  0 siblings, 2 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-02-04 20:35 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches


> Sami>  +2011-01-21  Sami Wagiaalla<swagiaal@redhat.com>
> Sami>  +                Oguz Kayral<oguzkayral@gmail.com>
>
> This is ok.  Thanks for persevering, and congratulations.
>
> Tom

Woho! :).. Thank you for all the guidance. Committing soon.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-04 20:35                       ` sami wagiaalla
@ 2011-02-04 23:00                         ` Paul Pluzhnikov
  2011-02-05  5:44                           ` Hui Zhu
  2011-04-20 20:26                         ` Patch for non-stop remote assertion (was: RE: [patch] Support inferior events in python) Marc Khouzam
  1 sibling, 1 reply; 42+ messages in thread
From: Paul Pluzhnikov @ 2011-02-04 23:00 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Tom Tromey, gdb-patches

On Fri, Feb 4, 2011 at 12:35 PM, sami wagiaalla <swagiaal@redhat.com> wrote:

> Woho! :).. Thank you for all the guidance. Committing soon.

Looks like commit was incomplete:

2011-02-04  Sami Wagiaalla  <swagiaal@redhat.com>
                Oguz Kayral <oguzkayral@gmail.com>
...
        * python/py-event.c: New file.


cvs up python/bp-event.c
cvs update: nothing known about python/bp-event.c


make: *** No rule to make target `../../src/gdb/python/py-bpevent.c',
needed by `py-bpevent.o'.  Stop.

Thanks!
-- 
Paul Pluzhnikov

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-04 23:00                         ` Paul Pluzhnikov
@ 2011-02-05  5:44                           ` Hui Zhu
  2011-02-07 15:22                             ` sami wagiaalla
  0 siblings, 1 reply; 42+ messages in thread
From: Hui Zhu @ 2011-02-05  5:44 UTC (permalink / raw)
  To: Paul Pluzhnikov; +Cc: sami wagiaalla, Tom Tromey, gdb-patches

Just check in a patch for it.

Hui

On Sat, Feb 5, 2011 at 07:00, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> On Fri, Feb 4, 2011 at 12:35 PM, sami wagiaalla <swagiaal@redhat.com> wrote:
>
>> Woho! :).. Thank you for all the guidance. Committing soon.
>
> Looks like commit was incomplete:
>
> 2011-02-04  Sami Wagiaalla  <swagiaal@redhat.com>
>                Oguz Kayral <oguzkayral@gmail.com>
> ...
>        * python/py-event.c: New file.
>
>
> cvs up python/bp-event.c
> cvs update: nothing known about python/bp-event.c
>
>
> make: *** No rule to make target `../../src/gdb/python/py-bpevent.c',
> needed by `py-bpevent.o'.  Stop.
>
> Thanks!
> --
> Paul Pluzhnikov
>

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-05  5:44                           ` Hui Zhu
@ 2011-02-07 15:22                             ` sami wagiaalla
  2011-02-07 15:24                               ` Tom Tromey
  0 siblings, 1 reply; 42+ messages in thread
From: sami wagiaalla @ 2011-02-07 15:22 UTC (permalink / raw)
  To: Hui Zhu; +Cc: Paul Pluzhnikov, Tom Tromey, gdb-patches

On 02/05/2011 12:44 AM, Hui Zhu wrote:
> Just check in a patch for it.
>
> Hui

Thanks for the fix Hui.

I apologies for breaking the build, although it is truly inexcusable.

   Sami

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-07 15:22                             ` sami wagiaalla
@ 2011-02-07 15:24                               ` Tom Tromey
  2011-02-07 15:34                                 ` Paul Pluzhnikov
  2011-02-07 15:39                                 ` sami wagiaalla
  0 siblings, 2 replies; 42+ messages in thread
From: Tom Tromey @ 2011-02-07 15:24 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Hui Zhu, Paul Pluzhnikov, gdb-patches

Sami> I apologies for breaking the build, although it is truly inexcusable.

Hey now.  Apologizing is fine, but "inexcusable"?  Forgetting to "cvs
add" is like a rite of passage.  Doing on a Friday is a twofer ;-)

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-07 15:24                               ` Tom Tromey
@ 2011-02-07 15:34                                 ` Paul Pluzhnikov
  2011-02-07 16:01                                   ` sami wagiaalla
  2011-02-07 15:39                                 ` sami wagiaalla
  1 sibling, 1 reply; 42+ messages in thread
From: Paul Pluzhnikov @ 2011-02-07 15:34 UTC (permalink / raw)
  To: Tom Tromey; +Cc: sami wagiaalla, Hui Zhu, gdb-patches

On Mon, Feb 7, 2011 at 7:24 AM, Tom Tromey <tromey@redhat.com> wrote:
> Sami> I apologies for breaking the build, although it is truly inexcusable.
>
> Hey now.  Apologizing is fine, but "inexcusable"?  Forgetting to "cvs
> add" is like a rite of passage.  Doing on a Friday is a twofer ;-)

This is why I always ping my patches on Monday, and commit on Tuesday
morning ;-)



-- 
Paul Pluzhnikov

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-07 15:24                               ` Tom Tromey
  2011-02-07 15:34                                 ` Paul Pluzhnikov
@ 2011-02-07 15:39                                 ` sami wagiaalla
  1 sibling, 0 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-02-07 15:39 UTC (permalink / raw)
  To: gdb-patches


Doing on a Friday is a twofer ;-)
>

I know!.. Never again

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-07 15:34                                 ` Paul Pluzhnikov
@ 2011-02-07 16:01                                   ` sami wagiaalla
  0 siblings, 0 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-02-07 16:01 UTC (permalink / raw)
  To: Paul Pluzhnikov; +Cc: Tom Tromey, Hui Zhu, gdb-patches

On 02/07/2011 10:33 AM, Paul Pluzhnikov wrote:
> On Mon, Feb 7, 2011 at 7:24 AM, Tom Tromey<tromey@redhat.com>  wrote:
>> Sami>  I apologies for breaking the build, although it is truly inexcusable.
>>
>> Hey now.  Apologizing is fine, but "inexcusable"?  Forgetting to "cvs
>> add" is like a rite of passage.  Doing on a Friday is a twofer ;-)
>
> This is why I always ping my patches on Monday, and commit on Tuesday
> morning ;-)
>

:)

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-04 20:07                   ` sami wagiaalla
  2011-02-04 20:29                     ` Tom Tromey
@ 2011-02-09  7:55                     ` Jan Kratochvil
  2011-02-09 16:19                       ` sami wagiaalla
  1 sibling, 1 reply; 42+ messages in thread
From: Jan Kratochvil @ 2011-02-09  7:55 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Tom Tromey, gdb-patches

On Fri, 04 Feb 2011 21:06:37 +0100, sami wagiaalla wrote:
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-evthreads.exp
[...]
> +send_gdb "continue -a\n"
> +gdb_expect {
> +    -re ".*stop reason: signal.*
> +.*stop signal: SIGSEGV.*
> +.*thread num: 3.*" {
> +        pass "thread 3 was signalled"
> +    }
> +    timeout {
> +	    fail "thread 3 was not signalled"
> +	}
> +}

This testcase has very random/racy results.


Regards,
Jan

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-09  7:55                     ` [patch] Support inferior events in python Jan Kratochvil
@ 2011-02-09 16:19                       ` sami wagiaalla
  2011-02-09 16:30                         ` Jan Kratochvil
  0 siblings, 1 reply; 42+ messages in thread
From: sami wagiaalla @ 2011-02-09 16:19 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 696 bytes --]

On 02/09/2011 02:55 AM, Jan Kratochvil wrote:
> On Fri, 04 Feb 2011 21:06:37 +0100, sami wagiaalla wrote:
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.python/py-evthreads.exp
> [...]
>> +send_gdb "continue -a\n"
>> +gdb_expect {
>> +    -re ".*stop reason: signal.*
>> +.*stop signal: SIGSEGV.*
>> +.*thread num: 3.*" {
>> +        pass "thread 3 was signalled"
>> +    }
>> +    timeout {
>> +	    fail "thread 3 was not signalled"
>> +	}
>> +}
>
> This testcase has very random/racy results.
>

Hmm... I thought I fixed that by avoiding checking for the prompt. I 
can't reproduce the problem but maybe moving the thread test into its 
own testcase helps. It makes the setup simpler.

   Sami



[-- Attachment #2: signal_test.patch --]
[-- Type: text/x-patch, Size: 2520 bytes --]

Move signal test into its own file.

2011-02-09  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.python/py-evsignal.exp: New file.

diff --git a/gdb/testsuite/gdb.python/py-evsignal.exp b/gdb/testsuite/gdb.python/py-evsignal.exp
new file mode 100644
index 0000000..4d1478f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evsignal.exp
@@ -0,0 +1,53 @@
+# 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"
+
+send_gdb "run\n"
+gdb_expect {
+    -re ".*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*" {
+        pass "thread 3 was signalled"
+    }
+    timeout {
+	    fail "thread 3 was not signalled"
+	}
+}
diff --git a/gdb/testsuite/gdb.python/py-evthreads.exp b/gdb/testsuite/gdb.python/py-evthreads.exp
index 6ea7eb4..957d345 100644
--- a/gdb/testsuite/gdb.python/py-evthreads.exp
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -106,14 +106,3 @@ gdb_expect {
 	}
 }
 
-send_gdb "continue -a\n"
-gdb_expect {
-    -re ".*stop reason: signal.*
-.*stop signal: SIGSEGV.*
-.*thread num: 3.*" {
-        pass "thread 3 was signalled"
-    }
-    timeout {
-	    fail "thread 3 was not signalled"
-	}
-}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-09 16:19                       ` sami wagiaalla
@ 2011-02-09 16:30                         ` Jan Kratochvil
  2011-02-11 15:28                           ` sami wagiaalla
  0 siblings, 1 reply; 42+ messages in thread
From: Jan Kratochvil @ 2011-02-09 16:30 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Tom Tromey, gdb-patches

On Wed, 09 Feb 2011 17:19:21 +0100, sami wagiaalla wrote:
> Hmm... I thought I fixed that by avoiding checking for the prompt.

I also find that one incorrect but I do not have a FAIL reproducer for it.

> I can't reproduce the problem

Reproducible for me in 90% of runs on Fedora 14 i386 (not x86_64).


Thanks,
Jan


Test Run By jkratoch on Wed Feb  9 17:28:09 2011
Native configuration is i386-unknown-linux-gnu

		=== gdb tests ===

Schedule of variations:
    unix

Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using ./config/unix.exp as tool-and-target-specific interface file.
Running ./gdb.python/py-evsignal.exp ...
Executing on host: gcc ./gdb.python/py-evthreads.c  -w -g  -lpthreads -lm   -o /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/gdb.python/py-evthreads    (timeout = 300)
spawn -ignore SIGHUP gcc ./gdb.python/py-evthreads.c -w -g -lpthreads -lm -o /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/gdb.python/py-evthreads
/usr/bin/ld: cannot find -lpthreads
collect2: ld returned 1 exit status
compiler exited with status 1
output is:
/usr/bin/ld: cannot find -lpthreads
collect2: ld returned 1 exit status

Executing on host: gcc ./gdb.python/py-evthreads.c  -w -g  -lpthread -lm   -o /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/gdb.python/py-evthreads    (timeout = 300)
spawn -ignore SIGHUP gcc ./gdb.python/py-evthreads.c -w -g -lpthread -lm -o /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/gdb.python/py-evthreads
PASS: gdb.python/py-evsignal.exp: successfully compiled posix threads test case
spawn /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../data-directory
GNU gdb (GDB) 7.2.50.20110209-cvs
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir ./gdb.python
Source directories searched: /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/./gdb.python:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/gdb.python/py-evthreads
Reading symbols from /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/gdb.python/py-evthreads...done.
(gdb) python print 'test'
test
(gdb) python execfile ('./gdb.python/py-events.py')
(gdb) Test_Events
Event testers registered.
(gdb) PASS: gdb.python/py-evsignal.exp: Test_Events
set non-stop on
(gdb) PASS: gdb.python/py-evsignal.exp: set non-stop on
set target-async on
(gdb) PASS: gdb.python/py-evsignal.exp: set target-async on
run
Starting program: /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/gdb.python/py-evthreads 
event type: continue
thread num: 1
[Thread debugging using libthread_db enabled]
[New Thread 0xf7feeb70 (LWP 28517)]
event type: continue
thread num: 1
[New Thread 0xf77edb70 (LWP 28518)]
event type: continue
thread num: 1
[Thread 0xf7feeb70 (LWP 28517) exited]
[Thread 0xf77edb70 (LWP 28518) exited]

Program exited with code 014.
event type: exit
exit code: 12
(gdb) FAIL: gdb.python/py-evsignal.exp: thread 3 was not signalled
testcase ./gdb.python/py-evsignal.exp completed in 11 seconds

		=== gdb Summary ===

# of expected passes		4
# of unexpected failures	1
Executing on host: /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../data-directory --version    (timeout = 300)
spawn -ignore SIGHUP /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../../gdb/gdb -nw -nx -data-directory /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../data-directory --version
GNU gdb (GDB) 7.2.50.20110209-cvs
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
/home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../../gdb/gdb version  7.2.50.20110209-cvs -nw -nx -data-directory /home/jkratoch/redhat/gdb-clean-m32/gdb/testsuite/../data-directory 

runtest completed at Wed Feb  9 17:28:21 2011

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-09 16:30                         ` Jan Kratochvil
@ 2011-02-11 15:28                           ` sami wagiaalla
  2011-02-11 15:55                             ` Joel Brobecker
  2011-02-11 15:57                             ` Pedro Alves
  0 siblings, 2 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-02-11 15:28 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 736 bytes --]

On 02/09/2011 11:30 AM, Jan Kratochvil wrote:
> On Wed, 09 Feb 2011 17:19:21 +0100, sami wagiaalla wrote:
>> Hmm... I thought I fixed that by avoiding checking for the prompt.
>
> I also find that one incorrect but I do not have a FAIL reproducer for it.
>

Yeah, the prompt is unreliable when non-stop is on.

>> I can't reproduce the problem
>
> Reproducible for me in 90% of runs on Fedora 14 i386 (not x86_64).
>

I could not reproduce it still, but the problem seems obvious now. The 
bad pointer which was supposed to cause the SIGSEGV was not initialized. 
I also added a breakpoint at the end of main to make sure that main 
waits for the signal to be delivered and not exit. Just in case.

Please try the attached patch.

Sami

[-- Attachment #2: signal_test.patch --]
[-- Type: text/x-patch, Size: 3342 bytes --]

Move signal test into its own file. Initialize bad pointer.

2011-02-11  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.python/py-evsignal.exp: New file.
	* gdb.python/py-evthreads.cc: Initialize bad pointer
	to NULL.

diff --git a/gdb/testsuite/gdb.python/py-evsignal.exp b/gdb/testsuite/gdb.python/py-evsignal.exp
new file mode 100644
index 0000000..6fbe033
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evsignal.exp
@@ -0,0 +1,55 @@
+# 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 [gdb_get_line_number "end of main"]
+
+send_gdb "run\n"
+gdb_expect {
+    -re ".*stop reason: signal.*
+.*stop signal: SIGSEGV.*
+.*thread num: 3.*" {
+        pass "thread 3 was signalled"
+    }
+    timeout {
+	    fail "thread 3 was not signalled"
+	}
+}
diff --git a/gdb/testsuite/gdb.python/py-evthreads.c b/gdb/testsuite/gdb.python/py-evthreads.c
index 1464ce6..55414ed 100644
--- a/gdb/testsuite/gdb.python/py-evthreads.c
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -28,7 +28,7 @@ void* thread3 (void* d)
   int count3 = 0;
   count3++;
 
-  int *bad;
+  int *bad = NULL;
   *bad = 1;
 
   return NULL;
@@ -46,10 +46,10 @@ int main (){
   pthread_create (&thread2_id, NULL, thread2, NULL);
   pthread_create (&thread3_id, NULL, thread3, NULL);
 
-  int count1 = 0; // stop1
+  int count1 = 0;
   count1++;
 
   pthread_join (thread2_id, NULL);
   pthread_join (thread3_id, NULL);
-  return 12;
+  return 12; // end of main
 }
diff --git a/gdb/testsuite/gdb.python/py-evthreads.exp b/gdb/testsuite/gdb.python/py-evthreads.exp
index 6ea7eb4..957d345 100644
--- a/gdb/testsuite/gdb.python/py-evthreads.exp
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -106,14 +106,3 @@ gdb_expect {
 	}
 }
 
-send_gdb "continue -a\n"
-gdb_expect {
-    -re ".*stop reason: signal.*
-.*stop signal: SIGSEGV.*
-.*thread num: 3.*" {
-        pass "thread 3 was signalled"
-    }
-    timeout {
-	    fail "thread 3 was not signalled"
-	}
-}

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-11 15:28                           ` sami wagiaalla
@ 2011-02-11 15:55                             ` Joel Brobecker
  2011-02-11 19:19                               ` sami wagiaalla
  2011-02-11 15:57                             ` Pedro Alves
  1 sibling, 1 reply; 42+ messages in thread
From: Joel Brobecker @ 2011-02-11 15:55 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Jan Kratochvil, Tom Tromey, gdb-patches

> +send_gdb "run\n"
> +gdb_expect {
> +    -re ".*stop reason: signal.*
> +.*stop signal: SIGSEGV.*
> +.*thread num: 3.*" {
> +        pass "thread 3 was signalled"
> +    }
> +    timeout {
> +	    fail "thread 3 was not signalled"
> +	}

Can you replace send_gdb+gdb_expext by gdb_test_multiple; it even
seems that a simple gdb_test would work, no?

-- 
Joel

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-11 15:28                           ` sami wagiaalla
  2011-02-11 15:55                             ` Joel Brobecker
@ 2011-02-11 15:57                             ` Pedro Alves
  2011-02-14 17:36                               ` sami wagiaalla
  1 sibling, 1 reply; 42+ messages in thread
From: Pedro Alves @ 2011-02-11 15:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: sami wagiaalla, Jan Kratochvil, Tom Tromey

On Friday 11 February 2011 15:28:27, sami wagiaalla wrote:
> +# This file is part of the GDB testsuite.  It tests Python-based
> +# pretty-printing for the CLI.

Is this really about pretty-printing?

> +
> +# 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}

You should check for the return here.  Not all targets
have <pthread.h>.

> +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"

You're not checking if the target actually
supported async/non-stop when first running, which
means the following tests won't work on many targets.
Actually, do you really need non-stop?

> +
> +gdb_breakpoint [gdb_get_line_number "end of main"]
> +
> +send_gdb "run\n"

Do you really need literal "run" here?  This doesn't
work against gdbserver + target remote.

> +gdb_expect {
> +    -re ".*stop reason: signal.*
> +.*stop signal: SIGSEGV.*
> +.*thread num: 3.*" {
> +        pass "thread 3 was signalled"
> +    }
> +    timeout {
> +           fail "thread 3 was not signalled"
> +       }
> +}

I wonder whether if you add an explicit -re for the
prompt, you'll be able to use gdb_test_multiple.
FYI, most tests that do non-stop are written in
MI so that the expected output is easier
to expect.


-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-11 15:55                             ` Joel Brobecker
@ 2011-02-11 19:19                               ` sami wagiaalla
  2011-02-11 19:46                                 ` Jan Kratochvil
  0 siblings, 1 reply; 42+ messages in thread
From: sami wagiaalla @ 2011-02-11 19:19 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Jan Kratochvil, Tom Tromey, gdb-patches

On 02/11/2011 10:54 AM, Joel Brobecker wrote:
>> +send_gdb "run\n"
>> +gdb_expect {
>> +    -re ".*stop reason: signal.*
>> +.*stop signal: SIGSEGV.*
>> +.*thread num: 3.*" {
>> +        pass "thread 3 was signalled"
>> +    }
>> +    timeout {
>> +	    fail "thread 3 was not signalled"
>> +	}
>
> Can you replace send_gdb+gdb_expext by gdb_test_multiple; it even
> seems that a simple gdb_test would work, no?
>

If I understand correctly gdb_test, and gdb_test_multiple test for the 
gdb prompt after the output, but the printing of the prompt is not 
reliable in non-stop mode. that is why I am using plain send and expect.

   Sami

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-11 19:19                               ` sami wagiaalla
@ 2011-02-11 19:46                                 ` Jan Kratochvil
  0 siblings, 0 replies; 42+ messages in thread
From: Jan Kratochvil @ 2011-02-11 19:46 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Joel Brobecker, Tom Tromey, gdb-patches

On Fri, 11 Feb 2011 20:18:53 +0100, sami wagiaalla wrote:
> If I understand correctly gdb_test, and gdb_test_multiple test for
> the gdb prompt after the output,

gdb_test does, gdb_test_multiple does not.  You should use gdb_test_multiple.

Additionally you could catch both the asynchornous info and $gdb_prompt
separately using gdb_test_multiple and exp_continue till you have the both
results, no matter in which order they come.  That way the testcase would not
submit a new command before the previous one has completed.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-11 15:57                             ` Pedro Alves
@ 2011-02-14 17:36                               ` sami wagiaalla
  2011-02-16 11:48                                 ` Jan Kratochvil
  0 siblings, 1 reply; 42+ messages in thread
From: sami wagiaalla @ 2011-02-14 17:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Jan Kratochvil, Tom Tromey

[-- Attachment #1: Type: text/plain, Size: 363 bytes --]

The attached patch incorporates fixes requested by Jan, Joel, and Pedro:

  - Use gdb_test_multiple.
  - Check the return value of gdb_compile_pthreads.
  - Remove incorrect comment about pretty printing.
  - Test that non-stop is supported.
  - Fix test intermittent failure on i386.

Where applicable these fixes were also applied to other related tests.

Sami

[-- Attachment #2: signal_test.patch --]
[-- Type: text/x-patch, Size: 6810 bytes --]

Fix non-stop Python event tests.

2011-02-14  Sami Wagiaalla  <swagiaal@redhat.com>

	* gdb.python/py-evsignal.exp: New file.
	* gdb.python/py-evthreads.cc: Initialize bad pointer
	to NULL.
	* gdb.python/py-events.exp: Remove pretty printing
	comment.
	* gdb.python/py-evthreads.exp: Ditto.
	Use gdb_test_multiple.

diff --git a/gdb/testsuite/gdb.python/py-events.exp b/gdb/testsuite/gdb.python/py-events.exp
index e5d6daf..8493809 100644
--- a/gdb/testsuite/gdb.python/py-events.exp
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -13,11 +13,6 @@
 # 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
 }
diff --git a/gdb/testsuite/gdb.python/py-evsignal.exp b/gdb/testsuite/gdb.python/py-evsignal.exp
new file mode 100644
index 0000000..ae67a12
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evsignal.exp
@@ -0,0 +1,49 @@
+# 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/>.
+
+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
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    return -1
+}
+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 [gdb_get_line_number "end of main"]
+
+gdb_test_multiple "run" "Signal Thread 3"  {
+    -re ".*stop reason: signal.*stop signal: SIGSEGV.*thread num: 3.*" {
+        pass "thread 3 was signaled"
+    }
+    -re "The target does not support running in non-stop mode"  {
+        unsupported "non-stop mode is unsupported"
+    }
+}
diff --git a/gdb/testsuite/gdb.python/py-evthreads.c b/gdb/testsuite/gdb.python/py-evthreads.c
index 1464ce6..55414ed 100644
--- a/gdb/testsuite/gdb.python/py-evthreads.c
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -28,7 +28,7 @@ void* thread3 (void* d)
   int count3 = 0;
   count3++;
 
-  int *bad;
+  int *bad = NULL;
   *bad = 1;
 
   return NULL;
@@ -46,10 +46,10 @@ int main (){
   pthread_create (&thread2_id, NULL, thread2, NULL);
   pthread_create (&thread3_id, NULL, thread3, NULL);
 
-  int count1 = 0; // stop1
+  int count1 = 0;
   count1++;
 
   pthread_join (thread2_id, NULL);
   pthread_join (thread3_id, NULL);
-  return 12;
+  return 12; // end of main
 }
diff --git a/gdb/testsuite/gdb.python/py-evthreads.exp b/gdb/testsuite/gdb.python/py-evthreads.exp
index 6ea7eb4..aadacd0 100644
--- a/gdb/testsuite/gdb.python/py-evthreads.exp
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -13,11 +13,6 @@
 # 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
 }
@@ -29,7 +24,9 @@ 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}
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    return -1
+}
 clean_restart $testfile
 
 if { [skip_python_tests] } { continue }
@@ -44,76 +41,38 @@ 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.*" {
+gdb_test_multiple "run" "Run to breakpoint 1" {
+    -re "event type: stop.*stop reason: breakpoint.*breakpoint number: 1.*thread num: 1.*" {
         pass "reached breakpoint 1"
     }
-    timeout {
-	    fail "did not reach breakpoint 1"
-	}
+    -re "The target does not support running in non-stop mode"  {
+        unsupported "non-stop mode is unsupported"
+        return
+    }
 }
 
-send_gdb "next\n"
-gdb_expect {
-    -re "event type: stop.*
-.*stop reason: breakpoint.*
-.*breakpoint number: 2.*
-.*thread num: 2.*" {
+gdb_test_multiple "next" "Run to breakpoint 2" {
+    -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.*" {
+gdb_test_multiple "next" "Run to breakpoint 3" {
+    -re "event type: stop.*stop reason: breakpoint.*breakpoint number: 3.*thread num: 3.*" {
         pass "reached breakpoint 3"
     }
-    timeout {
-	    fail "did not reach breakpoint 3"
-	}
 }
 
-send_gdb "continue&\n"
-gdb_expect {
-    -re ".*event type: continue.*
-.*thread num: 1.*" {
+gdb_test_multiple "continue&" "Continue thread 1" {
+    -re ".*event type: continue.*thread num: 1.*" {
         pass "continue thread 1"
     }
-    timeout {
-	    fail "continue thread 1 failed"
-	}
 }
 
 gdb_test "thread 2" ".*Switching to thread 2.*"
-send_gdb "continue&\n"
-gdb_expect {
-    -re ".*event type: continue.*
-.*thread num: 2.*" {
-        pass "continue thread 2"
-    }
-    timeout {
-	    fail "continue thread 2 failed"
-	}
-}
 
-send_gdb "continue -a\n"
-gdb_expect {
-    -re ".*stop reason: signal.*
-.*stop signal: SIGSEGV.*
-.*thread num: 3.*" {
-        pass "thread 3 was signalled"
+gdb_test_multiple "continue&" "Continue thread 2" {
+    -re ".*event type: continue.*thread num: 2.*" {
+        pass "continue thread 1"
     }
-    timeout {
-	    fail "thread 3 was not signalled"
-	}
 }

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-14 17:36                               ` sami wagiaalla
@ 2011-02-16 11:48                                 ` Jan Kratochvil
  2011-07-06 19:42                                   ` Jan Kratochvil
  0 siblings, 1 reply; 42+ messages in thread
From: Jan Kratochvil @ 2011-02-16 11:48 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Pedro Alves, gdb-patches, Tom Tromey

On Mon, 14 Feb 2011 18:28:13 +0100, sami wagiaalla wrote:
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-evsignal.exp
> @@ -0,0 +1,49 @@
> +# 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/>.
> +
> +if $tracelevel then {
> +    strace $tracelevel
> +}
> +
> +load_lib gdb-python.exp
> +
> +set testfile "py-evthreads"
> +set srcfile ${testfile}.c
> +set binfile ${objdir}/${subdir}/${testfile}

While $srcfile is OK please use "py-evsignal" as the $binfile.


> +set pyfile ${srcdir}/${subdir}/py-events.py
> +
> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
> +    return -1
> +}
> +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 [gdb_get_line_number "end of main"]
> +
> +gdb_test_multiple "run" "Signal Thread 3"  {

This will ignore gdbserver if you run it with:
	http://sourceware.org/gdb/wiki/TestingGDB#Testing_gdbserver_in_a_native_configuration

Although with runto_main and gdb_test_multiple "continue" the python support
will FAIL:
	RuntimeError: Could not find event thread


> +    -re ".*stop reason: signal.*stop signal: SIGSEGV.*thread num: 3.*" {
> +        pass "thread 3 was signaled"
> +    }
> +    -re "The target does not support running in non-stop mode"  {
> +        unsupported "non-stop mode is unsupported"
> +    }
> +}

I believe here could be `\r\n$gdb_prompt $' at the end as "run" (nor
"continue") are executed with trailing `&'.  But that is not a real problem.


> diff --git a/gdb/testsuite/gdb.python/py-evthreads.c b/gdb/testsuite/gdb.python/py-evthreads.c
> index 1464ce6..55414ed 100644
> --- a/gdb/testsuite/gdb.python/py-evthreads.c
> +++ b/gdb/testsuite/gdb.python/py-evthreads.c
> @@ -28,7 +28,7 @@ void* thread3 (void* d)
>    int count3 = 0;
>    count3++;
>  
> -  int *bad;
> +  int *bad = NULL;
>    *bad = 1;

This is needlessly fragile - for example on targets where NULL is writable.
What about some:
	raise (SIGUSR1);


> @@ -44,76 +41,38 @@ 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.*" {
> +gdb_test_multiple "run" "Run to breakpoint 1" {

Again gdbserver incompatible.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Patch for non-stop remote assertion  (was: RE: [patch] Support inferior events in python)
  2011-02-04 20:35                       ` sami wagiaalla
  2011-02-04 23:00                         ` Paul Pluzhnikov
@ 2011-04-20 20:26                         ` Marc Khouzam
  2011-04-25 18:12                           ` Patch for non-stop remote assertion Tom Tromey
  1 sibling, 1 reply; 42+ messages in thread
From: Marc Khouzam @ 2011-04-20 20:26 UTC (permalink / raw)
  To: 'sami wagiaalla', 'Tom Tromey',
	'gdb-patches@sourceware.org'

> -----Original Message-----
> From: sami wagiaalla [mailto:swagiaal@redhat.com] 
> Sent: Friday, February 04, 2011 3:35 PM
> To: Tom Tromey
> Cc: gdb-patches@sourceware.org
> Subject: Re: [patch] Support inferior events in python
> 
> 
> > Sami>  +2011-01-21  Sami Wagiaalla<swagiaal@redhat.com>
> > Sami>  +                Oguz Kayral<oguzkayral@gmail.com>
> >
> > This is ok.  Thanks for persevering, and congratulations.
> >
> > Tom
> 
> Woho! :).. Thank you for all the guidance. Committing soon.

Hi,

I think I'm having trouble with this patch.
With non-stop and extended-remote, I can no longer
attach to a process.  I get an assertion in the python
part.

What I think is happening is the following.
In remote_notice_new_inferior() line 1527 of remote.c, 
we find out for the first time about a thread on the remote.
The call to remote_add_thread() will add this thread
but will also trigger the notifications about a running
thread.  Still within remote_notice_new_inferior(), the
very next line, inferior_ptid is updated to match the 
new thread.  It seems to be too late though.  When
the python code receives the notification of a thread
resume, it uses the old inferior_ptid to find the arch
and the assertion is triggered because inferior_ptid does
not have the tid yet.

One fix that seems to work is to update the inferior_ptid
before calling remote_add_thread().  But I have no idea
if this is safe or not (it does not cause any regressions).
I posted the patch at the end of this mail.

The stack trace of the assertion and and very simple
example session below.

#0  0xb786e422 in __kernel_vsyscall ()
#1  0xb7417651 in raise () from /lib/tls/i686/cmov/libc.so.6
#2  0xb741aa82 in abort () from /lib/tls/i686/cmov/libc.so.6
#3  0x0809d915 in dump_core () at ../../src/gdb/utils.c:1053
#4  0x0809dbd5 in internal_vproblem (problem=0x847da54, file=0x83bf29a "../../src/gdb/thread.c", line=620, 
    fmt=0x83bf27c "%s: Assertion `%s' failed.", ap=0xbfaffc2c "\001\373;\b\227\362;\b") at ../../src/gdb/utils.c:1211
#5  0x0809dc31 in internal_verror (file=0x83bf29a "../../src/gdb/thread.c", line=620, fmt=0x83bf27c "%s: Assertion `%s' failed.", 
    ap=0xbfaffc2c "\001\373;\b\227\362;\b") at ../../src/gdb/utils.c:1236
#6  0x0809dc69 in internal_error (file=0x83bf29a "../../src/gdb/thread.c", line=620, string=0x83bf27c "%s: Assertion `%s' failed.")
    at ../../src/gdb/utils.c:1246
#7  0x081b79b6 in is_thread_state (ptid=..., state=THREAD_EXITED) at ../../src/gdb/thread.c:620
#8  0x081b7a17 in is_exited (ptid=...) at ../../src/gdb/thread.c:633
#9  0x080a5143 in has_stack_frames () at ../../src/gdb/frame.c:1336
#10 0x081ce2f4 in get_current_arch () at ../../src/gdb/arch-utils.c:757
#11 0x08132b48 in python_on_resume (ptid=...) at ../../src/gdb/python/py-inferior.c:103
#12 0x0809780b in observer_target_resumed_notification_stub (data=0x8132b36, args_data=0xbfaffd74) at ./observer.inc:423
#13 0x080970a0 in generic_observer_notify (subject=0x948f4e0, args=0xbfaffd74) at ../../src/gdb/observer.c:168
#14 0x08097895 in observer_notify_target_resumed (ptid=...) at ./observer.inc:448
#15 0x081b7951 in set_running (ptid=..., running=1) at ../../src/gdb/thread.c:610
#16 0x080e80ad in remote_add_thread (ptid=..., running=1) at ../../src/gdb/remote.c:1487
#17 0x080e8232 in remote_notice_new_inferior (currthread=..., running=1) at ../../src/gdb/remote.c:1527
#18 0x080ea041 in remote_threads_info (ops=0x848a7e0) at ../../src/gdb/remote.c:2668
#19 0x080ecb10 in extended_remote_attach_1 (target=0x848a7e0, args=0x944cdff "13303", from_tty=0) at ../../src/gdb/remote.c:4243
#20 0x080ecd7a in extended_remote_attach (ops=0x848a7e0, args=0x944cdff "13303", from_tty=0) at ../../src/gdb/remote.c:4299
#21 0x081e02d0 in target_attach (args=0x944cdff "13303", from_tty=0) at ../../src/gdb/target.c:3256
#22 0x081a3ea1 in attach_command (args=0x944cdff "13303", from_tty=0) at ../../src/gdb/infcmd.c:2475

Session to reproduce:

> gdb.7.4 
GNU gdb (GDB) 7.3.50.20110417-cvs
(gdb) set target-async on
(gdb) set pagination off
(gdb) set non-stop on
(gdb) target extended-remote :9999
Remote debugging using :9999
(gdb) attach 10283
Attached to process 10283
[New Thread 10283.10283]
../../src/gdb/thread.c:620: internal-error: is_thread_state: Assertion `tp' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.

Potential fix that causes no regressions.

What do you think?

The problem is in HEAD and 7_3 so a fix should go into both.

2011-04-19  Marc Khouzam  <marc.khouzam@ericsson.com>

	* remote.c (remote_notice_new_inferior): Update the 
	inferior_ptid before calling remote_add_thread.

### Eclipse Workspace Patch 1.0
#P src
Index: gdb/remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.443
diff -u -r1.443 remote.c
--- gdb/remote.c        20 Apr 2011 17:54:08 -0000      1.443
+++ gdb/remote.c        20 Apr 2011 20:15:19 -0000
@@ -1524,8 +1524,11 @@
            thread_change_ptid (inferior_ptid, currthread);
          else
            {
-             remote_add_thread (currthread, running);
+                 /* First update the inferior_ptid as it could
+                    be used within the call to remote_add_thread
+                    which triggers observer notifications */
              inferior_ptid = currthread;
+             remote_add_thread (currthread, running);
            }
          return;
        }

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: Patch for non-stop remote assertion
  2011-04-20 20:26                         ` Patch for non-stop remote assertion (was: RE: [patch] Support inferior events in python) Marc Khouzam
@ 2011-04-25 18:12                           ` Tom Tromey
  2011-04-25 18:31                             ` Marc Khouzam
  0 siblings, 1 reply; 42+ messages in thread
From: Tom Tromey @ 2011-04-25 18:12 UTC (permalink / raw)
  To: Marc Khouzam
  Cc: 'sami wagiaalla', 'gdb-patches@sourceware.org'

>>>>> "Marc" == Marc Khouzam <marc.khouzam@ericsson.com> writes:

Marc> #7  0x081b79b6 in is_thread_state (ptid=..., state=THREAD_EXITED) at ../../src/gdb/thread.c:620
Marc> #8  0x081b7a17 in is_exited (ptid=...) at ../../src/gdb/thread.c:633
Marc> #9  0x080a5143 in has_stack_frames () at ../../src/gdb/frame.c:1336
Marc> #10 0x081ce2f4 in get_current_arch () at ../../src/gdb/arch-utils.c:757
Marc> #11 0x08132b48 in python_on_resume (ptid=...) at ../../src/gdb/python/py-inferior.c:103

I think the last time this came up, we established that it is not ok to
call get_current_arch at this point.

Basically, this is a botch in the Python API -- we designed it
improperly :(

Maybe this code (and a few associated functions) could use
target_gdbarch for the time being.  That is safer and probably will not
lead to reduced functionality.

Could you try the appended?

Tom

diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index b9df394..45f5f04 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -100,7 +100,7 @@ python_on_resume (ptid_t ptid)
 {
   struct cleanup *cleanup;
 
-  cleanup = ensure_python_env (get_current_arch (), current_language);
+  cleanup = ensure_python_env (target_gdbarch, current_language);
 
   if (emit_continue_event (ptid) < 0)
     gdbpy_print_stack ();
@@ -116,7 +116,7 @@ python_inferior_exit (struct inferior *inf)
   ptid_t ptidp;
   struct target_waitstatus status;
 
-  cleanup = ensure_python_env (get_current_arch (), current_language);
+  cleanup = ensure_python_env (target_gdbarch, current_language);
 
   get_last_target_status (&ptidp, &status);
 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: Patch for non-stop remote assertion
  2011-04-25 18:12                           ` Patch for non-stop remote assertion Tom Tromey
@ 2011-04-25 18:31                             ` Marc Khouzam
  2011-05-16 15:41                               ` Marc Khouzam
  2011-05-19 18:38                               ` Tom Tromey
  0 siblings, 2 replies; 42+ messages in thread
From: Marc Khouzam @ 2011-04-25 18:31 UTC (permalink / raw)
  To: 'Tom Tromey'
  Cc: 'sami wagiaalla', 'gdb-patches@sourceware.org'

> -----Original Message-----
> From: Tom Tromey [mailto:tromey@redhat.com] 
> Sent: Monday, April 25, 2011 2:12 PM
> To: Marc Khouzam
> Cc: 'sami wagiaalla'; 'gdb-patches@sourceware.org'
> Subject: Re: Patch for non-stop remote assertion
> 
> >>>>> "Marc" == Marc Khouzam <marc.khouzam@ericsson.com> writes:
> 
> Marc> #7  0x081b79b6 in is_thread_state (ptid=..., 
> state=THREAD_EXITED) at ../../src/gdb/thread.c:620
> Marc> #8  0x081b7a17 in is_exited (ptid=...) at 
> ../../src/gdb/thread.c:633
> Marc> #9  0x080a5143 in has_stack_frames () at 
> ../../src/gdb/frame.c:1336
> Marc> #10 0x081ce2f4 in get_current_arch () at 
> ../../src/gdb/arch-utils.c:757
> Marc> #11 0x08132b48 in python_on_resume (ptid=...) at 
> ../../src/gdb/python/py-inferior.c:103
> 
> I think the last time this came up, we established that it is 
> not ok to
> call get_current_arch at this point.
> 
> Basically, this is a botch in the Python API -- we designed it
> improperly :(
> 
> Maybe this code (and a few associated functions) could use
> target_gdbarch for the time being.  That is safer and 
> probably will not
> lead to reduced functionality.
> 
> Could you try the appended?

Thanks!  That works.  No more assertion and I can do
extended-remote debugging.

I noticed a third use of get_current_arch () in that file,
within method python_on_normal_stop ().  Should that one be
changed also?

How do you want to move forward with this?

Thanks again

Marc

> 
> Tom
> 
> diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
> index b9df394..45f5f04 100644
> --- a/gdb/python/py-inferior.c
> +++ b/gdb/python/py-inferior.c
> @@ -100,7 +100,7 @@ python_on_resume (ptid_t ptid)
>  {
>    struct cleanup *cleanup;
>  
> -  cleanup = ensure_python_env (get_current_arch (), 
> current_language);
> +  cleanup = ensure_python_env (target_gdbarch, current_language);
>  
>    if (emit_continue_event (ptid) < 0)
>      gdbpy_print_stack ();
> @@ -116,7 +116,7 @@ python_inferior_exit (struct inferior *inf)
>    ptid_t ptidp;
>    struct target_waitstatus status;
>  
> -  cleanup = ensure_python_env (get_current_arch (), 
> current_language);
> +  cleanup = ensure_python_env (target_gdbarch, current_language);
>  
>    get_last_target_status (&ptidp, &status);
>  
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* RE: Patch for non-stop remote assertion
  2011-04-25 18:31                             ` Marc Khouzam
@ 2011-05-16 15:41                               ` Marc Khouzam
  2011-05-19 18:38                               ` Tom Tromey
  1 sibling, 0 replies; 42+ messages in thread
From: Marc Khouzam @ 2011-05-16 15:41 UTC (permalink / raw)
  To: 'Tom Tromey'
  Cc: 'sami wagiaalla', 'gdb-patches@sourceware.org'

 

> -----Original Message-----
> From: gdb-patches-owner@sourceware.org 
> [mailto:gdb-patches-owner@sourceware.org] On Behalf Of Marc Khouzam
> Sent: Monday, April 25, 2011 2:31 PM
> To: 'Tom Tromey'
> Cc: 'sami wagiaalla'; 'gdb-patches@sourceware.org'
> Subject: RE: Patch for non-stop remote assertion
> 
> > -----Original Message-----
> > From: Tom Tromey [mailto:tromey@redhat.com] 
> > Sent: Monday, April 25, 2011 2:12 PM
> > To: Marc Khouzam
> > Cc: 'sami wagiaalla'; 'gdb-patches@sourceware.org'
> > Subject: Re: Patch for non-stop remote assertion
> > 
> > >>>>> "Marc" == Marc Khouzam <marc.khouzam@ericsson.com> writes:
> > 
> > Marc> #7  0x081b79b6 in is_thread_state (ptid=..., 
> > state=THREAD_EXITED) at ../../src/gdb/thread.c:620
> > Marc> #8  0x081b7a17 in is_exited (ptid=...) at 
> > ../../src/gdb/thread.c:633
> > Marc> #9  0x080a5143 in has_stack_frames () at 
> > ../../src/gdb/frame.c:1336
> > Marc> #10 0x081ce2f4 in get_current_arch () at 
> > ../../src/gdb/arch-utils.c:757
> > Marc> #11 0x08132b48 in python_on_resume (ptid=...) at 
> > ../../src/gdb/python/py-inferior.c:103
> > 
> > I think the last time this came up, we established that it is 
> > not ok to
> > call get_current_arch at this point.
> > 
> > Basically, this is a botch in the Python API -- we designed it
> > improperly :(
> > 
> > Maybe this code (and a few associated functions) could use
> > target_gdbarch for the time being.  That is safer and 
> > probably will not
> > lead to reduced functionality.
> > 
> > Could you try the appended?
> 
> Thanks!  That works.  No more assertion and I can do
> extended-remote debugging.
> 
> I noticed a third use of get_current_arch () in that file,
> within method python_on_normal_stop ().  Should that one be
> changed also?
> 
> How do you want to move forward with this?

Since the proposed was yours, I didn't think it was my place
to post it, but if it will save you time, I can take it from
here, repost the patch, and upon approval, commit to 7.3 and HEAD.

What do you say?

Thanks

Marc

> 
> Thanks again
> 
> Marc
> 
> > 
> > Tom
> > 
> > diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
> > index b9df394..45f5f04 100644
> > --- a/gdb/python/py-inferior.c
> > +++ b/gdb/python/py-inferior.c
> > @@ -100,7 +100,7 @@ python_on_resume (ptid_t ptid)
> >  {
> >    struct cleanup *cleanup;
> >  
> > -  cleanup = ensure_python_env (get_current_arch (), 
> > current_language);
> > +  cleanup = ensure_python_env (target_gdbarch, current_language);
> >  
> >    if (emit_continue_event (ptid) < 0)
> >      gdbpy_print_stack ();
> > @@ -116,7 +116,7 @@ python_inferior_exit (struct inferior *inf)
> >    ptid_t ptidp;
> >    struct target_waitstatus status;
> >  
> > -  cleanup = ensure_python_env (get_current_arch (), 
> > current_language);
> > +  cleanup = ensure_python_env (target_gdbarch, current_language);
> >  
> >    get_last_target_status (&ptidp, &status);
> >  
> > 
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: Patch for non-stop remote assertion
  2011-04-25 18:31                             ` Marc Khouzam
  2011-05-16 15:41                               ` Marc Khouzam
@ 2011-05-19 18:38                               ` Tom Tromey
  1 sibling, 0 replies; 42+ messages in thread
From: Tom Tromey @ 2011-05-19 18:38 UTC (permalink / raw)
  To: Marc Khouzam
  Cc: 'sami wagiaalla', 'gdb-patches@sourceware.org'

>>>>> "Marc" == Marc Khouzam <marc.khouzam@ericsson.com> writes:

Sorry about the long delay on this.

Marc> I noticed a third use of get_current_arch () in that file,
Marc> within method python_on_normal_stop ().  Should that one be
Marc> changed also?

I think that one is ok.

Marc> How do you want to move forward with this?

I am going to check it in now.

Tom

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-02-16 11:48                                 ` Jan Kratochvil
@ 2011-07-06 19:42                                   ` Jan Kratochvil
  2011-07-07 13:51                                     ` sami wagiaalla
  0 siblings, 1 reply; 42+ messages in thread
From: Jan Kratochvil @ 2011-07-06 19:42 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Pedro Alves, gdb-patches, Tom Tromey

Hi Sami,

the testcase had some problems where multiple asynchronous events could happen
at the same time.  This is difficult to parse without any new framework in the
.exp code.

As Pedro asked
http://sourceware.org/ml/gdb-patches/2011-02/msg00213.html
> Actually, do you really need non-stop?

I also do not think the testcases should / need to test the non-stop mode.
But currently it cannot test thread id in all-stop/sync mode, therefore I have
filed it as PR and kept the testcases in non-stop/async mode:
	http://sourceware.org/bugzilla/show_bug.cgi?id=12967

Due to the difficulty of parsing events which can happen at the same time in
various order I have changed also the .c file so that only event can happen at
any time.  I hope I did not lower the testcase coverage.

Another KFAIL has been filed as:
	python threads incompatible with gdbserver
	http://sourceware.org/bugzilla/show_bug.cgi?id=12966

I will check it in in some time without any comments.


Thanks,
Jan


2011-07-06  Sami Wagiaalla  <swagiaal@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

        * gdb.python/py-events.exp: Remove pretty printing comment.
        * gdb.python/py-evsignal.exp: New file.
        * gdb.python/py-evthreads.c: Include signal.h.
	(thread3): Remove variable count3.  Remove variable bad and use raise
	instead.
	(thread2): Remove variable count2.  Move thread3 pthread_create here,
	merge pthread_join to a single line.
	(main): Remove variable count1.  Merge pthread_join with pthread_create
	to a single line.
	* gdb.python/py-evthreads.exp: Remove pretty printing comment.  New
	KFAIL python/12966 for gdbserver.  Test return value of
	gdb_compile_pthreads.  Use gdb_run_cmd.  Replace send_gdb and
	gdb_expect by gdb_test and gdb_test_multiple.
	(thread 2, thread 3): New tests.

--- a/gdb/testsuite/gdb.python/py-events.exp
+++ b/gdb/testsuite/gdb.python/py-events.exp
@@ -13,11 +13,6 @@
 # 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
 }
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-evsignal.exp
@@ -0,0 +1,54 @@
+# 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/>.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+if {[is_remote target]} {
+    # RuntimeError: Could not find event thread
+    kfail "python/12966" "Signal Thread 3"
+    return -1
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-evsignal"
+set srcfile py-evthreads.c
+set binfile ${objdir}/${subdir}/${testfile}
+set pyfile ${srcdir}/${subdir}/py-events.py
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    return -1
+}
+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_run_cmd
+gdb_test_multiple "" "Signal Thread 3"  {
+    -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n$gdb_prompt $" {
+        pass "thread 3 was signaled"
+    }
+    -re "The target does not support running in non-stop mode"  {
+        unsupported "non-stop mode is unsupported"
+    }
+}
--- a/gdb/testsuite/gdb.python/py-evthreads.c
+++ b/gdb/testsuite/gdb.python/py-evthreads.c
@@ -19,37 +19,35 @@
 #include <stdio.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <signal.h>
 
 pthread_t thread2_id;
 pthread_t thread3_id;
 
 void* thread3 (void* d)
 {
-  int count3 = 0;
-  count3++;
-
-  int *bad;
-  *bad = 1;
+  raise (SIGUSR1);
 
   return NULL;
 }
 
 void* thread2 (void* d)
 {
-  int count2 = 0;
-  count2++;
+  /* Do not quit thread3 asynchronously wrt thread2 stop - wait first on
+     thread3_id to stop.  It would complicate testcase receiption of the
+     events.  */
+
+  pthread_create (&thread3_id, NULL, thread3, NULL); pthread_join (thread3_id, NULL);
+
   return NULL;
 }
 
-int main (){
-
-  pthread_create (&thread2_id, NULL, thread2, NULL);
-  pthread_create (&thread3_id, NULL, thread3, NULL);
+int main (void)
+{
+  /* Use single line to not to race whether `thread2' breakpoint or `next' over
+     pthread_create will stop first.  */
 
-  int count1 = 0; // stop1
-  count1++;
+  pthread_create (&thread2_id, NULL, thread2, NULL); pthread_join (thread2_id, NULL);
 
-  pthread_join (thread2_id, NULL);
-  pthread_join (thread3_id, NULL);
   return 12;
 }
--- a/gdb/testsuite/gdb.python/py-evthreads.exp
+++ b/gdb/testsuite/gdb.python/py-evthreads.exp
@@ -13,15 +13,16 @@
 # 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
 }
 
+if {[is_remote target]} {
+    # RuntimeError: Could not find event thread
+    kfail "python/12966" "Run to breakpoint 1"
+    return -1
+}
+
 load_lib gdb-python.exp
 
 set testfile "py-evthreads"
@@ -29,7 +30,9 @@ 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}
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    return -1
+}
 clean_restart $testfile
 
 if { [skip_python_tests] } { continue }
@@ -44,76 +47,37 @@ 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"
+gdb_run_cmd
+set test "Run to breakpoint 1"
+gdb_test_multiple "" $test {
+    -re "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 1\r\nthread num: 1\r\n$gdb_prompt $" {
+        pass $test
     }
-    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"
+    -re "The target does not support running in non-stop mode" {
+        unsupported "non-stop mode is unsupported"
+        return
     }
-    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 "next" "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 2\r\nthread num: 2" "reached breakpoint 2"
 
-send_gdb "continue&\n"
-gdb_expect {
-    -re ".*event type: continue.*
-.*thread num: 1.*\r\n$gdb_prompt " {
-        pass "continue thread 1"
-    }
-    timeout {
-	    fail "continue thread 1 failed"
-	}
-}
+gdb_test "thread 2" {\[Switching to thread 2 .*}
+
+gdb_test "next" "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 3\r\nthread num: 3" "reached breakpoint 3"
+
+gdb_test "thread 3" {\[Switching to thread 3 .*}
 
-gdb_test "thread 2" ".*Switching to thread 2.*"
-send_gdb "continue&\n"
-gdb_expect {
-    -re ".*event type: continue.*
-.*thread num: 2.*" {
-        pass "continue thread 2"
+set test "continue thread 1"
+gdb_test_multiple "continue&" $test {
+    -re "event type: continue\r\nthread num: 3\r\n$gdb_prompt " {
+	# This expect string must not expect the end-of-buffer '$'.
+        pass $test
     }
-    timeout {
-	    fail "continue thread 2 failed"
-	}
 }
 
-send_gdb "continue -a\n"
-gdb_expect {
-    -re ".*stop reason: signal.*
-.*stop signal: SIGSEGV.*
-.*thread num: 3.*" {
-        pass "thread 3 was signalled"
+set test "thread 3 was signaled"
+gdb_test_multiple "" $test {
+    -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n$" {
+        pass $test
     }
-    timeout {
-	    fail "thread 3 was not signalled"
-	}
 }

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-07-06 19:42                                   ` Jan Kratochvil
@ 2011-07-07 13:51                                     ` sami wagiaalla
  2011-07-07 14:03                                       ` Jan Kratochvil
  2011-09-13 21:45                                       ` Jan Kratochvil
  0 siblings, 2 replies; 42+ messages in thread
From: sami wagiaalla @ 2011-07-07 13:51 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Pedro Alves, gdb-patches, Tom Tromey

On 07/06/2011 03:37 PM, Jan Kratochvil wrote:
> Hi Sami,
>
> the testcase had some problems where multiple asynchronous events could happen
> at the same time.  This is difficult to parse without any new framework in the
> .exp code.
>
> As Pedro asked
> http://sourceware.org/ml/gdb-patches/2011-02/msg00213.html
>> Actually, do you really need non-stop?
>
> I also do not think the testcases should / need to test the non-stop mode.
> But currently it cannot test thread id in all-stop/sync mode, therefore I have
> filed it as PR and kept the testcases in non-stop/async mode:
> 	http://sourceware.org/bugzilla/show_bug.cgi?id=12967
>

Yes, as you have concluded non-stop/async was needed to test thread id. 
It did not even occur to me that thread id should be available on 
all-stop because all threads are actually stopped. The event expresses 
that all threads are stopped by not setting thread id.

> Due to the difficulty of parsing events which can happen at the same time in
> various order I have changed also the .c file so that only event can happen at
> any time.  I hope I did not lower the testcase coverage.
>

Nope. That makes sense.

> Another KFAIL has been filed as:
> 	python threads incompatible with gdbserver
> 	http://sourceware.org/bugzilla/show_bug.cgi?id=12966
>
> I will check it in in some time without any comments.
>

Please do, and thank you for taking care of this :)

>
> Thanks,
> Jan
>
>
> 2011-07-06  Sami Wagiaalla<swagiaal@redhat.com>
> 	Jan Kratochvil<jan.kratochvil@redhat.com>
>
>          * gdb.python/py-events.exp: Remove pretty printing comment.
>          * gdb.python/py-evsignal.exp: New file.
>          * gdb.python/py-evthreads.c: Include signal.h.
> 	(thread3): Remove variable count3.  Remove variable bad and use raise
> 	instead.
> 	(thread2): Remove variable count2.  Move thread3 pthread_create here,
> 	merge pthread_join to a single line.
> 	(main): Remove variable count1.  Merge pthread_join with pthread_create
> 	to a single line.
> 	* gdb.python/py-evthreads.exp: Remove pretty printing comment.  New
> 	KFAIL python/12966 for gdbserver.  Test return value of
> 	gdb_compile_pthreads.  Use gdb_run_cmd.  Replace send_gdb and
> 	gdb_expect by gdb_test and gdb_test_multiple.
> 	(thread 2, thread 3): New tests.
>
> --- a/gdb/testsuite/gdb.python/py-events.exp
> +++ b/gdb/testsuite/gdb.python/py-events.exp
> @@ -13,11 +13,6 @@
>   # 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
>   }
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-evsignal.exp
> @@ -0,0 +1,54 @@
> +# 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/>.
> +
> +if $tracelevel then {
> +    strace $tracelevel
> +}
> +
> +if {[is_remote target]} {
> +    # RuntimeError: Could not find event thread
> +    kfail "python/12966" "Signal Thread 3"
> +    return -1
> +}
> +
> +load_lib gdb-python.exp
> +
> +set testfile "py-evsignal"
> +set srcfile py-evthreads.c
> +set binfile ${objdir}/${subdir}/${testfile}
> +set pyfile ${srcdir}/${subdir}/py-events.py
> +
> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
> +    return -1
> +}
> +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_run_cmd
> +gdb_test_multiple "" "Signal Thread 3"  {
> +    -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n$gdb_prompt $" {
> +        pass "thread 3 was signaled"
> +    }
> +    -re "The target does not support running in non-stop mode"  {
> +        unsupported "non-stop mode is unsupported"
> +    }
> +}
> --- a/gdb/testsuite/gdb.python/py-evthreads.c
> +++ b/gdb/testsuite/gdb.python/py-evthreads.c
> @@ -19,37 +19,35 @@
>   #include<stdio.h>
>   #include<pthread.h>
>   #include<unistd.h>
> +#include<signal.h>
>
>   pthread_t thread2_id;
>   pthread_t thread3_id;
>
>   void* thread3 (void* d)
>   {
> -  int count3 = 0;
> -  count3++;
> -
> -  int *bad;
> -  *bad = 1;
> +  raise (SIGUSR1);
>
>     return NULL;
>   }
>
>   void* thread2 (void* d)
>   {
> -  int count2 = 0;
> -  count2++;
> +  /* Do not quit thread3 asynchronously wrt thread2 stop - wait first on
> +     thread3_id to stop.  It would complicate testcase receiption of the
> +     events.  */
> +
> +  pthread_create (&thread3_id, NULL, thread3, NULL); pthread_join (thread3_id, NULL);
> +
>     return NULL;
>   }
>
> -int main (){
> -
> -  pthread_create (&thread2_id, NULL, thread2, NULL);
> -  pthread_create (&thread3_id, NULL, thread3, NULL);
> +int main (void)
> +{
> +  /* Use single line to not to race whether `thread2' breakpoint or `next' over
> +     pthread_create will stop first.  */
>
> -  int count1 = 0; // stop1
> -  count1++;
> +  pthread_create (&thread2_id, NULL, thread2, NULL); pthread_join (thread2_id, NULL);
>
> -  pthread_join (thread2_id, NULL);
> -  pthread_join (thread3_id, NULL);
>     return 12;
>   }
> --- a/gdb/testsuite/gdb.python/py-evthreads.exp
> +++ b/gdb/testsuite/gdb.python/py-evthreads.exp
> @@ -13,15 +13,16 @@
>   # 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
>   }
>
> +if {[is_remote target]} {
> +    # RuntimeError: Could not find event thread
> +    kfail "python/12966" "Run to breakpoint 1"
> +    return -1
> +}
> +
>   load_lib gdb-python.exp
>
>   set testfile "py-evthreads"
> @@ -29,7 +30,9 @@ 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}
> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
> +    return -1
> +}
>   clean_restart $testfile
>
>   if { [skip_python_tests] } { continue }
> @@ -44,76 +47,37 @@ 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"
> +gdb_run_cmd
> +set test "Run to breakpoint 1"
> +gdb_test_multiple "" $test {
> +    -re "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 1\r\nthread num: 1\r\n$gdb_prompt $" {
> +        pass $test
>       }
> -    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"
> +    -re "The target does not support running in non-stop mode" {
> +        unsupported "non-stop mode is unsupported"
> +        return
>       }
> -    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 "next" "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 2\r\nthread num: 2" "reached breakpoint 2"
>
> -send_gdb "continue&\n"
> -gdb_expect {
> -    -re ".*event type: continue.*
> -.*thread num: 1.*\r\n$gdb_prompt " {
> -        pass "continue thread 1"
> -    }
> -    timeout {
> -	    fail "continue thread 1 failed"
> -	}
> -}
> +gdb_test "thread 2" {\[Switching to thread 2 .*}
> +
> +gdb_test "next" "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 3\r\nthread num: 3" "reached breakpoint 3"
> +
> +gdb_test "thread 3" {\[Switching to thread 3 .*}
>
> -gdb_test "thread 2" ".*Switching to thread 2.*"
> -send_gdb "continue&\n"
> -gdb_expect {
> -    -re ".*event type: continue.*
> -.*thread num: 2.*" {
> -        pass "continue thread 2"
> +set test "continue thread 1"
> +gdb_test_multiple "continue&" $test {
> +    -re "event type: continue\r\nthread num: 3\r\n$gdb_prompt " {
> +	# This expect string must not expect the end-of-buffer '$'.
> +        pass $test
>       }
> -    timeout {
> -	    fail "continue thread 2 failed"
> -	}
>   }
>
> -send_gdb "continue -a\n"
> -gdb_expect {
> -    -re ".*stop reason: signal.*
> -.*stop signal: SIGSEGV.*
> -.*thread num: 3.*" {
> -        pass "thread 3 was signalled"
> +set test "thread 3 was signaled"
> +gdb_test_multiple "" $test {
> +    -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n$" {
> +        pass $test
>       }
> -    timeout {
> -	    fail "thread 3 was not signalled"
> -	}
>   }

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-07-07 13:51                                     ` sami wagiaalla
@ 2011-07-07 14:03                                       ` Jan Kratochvil
  2011-09-13 21:45                                       ` Jan Kratochvil
  1 sibling, 0 replies; 42+ messages in thread
From: Jan Kratochvil @ 2011-07-07 14:03 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Pedro Alves, gdb-patches, Tom Tromey, Phil Muldoon

On Thu, 07 Jul 2011 15:45:14 +0200, sami wagiaalla wrote:
> On 07/06/2011 03:37 PM, Jan Kratochvil wrote:
> > As Pedro asked
> > http://sourceware.org/ml/gdb-patches/2011-02/msg00213.html
> > > Actually, do you really need non-stop?
> > 
> > I also do not think the testcases should / need to test the non-stop mode.
> > But currently it cannot test thread id in all-stop/sync mode, therefore I have
> > filed it as PR and kept the testcases in non-stop/async mode:
> > 	http://sourceware.org/bugzilla/show_bug.cgi?id=12967
> 
> Yes, as you have concluded non-stop/async was needed to test thread
> id. It did not even occur to me that thread id should be available
> on all-stop because all threads are actually stopped. The event
> expresses that all threads are stopped by not setting thread id.

I still believe event.inferior_thread should be there even in all-stop/sync
mode, the event occured for that thread.  Whether the Python script can find
out the information also elsewhere or not I do not think that matters.

Sure it is more about some design style than any real bug so there can be
different opinions.  That PR python/12967 above is up to Phil now.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [patch] Support inferior events in python
  2011-07-07 13:51                                     ` sami wagiaalla
  2011-07-07 14:03                                       ` Jan Kratochvil
@ 2011-09-13 21:45                                       ` Jan Kratochvil
  1 sibling, 0 replies; 42+ messages in thread
From: Jan Kratochvil @ 2011-09-13 21:45 UTC (permalink / raw)
  To: sami wagiaalla; +Cc: Pedro Alves, gdb-patches, Tom Tromey

On Thu, 07 Jul 2011 15:45:14 +0200, sami wagiaalla wrote:
> On 07/06/2011 03:37 PM, Jan Kratochvil wrote:
> >I will check it in in some time without any comments.
> 
> Please do, and thank you for taking care of this :)

Checked in, with a technical re-diff.


Thanks,
Jan


http://sourceware.org/ml/gdb-cvs/2011-09/msg00076.html

--- src/gdb/testsuite/ChangeLog	2011/09/12 21:24:50	1.2851
+++ src/gdb/testsuite/ChangeLog	2011/09/13 21:39:58	1.2852
@@ -1,3 +1,21 @@
+2011-09-13  Sami Wagiaalla  <swagiaal@redhat.com>
+	    Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* gdb.python/py-events.exp: Remove pretty printing comment.
+	* gdb.python/py-evsignal.exp: New file.
+	* gdb.python/py-evthreads.c: Include signal.h.
+	(thread3): Remove variable count3.  Remove variable bad and use raise
+	instead.
+	(thread2): Remove variable count2.  Move thread3 pthread_create here,
+	merge pthread_join to a single line.
+	(main): Remove variable count1.  Merge pthread_join with pthread_create
+	to a single line.
+	* gdb.python/py-evthreads.exp: Remove pretty printing comment.  New
+	KFAIL python/12966 for gdbserver.  Test return value of
+	gdb_compile_pthreads.  Use gdb_run_cmd.  Replace send_gdb and
+	gdb_expect by gdb_test and gdb_test_multiple.
+	(thread 2, thread 3): New tests.
+
 2011-09-12  Matt Rice  <ratmice@gmail.com>
 	    Pedro Alves  <pedro@codesourcery.com>
 
--- src/gdb/testsuite/gdb.python/py-evsignal.exp
+++ src/gdb/testsuite/gdb.python/py-evsignal.exp	2011-09-13 21:40:18.445023000 +0000
@@ -0,0 +1,54 @@
+# 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/>.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+if {[is_remote target]} {
+    # RuntimeError: Could not find event thread
+    kfail "python/12966" "Signal Thread 3"
+    return -1
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-evsignal"
+set srcfile py-evthreads.c
+set binfile ${objdir}/${subdir}/${testfile}
+set pyfile ${srcdir}/${subdir}/py-events.py
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    return -1
+}
+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_run_cmd
+gdb_test_multiple "" "Signal Thread 3"  {
+    -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n$gdb_prompt $" {
+        pass "thread 3 was signaled"
+    }
+    -re "The target does not support running in non-stop mode"  {
+        unsupported "non-stop mode is unsupported"
+    }
+}
--- src/gdb/testsuite/gdb.python/py-events.exp	2011/02/05 05:27:23	1.1
+++ src/gdb/testsuite/gdb.python/py-events.exp	2011/09/13 21:39:59	1.2
@@ -13,11 +13,6 @@
 # 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
 }
--- src/gdb/testsuite/gdb.python/py-evthreads.c	2011/02/05 05:27:23	1.1
+++ src/gdb/testsuite/gdb.python/py-evthreads.c	2011/09/13 21:39:59	1.2
@@ -19,37 +19,35 @@
 #include <stdio.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <signal.h>
 
 pthread_t thread2_id;
 pthread_t thread3_id;
 
 void* thread3 (void* d)
 {
-  int count3 = 0;
-  count3++;
-
-  int *bad;
-  *bad = 1;
+  raise (SIGUSR1);
 
   return NULL;
 }
 
 void* thread2 (void* d)
 {
-  int count2 = 0;
-  count2++;
+  /* Do not quit thread3 asynchronously wrt thread2 stop - wait first on
+     thread3_id to stop.  It would complicate testcase receiption of the
+     events.  */
+
+  pthread_create (&thread3_id, NULL, thread3, NULL); pthread_join (thread3_id, NULL);
+
   return NULL;
 }
 
-int main (){
-
-  pthread_create (&thread2_id, NULL, thread2, NULL);
-  pthread_create (&thread3_id, NULL, thread3, NULL);
+int main (void)
+{
+  /* Use single line to not to race whether `thread2' breakpoint or `next' over
+     pthread_create will stop first.  */
 
-  int count1 = 0; // stop1
-  count1++;
+  pthread_create (&thread2_id, NULL, thread2, NULL); pthread_join (thread2_id, NULL);
 
-  pthread_join (thread2_id, NULL);
-  pthread_join (thread3_id, NULL);
   return 12;
 }
--- src/gdb/testsuite/gdb.python/py-evthreads.exp	2011/07/18 04:14:21	1.4
+++ src/gdb/testsuite/gdb.python/py-evthreads.exp	2011/09/13 21:39:59	1.5
@@ -13,15 +13,16 @@
 # 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
 }
 
+if {[is_remote target]} {
+    # RuntimeError: Could not find event thread
+    kfail "python/12966" "Run to breakpoint 1"
+    return -1
+}
+
 if { ![support_displaced_stepping] } { 
     unsupported "displaced stepping"
     return -1
@@ -34,7 +35,9 @@
 set binfile ${objdir}/${subdir}/${testfile}
 set pyfile ${srcdir}/${subdir}/py-events.py
 
-gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    return -1
+}
 clean_restart $testfile
 
 if { [skip_python_tests] } { continue }
@@ -49,76 +52,37 @@
 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"
+gdb_run_cmd
+set test "Run to breakpoint 1"
+gdb_test_multiple "" $test {
+    -re "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 1\r\nthread num: 1\r\n$gdb_prompt $" {
+        pass $test
     }
-    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"
+    -re "The target does not support running in non-stop mode" {
+        unsupported "non-stop mode is unsupported"
+        return
     }
-    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 "next" "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 2\r\nthread num: 2" "reached breakpoint 2"
 
-send_gdb "continue&\n"
-gdb_expect {
-    -re ".*event type: continue.*
-.*thread num: 1.*\r\n$gdb_prompt $" {
-        pass "continue thread 1"
-    }
-    timeout {
-	    fail "continue thread 1 failed"
-	}
-}
+gdb_test "thread 2" {\[Switching to thread 2 .*}
+
+gdb_test "next" "event type: stop\r\nstop reason: breakpoint\r\nbreakpoint number: 3\r\nthread num: 3" "reached breakpoint 3"
+
+gdb_test "thread 3" {\[Switching to thread 3 .*}
 
-gdb_test "thread 2" ".*Switching to thread 2.*"
-send_gdb "continue&\n"
-gdb_expect {
-    -re ".*event type: continue.*
-.*thread num: 2.*" {
-        pass "continue thread 2"
+set test "continue thread 1"
+gdb_test_multiple "continue&" $test {
+    -re "event type: continue\r\nthread num: 3\r\n$gdb_prompt " {
+	# This expect string must not expect the end-of-buffer '$'.
+        pass $test
     }
-    timeout {
-	    fail "continue thread 2 failed"
-	}
 }
 
-send_gdb "continue -a\n"
-gdb_expect {
-    -re ".*stop reason: signal.*
-.*stop signal: SIGSEGV.*
-.*thread num: 3.*" {
-        pass "thread 3 was signalled"
+set test "thread 3 was signaled"
+gdb_test_multiple "" $test {
+    -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n$" {
+        pass $test
     }
-    timeout {
-	    fail "thread 3 was not signalled"
-	}
 }

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2011-09-13 21:42 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-04 15:54 [patch] Support inferior events in python sami wagiaalla
2011-01-04 18:22 ` Eli Zaretskii
2011-01-04 20:09 ` Tom Tromey
2011-01-17 22:59   ` sami wagiaalla
2011-01-19 16:42     ` Tom Tromey
2011-01-21 23:06       ` sami wagiaalla
2011-01-28 16:21         ` Tom Tromey
2011-02-02 21:04           ` sami wagiaalla
2011-02-02 21:35             ` Tom Tromey
2011-02-03 16:41               ` sami wagiaalla
2011-02-03 18:26                 ` Eli Zaretskii
2011-02-03 19:45                   ` sami wagiaalla
2011-02-03 21:42                 ` Tom Tromey
2011-02-04 20:07                   ` sami wagiaalla
2011-02-04 20:29                     ` Tom Tromey
2011-02-04 20:35                       ` sami wagiaalla
2011-02-04 23:00                         ` Paul Pluzhnikov
2011-02-05  5:44                           ` Hui Zhu
2011-02-07 15:22                             ` sami wagiaalla
2011-02-07 15:24                               ` Tom Tromey
2011-02-07 15:34                                 ` Paul Pluzhnikov
2011-02-07 16:01                                   ` sami wagiaalla
2011-02-07 15:39                                 ` sami wagiaalla
2011-04-20 20:26                         ` Patch for non-stop remote assertion (was: RE: [patch] Support inferior events in python) Marc Khouzam
2011-04-25 18:12                           ` Patch for non-stop remote assertion Tom Tromey
2011-04-25 18:31                             ` Marc Khouzam
2011-05-16 15:41                               ` Marc Khouzam
2011-05-19 18:38                               ` Tom Tromey
2011-02-09  7:55                     ` [patch] Support inferior events in python Jan Kratochvil
2011-02-09 16:19                       ` sami wagiaalla
2011-02-09 16:30                         ` Jan Kratochvil
2011-02-11 15:28                           ` sami wagiaalla
2011-02-11 15:55                             ` Joel Brobecker
2011-02-11 19:19                               ` sami wagiaalla
2011-02-11 19:46                                 ` Jan Kratochvil
2011-02-11 15:57                             ` Pedro Alves
2011-02-14 17:36                               ` sami wagiaalla
2011-02-16 11:48                                 ` Jan Kratochvil
2011-07-06 19:42                                   ` Jan Kratochvil
2011-07-07 13:51                                     ` sami wagiaalla
2011-07-07 14:03                                       ` Jan Kratochvil
2011-09-13 21:45                                       ` Jan Kratochvil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).