public inbox for archer@sourceware.org
 help / color / mirror / Atom feed
* Python inferior control
@ 2010-08-13 14:54 Phil Muldoon
  2010-08-13 19:49 ` Tom Tromey
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Phil Muldoon @ 2010-08-13 14:54 UTC (permalink / raw)
  To: archer, oguzkayral

Hi,

On the 23rd of August 2009 Oguz Kayral submitted an initial patch to
implement GDB inferior notification events in Python.  Since then the
patch has bit-rotted somewhat.  I've reconstituted this patch
against current GDB head and attached it.  I've not changed very much:
renamed the files, re-ordered the Makefile.in and made some minor code
changes so that it compiles.

Why am I doing this?

Firstly as a historical context.  Oguz's patches were a series of
patches and also emails containing code in-line and not in patch format.
This patch unifies this (though I left out the examples, as they
cannot belong in the CVS tree at the moment).  I'll reconstitute the
ChangeLogs when we submit this code upstream.  Secondly, I am planning
on working on this patch/code: improving, adding and eventually
submitting it upstream.  As the patch that Oguz wrote is substantial
enough to give a general thrust of the design intentions I thought it
would be a good idea to re-spark any conversations before I work on
this code.  So if there any ideas, let's here them!


Cheers

Phil

--

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 65eb1fe..33cccd9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -272,7 +272,12 @@ SUBDIR_PYTHON_OBS = \
 	py-auto-load.o \
 	py-block.o \
 	py-breakpoint.o \
+	py-breakpointstopevent.o \
 	py-cmd.o \
+	py-continueevent.o \
+	py-event.o \
+	py-eventregistry.o \
+	py-exitedevent.o \
 	py-frame.o \
 	py-function.o \
 	py-inferior.o \
@@ -282,17 +287,25 @@ SUBDIR_PYTHON_OBS = \
 	py-param.o \
 	py-prettyprint.o \
 	py-progspace.o \
+	py-signalstopevent.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-breakpointstopevent.c \
 	python/py-cmd.c \
+	python/py-continueevent.c \
+	python/py-event.c \
+	python/py-eventregistry.c \
+	python/py-exitedevent.c \
 	python/py-frame.c \
 	python/py-function.c \
 	python/py-inferior.c \
@@ -302,6 +315,8 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-param.c \
 	python/py-prettyprint.c \
 	python/py-progspace.c \
+	python/py-signalstopevent.c \
+	python/py-stopevent.c \
 	python/py-symbol.c \
 	python/py-symtab.c \
 	python/py-type.c \
@@ -2010,10 +2025,30 @@ py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
 	$(POSTCOMPILE)
 
+py-breakpointstopevent.o: $(srcdir)/python/py-breakpointstopevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpointstopevent.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-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)
@@ -2050,6 +2085,14 @@ py-progspace.o: $(srcdir)/python/py-progspace.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-progspace.c
 	$(POSTCOMPILE)
 
+py-signalstopevent.o: $(srcdir)/python/py-signalstopevent.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-signalstopevent.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 14f0417..d00048a 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;
 
 /* A dynamically allocated vector of breakpoint objects.  Each
@@ -52,18 +49,6 @@ static int bppy_live;
    constructor and the breakpoint-created hook function.  */
 static breakpoint_object *bppy_pending_object;
 
-struct breakpoint_object
-{
-  PyObject_HEAD
-
-  /* The breakpoint number according to gdb.  */
-  int number;
-
-  /* The gdb breakpoint object, or NULL if the breakpoint has been
-     deleted.  */
-  struct breakpoint *bp;
-};
-
 /* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
    exception if it is invalid.  */
 #define BPPY_REQUIRE_VALID(Breakpoint)					\
@@ -626,6 +611,34 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
   return result;
 }
 
+/* Function to get the corresponding breakpoint object for the given
+   bpstats. */
+
+breakpoint_object *
+gdbpy_breakpoint_from_bpstats (struct bpstats *bs)
+{
+  int i, out = 0;
+  breakpoint_object *breakpoint = NULL;
+
+  if (bppy_live == 0)
+    return NULL;
+
+  for (i = 0; out < bppy_live; i++)
+    {
+      if (! bppy_breakpoints[i])
+	continue;
+
+      if (bs->breakpoint_at == bppy_breakpoints[i]->bp->loc)
+	breakpoint = bppy_breakpoints[i];
+
+      ++out;
+    }
+
+  return breakpoint;
+}
+
+
+
 \f
 
 /* Static function to return a tuple holding all breakpoints.  */
diff --git a/gdb/python/py-breakpointstopevent.c b/gdb/python/py-breakpointstopevent.c
new file mode 100644
index 0000000..b63df7b
--- /dev/null
+++ b/gdb/python/py-breakpointstopevent.c
@@ -0,0 +1,166 @@
+/* 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 "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject breakpoint_stop_event_object_type;
+
+typedef struct
+{
+  stop_event_object stop_event;
+  breakpoint_object *breakpoint;
+} breakpoint_stop_event_object;
+
+static void
+bp_stop_evpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((breakpoint_stop_event_object *) self)->breakpoint);
+  self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's breakpoint. */
+static PyObject *
+bp_stop_evpy_get_breakpoint (PyObject *self, void *closure)
+{
+  breakpoint_stop_event_object *breakpoint_stop_event_obj =
+(breakpoint_stop_event_object *) self;
+
+  Py_INCREF (breakpoint_stop_event_obj->breakpoint);
+
+  return (PyObject *) (breakpoint_stop_event_obj->breakpoint);
+}
+
+breakpoint_stop_event_object *
+create_breakpoint_stop_event_object (breakpoint_object *bp)
+{
+  breakpoint_stop_event_object *breakpoint_stop_event_obj;
+
+  breakpoint_stop_event_obj = PyObject_New
+(breakpoint_stop_event_object, &breakpoint_stop_event_object_type);
+  if (!breakpoint_stop_event_obj)
+    return NULL;
+
+  breakpoint_stop_event_obj->stop_event.event.inferior_thread =
+find_thread_object (inferior_ptid);
+  Py_INCREF (breakpoint_stop_event_obj->stop_event.event.inferior_thread);
+  breakpoint_stop_event_obj->stop_event.event.event_type =
+(PyStringObject *) PyString_FromString ("stop");
+  breakpoint_stop_event_obj->stop_event.stop_reason = (PyStringObject
+*) PyString_FromString ("breakpoint");
+  breakpoint_stop_event_obj->breakpoint = bp;
+  Py_INCREF (breakpoint_stop_event_obj->breakpoint);
+
+  return breakpoint_stop_event_obj;
+}
+
+/* Initialize the Python breakpoint stop event code. */
+void
+gdbpy_initialize_breakpoint_stop_event (void)
+{
+  breakpoint_stop_event_object_type.tp_base = &stop_event_object_type;
+  if (PyType_Ready (&breakpoint_stop_event_object_type) < 0)
+    return;
+
+  Py_INCREF (&breakpoint_stop_event_object_type);
+  PyModule_AddObject (gdb_module, "BreakpointStopEvent", (PyObject *)
+&breakpoint_stop_event_object_type);
+}
+
+/* Callback that is used when a stop event occurs. This function will
+create a new Python breakpoint stop event object. */
+void
+emit_breakpoint_stop_event (struct bpstats *bs)
+{
+  thread_object *inferior_thread;
+  PyObject *callback_list;
+  PyObject *args_tuple;
+  Py_ssize_t i;
+  breakpoint_object *breakpoint;
+  breakpoint_stop_event_object *breakpoint_stop_event_obj;
+
+  inferior_thread = find_thread_object (inferior_ptid);
+
+  breakpoint = gdbpy_breakpoint_from_bpstats (bs);
+
+  breakpoint_stop_event_obj = create_breakpoint_stop_event_object (breakpoint);
+
+  callback_list = (PyObject *)
+(inferior_thread->breakpoint_stop_eventregistry->callbacks);
+
+  args_tuple = PyTuple_New ((Py_ssize_t) 1);
+  PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *)
+breakpoint_stop_event_obj);
+
+  for (i = 0; i < PyList_Size (callback_list); i++)
+    {
+      PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+    }
+}
+
+static PyGetSetDef breakpoint_stop_event_object_getset[] =
+{
+  { "breakpoint", bp_stop_evpy_get_breakpoint, NULL, "Breakpoint.", NULL },
+
+  { NULL } /* Sentinel. */
+};
+
+static PyTypeObject breakpoint_stop_event_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,                                          /* ob_size */
+  "gdb.BreakpointStopEvent",                  /* tp_name */
+  sizeof (breakpoint_stop_event_object),      /* tp_basicsize */
+  0,                                          /* tp_itemsize */
+  bp_stop_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,                         /* tp_flags */
+  "GDB breakpoint stop 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 */
+  breakpoint_stop_event_object_getset,        /* 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-continueevent.c b/gdb/python/py-continueevent.c
new file mode 100644
index 0000000..f80d9ac
--- /dev/null
+++ b/gdb/python/py-continueevent.c
@@ -0,0 +1,138 @@
+/* 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 "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject continue_event_object_type;
+
+typedef struct
+{
+  event_object event;
+} continue_event_object;
+
+static void
+continue_evpy_dealloc (PyObject *self)
+{
+  self->ob_type->tp_free (self);
+}
+
+continue_event_object *
+create_continue_event_object ()
+{
+  continue_event_object *continue_event_obj;
+
+  continue_event_obj = PyObject_New (continue_event_object,
+&continue_event_object_type);
+
+  if (!continue_event_obj)
+    return NULL;
+
+  continue_event_obj->event.inferior_thread = find_thread_object
+(inferior_ptid);
+  Py_INCREF (continue_event_obj->event.inferior_thread);
+  continue_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("continue");
+
+  return continue_event_obj;
+}
+
+/* Initialize the Python continue event code. */
+void
+gdbpy_initialize_continue_event (void)
+{
+  continue_event_object_type.tp_base = &event_object_type;
+  if (PyType_Ready (&continue_event_object_type) < 0)
+    return;
+
+  Py_INCREF (&continue_event_object_type);
+  PyModule_AddObject (gdb_module, "ContinueEvent", (PyObject *)
+&continue_event_object_type);
+}
+
+/* Callback that is used when a continue event occurs. This function
+   will create a new Python continue event object. */
+void
+emit_continue_event (ptid_t ptid)
+{
+  thread_object *inferior_thread;
+  PyObject *callback_list;
+  PyObject *args_tuple;
+  Py_ssize_t i;
+  continue_event_object *continue_event_obj;
+
+  inferior_thread = find_thread_object (inferior_ptid);
+
+  continue_event_obj = create_continue_event_object();
+
+  callback_list = (PyObject *)
+(inferior_thread->continue_eventregistry->callbacks);
+
+  args_tuple = PyTuple_New ((Py_ssize_t) 1);
+  PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) continue_event_obj);
+
+  for (i = 0; i < PyList_Size (callback_list); i++)
+    {
+      PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+    }
+}
+
+static PyTypeObject continue_event_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,                                          /* ob_size */
+  "gdb.ContinueEvent",                        /* tp_name */
+  sizeof (continue_event_object),             /* tp_basicsize */
+  0,                                          /* tp_itemsize */
+  continue_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,                         /* tp_flags */
+  "GDB continue 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 */
+  0,                                          /* tp_dictoffset */
+  0,                                          /* tp_init */
+  0                                           /* tp_alloc */
+};
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
new file mode 100644
index 0000000..7394ded
--- /dev/null
+++ b/gdb/python/py-event.c
@@ -0,0 +1,130 @@
+/* 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 "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+event_object *
+create_event_object (const char *event_type)
+{
+  event_object *event_obj;
+
+  event_obj = PyObject_New (event_object, &event_object_type);
+  if (!event_obj)
+    return NULL;
+
+  event_obj->inferior_thread = find_thread_object (inferior_ptid);
+  Py_INCREF (event_obj->inferior_thread);
+  event_obj->event_type = (PyStringObject *) PyString_FromString (event_type);
+
+  return event_obj;
+}
+
+static void
+evpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((event_object *) self)->inferior_thread);
+  self->ob_type->tp_free (self);
+}
+
+/* Python function to get the event's thread. */
+static PyObject *
+evpy_get_inferior_thread (PyObject *self, void *closure)
+{
+  event_object *event_obj = (event_object *) self;
+
+  Py_INCREF (event_obj->inferior_thread);
+
+  return (PyObject *) (event_obj->inferior_thread);
+}
+
+/* Python function to get the event's type. */
+static PyObject *
+evpy_get_event_type (PyObject *self, void *closure)
+{
+  event_object *event_obj = (event_object *) self;
+
+  Py_INCREF (event_obj->event_type);
+
+  return (PyObject *) (event_obj->event_type);
+}
+
+/* Initialize the Python event code. */
+void
+gdbpy_initialize_event (void)
+{
+  if (PyType_Ready (&event_object_type) < 0)
+    return;
+
+  Py_INCREF (&event_object_type);
+  PyModule_AddObject (gdb_module, "Event", (PyObject *) &event_object_type);
+}
+
+static PyGetSetDef event_object_getset[] =
+{
+  { "inferior_thread", evpy_get_inferior_thread, NULL, 
+    "Inferior thread.", NULL },
+  { "event_type", evpy_get_event_type, NULL, "Event type.", NULL },
+
+  { NULL } /* Sentinel. */
+};
+
+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 */
+  event_object_getset,                        /* 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-eventregistry.c b/gdb/python/py-eventregistry.c
new file mode 100644
index 0000000..c1aa7b4
--- /dev/null
+++ b/gdb/python/py-eventregistry.c
@@ -0,0 +1,155 @@
+/* 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 "python-internal.h"
+
+static PyTypeObject eventregistry_object_type;
+
+/* Implementation of EventRegistry.connect () -> NULL */
+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;
+    }
+
+  Py_INCREF (func);
+
+  PyList_Append (callback_list, func);
+
+  Py_RETURN_NONE;
+}
+
+/* Implementation of EventRegistry.disconnect () -> NULL */
+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;
+    }
+
+  Py_INCREF (func);
+
+  PySequence_DelItem (callback_list, PySequence_Index (callback_list, func));
+
+  Py_RETURN_NONE;
+}
+
+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);
+}
+
+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-exitedevent.c b/gdb/python/py-exitedevent.c
new file mode 100644
index 0000000..d2a1d88
--- /dev/null
+++ b/gdb/python/py-exitedevent.c
@@ -0,0 +1,156 @@
+/* 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 "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject exited_event_object_type;
+
+typedef struct
+{
+  event_object event;
+  PyLongObject *exit_code;
+} exited_event_object;
+
+static void
+exit_evpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((exited_event_object *) self)->exit_code);
+  self->ob_type->tp_free (self);
+}
+
+/* Python function to get the exited event's exit code. */
+static PyObject *
+exit_evpy_get_exit_code (PyObject *self, void *closure)
+{
+  exited_event_object *exited_event_obj = (exited_event_object *) self;
+
+  Py_INCREF (exited_event_obj->exit_code);
+
+  return (PyObject *) (exited_event_obj->exit_code);
+}
+
+exited_event_object *
+create_exited_event_object (thread_object *inferior_thread, long long
+int *exit_code)
+{
+  exited_event_object *exited_event_obj;
+
+  exited_event_obj = PyObject_New (exited_event_object,
+&exited_event_object_type);
+
+  if (!exited_event_obj)
+    return NULL;
+
+  exited_event_obj->event.inferior_thread = inferior_thread;
+  Py_INCREF (exited_event_obj->event.inferior_thread);
+  exited_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("exit");
+  exited_event_obj->exit_code = (PyLongObject *) PyLong_FromLongLong
+(*exit_code);
+
+  return exited_event_obj;
+}
+
+/* Initialize the Python exited event code. */
+void gdbpy_initialize_exited_event (void)
+{
+  exited_event_object_type.tp_base = &event_object_type;
+  if (PyType_Ready (&exited_event_object_type) < 0)
+    return;
+
+  Py_INCREF (&exited_event_object_type);
+  PyModule_AddObject (gdb_module, "ExitedEvent", (PyObject *)
+&exited_event_object_type);
+}
+
+/* Callback that is used when an exit event occurs. This function
+   will create a new Python exited event object. */
+void
+emit_exited_event (thread_object *inferior_thread, long long int *exit_code)
+{
+  PyObject *callback_list;
+  PyObject *args_tuple;
+  Py_ssize_t i;
+  exited_event_object *exited_event_obj;
+
+  exited_event_obj = create_exited_event_object (inferior_thread, exit_code);
+
+  callback_list = (PyObject *)
+(inferior_thread->exited_eventregistry->callbacks);
+
+  args_tuple = PyTuple_New ((Py_ssize_t) 1);
+  PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) exited_event_obj);
+
+  for (i = 0; i < PyList_Size (callback_list); i++)
+    {
+      PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+    }
+}
+
+static PyGetSetDef exited_event_object_getset[] =
+{
+  { "exit_code", exit_evpy_get_exit_code, NULL, "Exit code.", NULL },
+
+  { NULL } /* Sentinel. */
+};
+
+static PyTypeObject exited_event_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,                                          /* ob_size */
+  "gdb.ExitedEvent",                          /* tp_name */
+  sizeof (exited_event_object),               /* tp_basicsize */
+  0,                                          /* tp_itemsize */
+  exit_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,                         /* tp_flags */
+  "GDB exited 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 */
+  exited_event_object_getset,                 /* 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-inferior.c b/gdb/python/py-inferior.c
index 3a0feab..9e182c4 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -26,6 +26,7 @@
 #include "python-internal.h"
 #include "arch-utils.h"
 #include "language.h"
+#include "gdb_signals.h"
 
 struct threadlist_entry {
   thread_object *thread_obj;
@@ -73,6 +74,72 @@ static PyTypeObject membuf_object_type;
       }								\
   } while (0)
 
+static void
+python_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+  PyGILState_STATE state;
+  char *stop_signal;
+
+  if (!find_thread_ptid (inferior_ptid))
+      return;
+
+  stop_signal = (char *) target_signal_to_name (inferior_thread()->stop_signal);
+
+  state = PyGILState_Ensure ();
+
+  emit_stop_event (bs, stop_signal);
+
+  PyGILState_Release (state);
+}
+
+static void
+python_on_resume (ptid_t ptid)
+{
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+
+  emit_continue_event (ptid);
+
+  PyGILState_Release (state);
+}
+
+static void
+python_thread_exit (struct thread_info *tp, int ignore)
+{
+  PyGILState_STATE state;
+  LONGEST exitcode_val;
+  long long int *exit_code;
+  inferior_object *inf_obj;
+  thread_object *thread_obj;
+  struct threadlist_entry **entry;
+
+  inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid));
+  if (!inf_obj)
+    return;
+
+  /* Find thread entry in its inferior's thread_list. */
+  for (entry = &inf_obj->threads; *entry != NULL; entry = &(*entry)->next)
+    if ((*entry)->thread_obj->thread == tp)
+      break;
+
+  if (!*entry)
+    return;
+
+  thread_obj = (*entry)->thread_obj;
+
+  state = PyGILState_Ensure ();
+
+  if (get_internalvar_integer (lookup_internalvar ("_exitcode"), &exitcode_val))
+    exit_code = (long long int *) &exitcode_val;
+
+  if (exit_code)
+    emit_exited_event (thread_obj, exit_code);
+
+  PyGILState_Release (state);
+}
+
+
 /* 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.  */
@@ -589,6 +656,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_thread_exit (python_thread_exit);
 
   if (PyType_Ready (&membuf_object_type) < 0)
     return;
diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c
index 86aba50..d3f448c 100644
--- a/gdb/python/py-infthread.c
+++ b/gdb/python/py-infthread.c
@@ -51,6 +51,12 @@ create_thread_object (struct thread_info *tp)
   thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid));
   Py_INCREF (thread_obj->inf_obj);
 
+  thread_obj->stop_eventregistry = create_eventregistry_object ();
+  thread_obj->breakpoint_stop_eventregistry = create_eventregistry_object ();
+  thread_obj->signal_stop_eventregistry = create_eventregistry_object ();
+  thread_obj->continue_eventregistry = create_eventregistry_object ();
+  thread_obj->exited_eventregistry = create_eventregistry_object ();
+
   return thread_obj;
 }
 

 static void
 thpy_dealloc (PyObject *self)
 {
   Py_DECREF (((thread_object *) self)->inf_obj);
+  Py_DECREF (((thread_object *) self)->stop_eventregistry);
+  Py_DECREF (((thread_object *) self)->breakpoint_stop_eventregistry);
+  Py_DECREF (((thread_object *) self)->signal_stop_eventregistry);
+  Py_DECREF (((thread_object *) self)->continue_eventregistry);
+  Py_DECREF (((thread_object *) self)->exited_eventregistry);
+
   self->ob_type->tp_free (self);
 }
 
 static PyObject *
+thpy_get_stop_eventregistry (PyObject *self, void *closure)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  Py_INCREF (thread_obj->stop_eventregistry);
+
+  return (PyObject *) (thread_obj->stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_breakpoint_stop_eventregistry (PyObject *self, void *closure)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  Py_INCREF (thread_obj->breakpoint_stop_eventregistry);
+
+  return (PyObject *) (thread_obj->breakpoint_stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_signal_stop_eventregistry (PyObject *self, void *closure)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  Py_INCREF (thread_obj->signal_stop_eventregistry);
+
+  return (PyObject *) (thread_obj->signal_stop_eventregistry);
+}
+
+static PyObject *
+thpy_get_continue_eventregistry (PyObject *self, void *closure)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  Py_INCREF (thread_obj->continue_eventregistry);
+
+  return (PyObject *) (thread_obj->continue_eventregistry);
+}
+
+static PyObject *
+thpy_get_exited_eventregistry (PyObject *self, void *closure)
+{
+  thread_object *thread_obj = (thread_object *) self;
+
+  THPY_REQUIRE_VALID (thread_obj);
+
+  Py_INCREF (thread_obj->exited_eventregistry);
+
+  return (PyObject *) (thread_obj->exited_eventregistry);
+}
+
+static PyObject *
 thpy_get_num (PyObject *self, void *closure)
 {
   thread_object *thread_obj = (thread_object *) self;
@@ -204,6 +274,17 @@ static PyGetSetDef thread_object_getset[] =
   { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
   { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.",
     NULL },
+  { "stop_eventregistry", thpy_get_stop_eventregistry, NULL, 
+    "Stop event registry object of the thread.", NULL },
+  { "breakpoint_stop_eventregistry",
+    thpy_get_breakpoint_stop_eventregistry, NULL, 
+    "Breakpoint stop event registry object of the thread.", NULL },
+  { "signal_stop_eventregistry", thpy_get_signal_stop_eventregistry,
+    NULL, "Signal stop event registry object of the thread.", NULL },
+  { "continue_eventregistry", thpy_get_continue_eventregistry, NULL,
+    "Continue event registry object of the thread.", NULL },
+  { "exited_eventregistry", thpy_get_exited_eventregistry, NULL,
+    "Exited event registry object of the thread.", NULL },
 
   { NULL }
 };
diff --git a/gdb/python/py-signalstopevent.c b/gdb/python/py-signalstopevent.c
new file mode 100644
index 0000000..5ab8af7
--- /dev/null
+++ b/gdb/python/py-signalstopevent.c
@@ -0,0 +1,163 @@
+/* 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 "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static PyTypeObject signal_stop_event_object_type;
+
+typedef struct
+{
+  stop_event_object stop_event;
+  PyStringObject *stop_signal;
+} signal_stop_event_object;
+
+static void
+sig_stop_evpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((signal_stop_event_object *) self)->stop_signal);
+  self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's stop signal. */
+static PyObject *
+sig_stop_evpy_get_stop_signal (PyObject *self, void *closure)
+{
+  signal_stop_event_object *signal_stop_event_obj =
+(signal_stop_event_object *) self;
+
+  Py_INCREF (signal_stop_event_obj->stop_signal);
+
+  return (PyObject *) (signal_stop_event_obj->stop_signal);
+}
+
+signal_stop_event_object *
+create_signal_stop_event_object (const char *stop_signal)
+{
+  signal_stop_event_object *signal_stop_event_obj;
+
+  signal_stop_event_obj = PyObject_New (signal_stop_event_object,
+&signal_stop_event_object_type);
+  if (!signal_stop_event_obj)
+    return NULL;
+
+  signal_stop_event_obj->stop_event.event.inferior_thread =
+find_thread_object (inferior_ptid);
+  Py_INCREF (signal_stop_event_obj->stop_event.event.inferior_thread);
+  signal_stop_event_obj->stop_event.event.event_type = (PyStringObject
+*) PyString_FromString ("stop");
+  signal_stop_event_obj->stop_event.stop_reason = (PyStringObject *)
+PyString_FromString ("signal");
+  signal_stop_event_obj->stop_signal = (PyStringObject *)
+PyString_FromString (stop_signal);
+
+  return signal_stop_event_obj;
+}
+
+/* Initialize the Python stop event code. */
+void
+gdbpy_initialize_signal_stop_event (void)
+{
+  signal_stop_event_object_type.tp_base = &stop_event_object_type;
+  if (PyType_Ready (&signal_stop_event_object_type) < 0)
+    return;
+
+  Py_INCREF (&signal_stop_event_object_type);
+  PyModule_AddObject (gdb_module, "SignalStopEvent", (PyObject *)
+&signal_stop_event_object_type);
+}
+
+/* Callback that is used when a signal stop event occurs. This function
+   will create a new Python signal stop event object. */
+void
+emit_signal_stop_event (const char *stop_signal)
+{
+  thread_object *inferior_thread;
+  PyObject *callback_list;
+  PyObject *args_tuple;
+  Py_ssize_t i;
+  signal_stop_event_object *signal_stop_event_obj;
+
+  inferior_thread = find_thread_object (inferior_ptid);
+
+  signal_stop_event_obj = create_signal_stop_event_object (stop_signal);
+
+  callback_list = (PyObject *)
+(inferior_thread->signal_stop_eventregistry->callbacks);
+
+  args_tuple = PyTuple_New ((Py_ssize_t) 1);
+  PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *)
+signal_stop_event_obj);
+
+  for (i = 0; i < PyList_Size (callback_list); i++)
+    {
+      PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+    }
+}
+
+static PyGetSetDef signal_stop_event_object_getset[] =
+{
+  { "stop_signal", sig_stop_evpy_get_stop_signal, NULL, "Stop signal.", NULL },
+
+  { NULL } /* Sentinel. */
+};
+
+static PyTypeObject signal_stop_event_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,                                          /* ob_size */
+  "gdb.SignalStopEvent",                      /* tp_name */
+  sizeof (signal_stop_event_object),          /* tp_basicsize */
+  0,                                          /* tp_itemsize */
+  sig_stop_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,                         /* tp_flags */
+  "GDB signal stop 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 */
+  signal_stop_event_object_getset,            /* 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-stopevent.c b/gdb/python/py-stopevent.c
new file mode 100644
index 0000000..069e441
--- /dev/null
+++ b/gdb/python/py-stopevent.c
@@ -0,0 +1,164 @@
+/* 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 "defs.h"
+#include "command.h"
+#include "python-internal.h"
+#include "inferior.h"
+
+static void
+stop_evpy_dealloc (PyObject *self)
+{
+  Py_DECREF (((stop_event_object *) self)->stop_reason);
+  self->ob_type->tp_free (self);
+}
+
+/* Python function to get the stop event's stop reason. */
+static PyObject *
+stop_evpy_get_stop_reason (PyObject *self, void *closure)
+{
+  stop_event_object *stop_event_obj = (stop_event_object *) self;
+
+  Py_INCREF (stop_event_obj->stop_reason);
+
+  return (PyObject *) (stop_event_obj->stop_reason);
+}
+
+stop_event_object *
+create_stop_event_object (const char *stop_reason)
+{
+  stop_event_object *stop_event_obj;
+
+  stop_event_obj = PyObject_New (stop_event_object, &stop_event_object_type);
+  if (!stop_event_obj)
+    return NULL;
+
+  stop_event_obj->event.inferior_thread = find_thread_object (inferior_ptid);
+  Py_INCREF (stop_event_obj->event.inferior_thread);
+  stop_event_obj->event.event_type = (PyStringObject *)
+PyString_FromString ("stop");
+  stop_event_obj->stop_reason = (PyStringObject *) PyString_FromString
+(stop_reason);
+
+  return stop_event_obj;
+}
+
+/* Initialize the Python stop event code. */
+void
+gdbpy_initialize_stop_event (void)
+{
+  stop_event_object_type.tp_base = &event_object_type;
+  if (PyType_Ready (&stop_event_object_type) < 0)
+    return;
+
+  Py_INCREF (&stop_event_object_type);
+  PyModule_AddObject (gdb_module, "StopEvent", (PyObject *)
+&stop_event_object_type);
+}
+
+/* Callback that is used when a stop event occurs. This function
+   will create a new Python stop event object. */
+void
+emit_stop_event (struct bpstats *bs, const char *stop_signal)
+{
+  thread_object *inferior_thread;
+  PyObject *callback_list;
+  PyObject *args_tuple;
+  Py_ssize_t i;
+  stop_event_object *stop_event_obj = NULL; /* Appease GCC warning.  */
+
+  inferior_thread = find_thread_object (inferior_ptid);
+
+  if (bs)
+    {
+      stop_event_obj = create_stop_event_object ("breakpoint");
+      emit_breakpoint_stop_event (bs);
+    }
+
+  /* Check if the signal is "Signal 0" or "Trace/breakpoint trap". */
+  if ((strcmp (stop_signal, "0") != 0) && (strcmp (stop_signal,
+"SIGTRAP") != 0))
+    {
+      stop_event_obj = create_stop_event_object ("signal");
+      emit_signal_stop_event (stop_signal);
+    }
+
+  if (!stop_event_obj)
+    stop_event_obj = create_stop_event_object ("unknown");
+
+  callback_list = (PyObject *) (inferior_thread->stop_eventregistry->callbacks);
+
+  args_tuple = PyTuple_New ((Py_ssize_t) 1);
+  PyTuple_SetItem (args_tuple, (Py_ssize_t) 0, (PyObject *) stop_event_obj);
+
+  for (i = 0; i < PyList_Size (callback_list); i++)
+    {
+      PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
+    }
+
+}
+
+static PyGetSetDef stop_event_object_getset[] =
+{
+  { "stop_reason", stop_evpy_get_stop_reason, NULL, "Stop reason.", NULL },
+
+  { NULL } /* Sentinel. */
+};
+
+PyTypeObject stop_event_object_type =
+{
+  PyObject_HEAD_INIT (NULL)
+  0,                                          /* ob_size */
+  "gdb.StopEvent",                            /* tp_name */
+  sizeof (stop_event_object),                 /* tp_basicsize */
+  0,                                          /* tp_itemsize */
+  stop_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 stop 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 */
+  stop_event_object_getset,                   /* 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/python-internal.h b/gdb/python/python-internal.h
index 2b8d301..609892a 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -75,6 +75,7 @@ typedef int Py_ssize_t;
 
 /* Also needed to parse enum var_types. */
 #include "command.h"
+#include "breakpoint.h"
 
 struct block;
 struct value;
@@ -85,6 +86,31 @@ 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 stop_event_object_type;
+
+/* Used in python-breakpoint.c */
+typedef struct breakpoint_object breakpoint_object;
+
+struct breakpoint_object
+{
+  PyObject_HEAD
+
+  /* The breakpoint number according to gdb.  */
+  int number;
+
+  /* The gdb breakpoint object, or NULL if the breakpoint has been
+     deleted.  */
+  struct breakpoint *bp;
+};
+
+/* Used in python-eventregistry.c */
+typedef struct
+{
+  PyObject_HEAD
+
+  PyListObject *callbacks;
+} eventregistry_object;
 
 typedef struct
 {
@@ -92,11 +118,32 @@ typedef struct
 
   /* The thread we represent.  */
   struct thread_info *thread;
+  eventregistry_object *stop_eventregistry;
+  eventregistry_object *breakpoint_stop_eventregistry;
+  eventregistry_object *signal_stop_eventregistry;
+  eventregistry_object *continue_eventregistry;
+  eventregistry_object *exited_eventregistry;
 
   /* The Inferior object to which this thread belongs.  */
   PyObject *inf_obj;
 } thread_object;
 
+/* Used in python-event.c */
+typedef struct
+{
+  PyObject_HEAD
+
+  thread_object *inferior_thread;
+  PyStringObject *event_type;
+} event_object;
+
+/* Used in python-stopevent.c */
+typedef struct
+{
+  event_object event;
+  PyStringObject *stop_reason;
+} stop_event_object;
+
 extern struct cmd_list_element *set_python_list;
 extern struct cmd_list_element *show_python_list;
 
@@ -136,6 +183,14 @@ 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);
+eventregistry_object *create_eventregistry_object (void);
+breakpoint_object *gdbpy_breakpoint_from_bpstats (struct bpstats *bs);
+void emit_stop_event (struct bpstats *bs, const char *stop_signal);
+void emit_breakpoint_stop_event (struct bpstats *bs);
+void emit_signal_stop_event (const char *stop_signal);
+void emit_continue_event (ptid_t ptid);
+void emit_exited_event (thread_object *inferior_thread, 
+			long long int *exit_code);
 
 struct block *block_object_to_block (PyObject *obj);
 struct symbol *symbol_object_to_symbol (PyObject *obj);
@@ -162,6 +217,13 @@ 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_stop_event (void);
+void gdbpy_initialize_signal_stop_event (void);
+void gdbpy_initialize_breakpoint_stop_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 030b142..46f4a9e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -965,6 +965,14 @@ Enables or disables printing of Python stack traces."),
   gdbpy_initialize_inferior ();
   gdbpy_initialize_events ();
 
+  gdbpy_initialize_eventregistry ();
+  gdbpy_initialize_event ();
+  gdbpy_initialize_stop_event ();
+  gdbpy_initialize_signal_stop_event ();
+  gdbpy_initialize_breakpoint_stop_event ();
+  gdbpy_initialize_continue_event ();
+  gdbpy_initialize_exited_event ();
+
   PyRun_SimpleString ("import gdb");
   PyRun_SimpleString ("gdb.pretty_printers = []");
 

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

* Re: Python inferior control
  2010-08-13 14:54 Python inferior control Phil Muldoon
@ 2010-08-13 19:49 ` Tom Tromey
  2010-08-26 15:02   ` Oguz Kayral
  2010-08-15 17:42 ` Richard Ward
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Tom Tromey @ 2010-08-13 19:49 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: archer, oguzkayral

>>>>> "Phil" == Phil Muldoon <pmuldoon@redhat.com> writes:

Phil> I've not changed very much: renamed the files, re-ordered the
Phil> Makefile.in and made some minor code changes so that it compiles.

Thanks for doing this.

I skimmed through it.  Some of the formatting is weird, maybe due to
wrapping in the original posts?  Anyway, be sure to fix all that up.

It still seems like a lot of code to define a new event.  But I think we
will just live with that.  Or maybe there is some way to reduce its
size, through macros or something.  There seems to be a fair amount of
boilerplate.

There are places where the error-checking is not correct.  E.g.,
emit_breakpoint_stop_event calls PyObject_CallObject but does not check
its return value.  (FWIW I think that errors in events should be
reported and then ignored -- not propagate.)

I see new attributes like "stop_eventregistry".  I think we should drop
the "registry" part of these names.

I see that all the existing event registries are on the Thread object.
I think this is fine, but I think we will also want to add more.  In
particular:

* We want some way to determine that the entire inferior has exited.
* It seems logical to want to be able to put an event handler on a
  breakpoint, to notice when that breakpoint is hit.

There are probably more of these.  I don't mind if we add them as needed
-- but it would be nice if the first release incorporating the event
machinery were complete enough to enable some "nice" scripts.

I am not sure about all of the logic in emit_stop_event.  Is this a full
enumeration of stop reasons?  Also I am unsure about python_thread_exit.
Looking at $_exitcode seems strange -- a thread doesn't really have an
exit code, only the inferior as a whole does.

One place to look for ideas here is how MI does it...


I'm afraid there will probably be more things once the above are fixed
up.  Due to the formatting and lack of docs, this patch was sort of
difficult to read.  But, I think the basics are ok.

Tom

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

* Re: Python inferior control
  2010-08-13 14:54 Python inferior control Phil Muldoon
  2010-08-13 19:49 ` Tom Tromey
@ 2010-08-15 17:42 ` Richard Ward
  2010-08-26 20:23   ` Tom Tromey
  2010-08-25 16:10 ` Phil Muldoon
  2010-12-01 18:58 ` sami wagiaalla
  3 siblings, 1 reply; 10+ messages in thread
From: Richard Ward @ 2010-08-15 17:42 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: archer, oguzkayral

> On the 23rd of August 2009 Oguz Kayral submitted an initial patch to
> implement GDB inferior notification events in Python.

At the time I sent this (from a different email):

On 24 September 2009 02:52, Richard Ward <richard.j.ward1@googlemail.com> wrote:
> Oguz Kayral wrote:
>>
>> Hi,
>> This patch series adds inferior event handling support to GDB Python
>> scripting.
>
> Hi Oguz, I've been looking forward to this functionality, Good stuff!
>
> I have a few comments though, if you don't mind.
>
>
> Firstly two (fairly  unimportant) things about the function registration.
>
> I think it would be nice if you could give upvalues to the registration
> function (similar to gobject's `connect'), though admittedly it is very easy
> to fake that in python using a class that defines __call__.
>
> Also, I'm not sure whether this would ever be an issue but it seems
> advantageous to have the registration function return a unique object or
> number that could subsequently be used to unregister your callable, rather
> than using the callable object itself.
>
>
> Next, in python-stopevent.c:
> emit_stop_event (struct bpstats *bs, const char *stop_signal)
> {
>  /*...snip...*/
>  for (i = 0; i < PyList_Size (callback_list); i++)
>    {
>      PyObject_CallObject (PyList_GET_ITEM (callback_list, i), args_tuple);
>    }
> }
>
> A couple of issues with this. First, PyObject_Callback returns a new
> reference which is the return value of the function (or NULL), so it must be
> handled otherwise it will leak.
>
> Secondly the user code may throw an exception, or the object may not be
> callable. The exception should be cleared, and it would be nice to also
> print the exception (PyErr_Print does both).
>
> Most important here though is the iteration through the list. If the user
> disconnects a callback from inside a callback then the some callbacks could
> be skipped. It could be better to copy the list first, but that could still
> lead to some confusing behaviour, for example a callback being called after
> the user thinks it ought to have been disconnected.
>
> Thanks,
> Richard

I think on reflection that copying the list is probably the sensible way to go.

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

* Re: Python inferior control
  2010-08-13 14:54 Python inferior control Phil Muldoon
  2010-08-13 19:49 ` Tom Tromey
  2010-08-15 17:42 ` Richard Ward
@ 2010-08-25 16:10 ` Phil Muldoon
  2010-12-01 18:58 ` sami wagiaalla
  3 siblings, 0 replies; 10+ messages in thread
From: Phil Muldoon @ 2010-08-25 16:10 UTC (permalink / raw)
  To: archer, oguzkayral

On 13/08/10 15:54, Phil Muldoon wrote:
> Hi,
> 
> On the 23rd of August 2009 Oguz Kayral submitted an initial patch to
> implement GDB inferior notification events in Python.  Since then the
> patch has bit-rotted somewhat.  I've reconstituted this patch
> against current GDB head and attached it.  I've not changed very much:
> renamed the files, re-ordered the Makefile.in and made some minor code
> changes so that it compiles.

I talked with Oguz on external #gdb on freenode this week.  We had a
good chat about the current state of this code.  It turns out there
was a branch, but there are no substantive differences between this
(email) patch and the patch checked into that branch.  Anyway here is
what was disused:

* Oguz will create a new branch based on the current CVS.

* Oguz Will update the patches and apply to that branch. 

* There was some feedback and suggestions that were chatted about other
  than in email, so Oguz wants to implement those too.

Oguz,

Can you reply here with the name of the branch?

What about schedule? I'd like to collaborate as much as possible. I
can't really do that until the first two items above are done.  When
do you think you will that done? 

If we could get these patches approved and checked into the CVS
repository well before 7.3 that would be awesome!

Cheers,

Phil

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

* Re: Python inferior control
  2010-08-13 19:49 ` Tom Tromey
@ 2010-08-26 15:02   ` Oguz Kayral
  2010-08-26 20:28     ` Tom Tromey
  0 siblings, 1 reply; 10+ messages in thread
From: Oguz Kayral @ 2010-08-26 15:02 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Phil Muldoon, archer

On 13 August 2010 21:49, Tom Tromey <tromey@redhat.com> wrote:
> It still seems like a lot of code to define a new event.  But I think we
> will just live with that.  Or maybe there is some way to reduce its
> size, through macros or something.  There seems to be a fair amount of
> boilerplate.

This bothers me too, very little work is done with a lot of code.
Actually creating an event is straightforward but it requires coding
custom constructors, getter/setters, emit functions everytime. What
can we do to make this easier?

> I see new attributes like "stop_eventregistry".  I think we should drop
> the "registry" part of these names.

(not specific to stop, applies for all events.)
A stop_eventregistry is not a stop_event. A stop_eventregistry
contains the functions to be called when the inferior stops, a
stop_event contains information about the event(stop_reason etc.). We
can drop it if we can find a way to avoid confusion.

> I see that all the existing event registries are on the Thread object.
> I think this is fine, but I think we will also want to add more.  In
> particular:
> * We want some way to determine that the entire inferior has exited.

We decided to concentrate on thread events during GSoC. Please bring
out any events that you can think of so I can add them.

> * It seems logical to want to be able to put an event handler on a
>  breakpoint, to notice when that breakpoint is hit.

Can't breakpoint_stop_event already do this? I think it does *lack of docs* :-)

> There are probably more of these.  I don't mind if we add them as needed
> -- but it would be nice if the first release incorporating the event
> machinery were complete enough to enable some "nice" scripts.
>
> I am not sure about all of the logic in emit_stop_event.  Is this a full
> enumeration of stop reasons?  Also I am unsure about python_thread_exit.
> Looking at $_exitcode seems strange -- a thread doesn't really have an
> exit code, only the inferior as a whole does.
>
> One place to look for ideas here is how MI does it...

The idea originally came from MI but it's wrong. Thanks for pointing this out.

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

* Re: Python inferior control
  2010-08-15 17:42 ` Richard Ward
@ 2010-08-26 20:23   ` Tom Tromey
  0 siblings, 0 replies; 10+ messages in thread
From: Tom Tromey @ 2010-08-26 20:23 UTC (permalink / raw)
  To: Richard Ward; +Cc: Phil Muldoon, archer, oguzkayral

Richard> At the time I sent this (from a different email):

... I just wanted to make sure this didn't go un-replied-to.

Richard> I think on reflection that copying the list is probably the
Richard> sensible way to go.

Me too.

Tom

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

* Re: Python inferior control
  2010-08-26 15:02   ` Oguz Kayral
@ 2010-08-26 20:28     ` Tom Tromey
  2010-09-20 16:13       ` Matt Rice
  0 siblings, 1 reply; 10+ messages in thread
From: Tom Tromey @ 2010-08-26 20:28 UTC (permalink / raw)
  To: Oguz Kayral; +Cc: Phil Muldoon, archer

>>>>> "Oguz" == Oguz Kayral <oguzkayral@gmail.com> writes:

First, thanks for looking at this again.  This is a very important
feature; if you look at the Python API to-do list I wrote up recently,
this feature blocks any number of other nice projects... so I am very
eager to see it in the tree.

Tom> It still seems like a lot of code to define a new event.  But I think we
Tom> will just live with that.  Or maybe there is some way to reduce its
Tom> size, through macros or something.  There seems to be a fair amount of
Tom> boilerplate.

Oguz> This bothers me too, very little work is done with a lot of code.
Oguz> Actually creating an event is straightforward but it requires coding
Oguz> custom constructors, getter/setters, emit functions everytime. What
Oguz> can we do to make this easier?

I came up with two ideas.  Maybe there are more.


One is to just have a generic gdb.Event type.  It would act as a basic
wrapper around a dictionary.  A module in gdb that wants to generate an
event would make a dictionary and wrap an Event around it.

This would mean that different kinds of events would not be
differentiated by type.  To make this less troublesome we could add a
"type" field that would describe the event.


Another approach would be to take this same idea and extend it a little
to provide real event classes.  I think this could be done by having an
Event base class, as above, then individual subclasses which don't
provide any additional behavior.  Then the class objects themselves
could be wrapped up in C macros to make their definitions very short.


I don't have a very strong preference.  It seems safe to start with the
first and move to the second if needed.

Tom> I see new attributes like "stop_eventregistry".  I think we should drop
Tom> the "registry" part of these names.

Oguz> (not specific to stop, applies for all events.)
Oguz> A stop_eventregistry is not a stop_event. A stop_eventregistry
Oguz> contains the functions to be called when the inferior stops, a
Oguz> stop_event contains information about the event(stop_reason etc.). We
Oguz> can drop it if we can find a way to avoid confusion.

I don't think there will be much confusion if the registry name is
similar to the class name of the event that it emits.  I think this is
pretty typical in other frameworks.

In Gtk you write something like:

    object.connect ("clicked", method)

In GDB you will write something like:

    object.stop_event.connect (method)

Or am I confused about how this works?

Oguz> We decided to concentrate on thread events during GSoC. Please bring
Oguz> out any events that you can think of so I can add them.

No problem.  And FWIW I think it is completely ok for us to start with
what you wrote and add events as we go.  Actually, I would prefer that
approach.

Tom> * It seems logical to want to be able to put an event handler on a
Tom>  breakpoint, to notice when that breakpoint is hit.

Oguz> Can't breakpoint_stop_event already do this? I think it does *lack
Oguz> of docs* :-)

It seems to me that you might want to watch a Thread for stops, or you
might want to watch a Breakpoint.  You can achieve the latter by
watching for all stop events and then filtering -- but it seems nicer
for the user if gdb just provides the functionality directly:

    bpt = Breakpoint (...)
    bpt.stop_event.connect (callback)


And, yeah, docs and test cases are necessary.

Tom

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

* Re: Python inferior control
  2010-08-26 20:28     ` Tom Tromey
@ 2010-09-20 16:13       ` Matt Rice
  2010-09-21 21:48         ` Tom Tromey
  0 siblings, 1 reply; 10+ messages in thread
From: Matt Rice @ 2010-09-20 16:13 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Oguz Kayral, Phil Muldoon, archer

On Thu, Aug 26, 2010 at 1:28 PM, Tom Tromey <tromey@redhat.com> wrote:
>>>>>> "Oguz" == Oguz Kayral <oguzkayral@gmail.com> writes:
>
> Oguz>  What can we do to make this easier?
>
> I came up with two ideas.  Maybe there are more.
>
>
> One is to just have a generic gdb.Event type.  It would act as a basic
> wrapper around a dictionary.  A module in gdb that wants to generate an
> event would make a dictionary and wrap an Event around it.
>
> This would mean that different kinds of events would not be
> differentiated by type.  To make this less troublesome we could add a
> "type" field that would describe the event.

I like this approach,

> Tom> I see new attributes like "stop_eventregistry".  I think we should drop
> Tom> the "registry" part of these names.
>
> Oguz> (not specific to stop, applies for all events.)
> Oguz> A stop_eventregistry is not a stop_event. A stop_eventregistry
> Oguz> contains the functions to be called when the inferior stops, a
> Oguz> stop_event contains information about the event(stop_reason etc.). We
> Oguz> can drop it if we can find a way to avoid confusion.
>
> I don't think there will be much confusion if the registry name is
> similar to the class name of the event that it emits.  I think this is
> pretty typical in other frameworks.
>
> In Gtk you write something like:
>
>    object.connect ("clicked", method)
>
> In GDB you will write something like:
>
>    object.stop_event.connect (method)
>
> Or am I confused about how this works?

i'm late to the party, nor do i really know python,
with the simplified event dictionary tromey describes, and the type
flag to go with it, you could just use a single stack/linked list to
push/pop all types of events onto,

 and maybe a way to mask which events get pushed if frequency of
events is a problem, maybe incrementing/decrementing a per-event type
counter when events are added/removed so it could avoid looking for
events that aren't there.

this would allow you to easily add and remove event types without
creating a specific registry and allow one to easily figure out which
order the events occured in,  (e.g. was the last stopped || running
event a stopped or a running event?) or serialize the event stream so
you could e.g. check if subsequent runs produce the same events
without implementing all of the callbacks.

so in general what i was thinking would look like this

head->filter (list of event types that will be added or that will be ignored)
head->bill_of_materials (event type/count to be incremented when
pushing/popping)
head->list_of_events or something...

a callback mechanism could be added on top of this,
and filter/bill_of_materials need only be implemented if (event
frequency-event desire) is high

i'd think it'd need to be walkable in order to implement peeking of
events without removing.

is this stuff on a branch somewhere?

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

* Re: Python inferior control
  2010-09-20 16:13       ` Matt Rice
@ 2010-09-21 21:48         ` Tom Tromey
  0 siblings, 0 replies; 10+ messages in thread
From: Tom Tromey @ 2010-09-21 21:48 UTC (permalink / raw)
  To: Matt Rice; +Cc: Oguz Kayral, Phil Muldoon, archer

Matt> with the simplified event dictionary tromey describes, and the type
Matt> flag to go with it, you could just use a single stack/linked list to
Matt> push/pop all types of events onto,

Interesting idea.

Alternatively, we could have an "any_event" source.  I suspect most
event receivers will only want to connect to a particular source.

Matt> is this stuff on a branch somewhere?

Just gsoc-kayral-python.  I think that is rather old.
Phil prepared a RFC patch, but AFAIK that isn't committed anywhere.

Tom

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

* Re: Python inferior control
  2010-08-13 14:54 Python inferior control Phil Muldoon
                   ` (2 preceding siblings ...)
  2010-08-25 16:10 ` Phil Muldoon
@ 2010-12-01 18:58 ` sami wagiaalla
  3 siblings, 0 replies; 10+ messages in thread
From: sami wagiaalla @ 2010-12-01 18:58 UTC (permalink / raw)
  To: archer



On 08/13/2010 10:54 AM, Phil Muldoon wrote:
> Hi,
>
> On the 23rd of August 2009 Oguz Kayral submitted an initial patch to
> implement GDB inferior notification events in Python.  Since then the
> patch has bit-rotted somewhat.  I've reconstituted this patch
> against current GDB head and attached it.  I've not changed very much:
> renamed the files, re-ordered the Makefile.in and made some minor code
> changes so that it compiles.
>

I have started looking at this with the purpose of getting Oguz's work 
upstream. I stated by removing bit rot from the patch that phil posted, 
and making my own modifications to get things to conform to GDB coding 
standards. I have also started addressing some of the issues that where 
brought up on this thread and in reply to Oguz's original posts.

You can follow my progress on this branch on the archer repository:

   archer-swagiaal-oguz

When I am finished I will reply to the emails here and post the patch on 
gdb-patches so we can continue the discussion there.

Sami

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

end of thread, other threads:[~2010-12-01 18:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-13 14:54 Python inferior control Phil Muldoon
2010-08-13 19:49 ` Tom Tromey
2010-08-26 15:02   ` Oguz Kayral
2010-08-26 20:28     ` Tom Tromey
2010-09-20 16:13       ` Matt Rice
2010-09-21 21:48         ` Tom Tromey
2010-08-15 17:42 ` Richard Ward
2010-08-26 20:23   ` Tom Tromey
2010-08-25 16:10 ` Phil Muldoon
2010-12-01 18:58 ` sami wagiaalla

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