aboutsummaryrefslogtreecommitdiff
path: root/gdb/python/python.c
diff options
context:
space:
mode:
authorPhil Muldoon <pmuldoon@redhat.com>2010-08-11 20:54:12 +0000
committerPhil Muldoon <pmuldoon@redhat.com>2010-08-11 20:54:12 +0000
commitca5c20b6d32018c05a1c20a099a71137b4b27a4d (patch)
tree482c9088571e90381ebc0739179e47c8e3c0f1f8 /gdb/python/python.c
parent7346b668d73fe13b9b07b805379ff0e03d3aef5e (diff)
downloadgdb-ca5c20b6d32018c05a1c20a099a71137b4b27a4d.zip
gdb-ca5c20b6d32018c05a1c20a099a71137b4b27a4d.tar.gz
gdb-ca5c20b6d32018c05a1c20a099a71137b4b27a4d.tar.bz2
2010-08-11 Tom Tromey <tromey@redhat.com>
Phil Muldoon <pmuldoon@redhat.com> * python/python.c (gdbpy_run_events): New function. (gdbpy_post_event): Likewise. (gdbpy_initialize_events): Likewise. (_initialize_python): Call gdbpy_initialize_events. 2010-08-11 Tom Tromey <tromey@redhat.com> Phil Muldoon <pmuldoon@redhat.com> * gdb.texinfo (Basic Python): Describe post_event API. 2010-08-11 Phil Muldoon <pmuldoon@redhat.com> * gdb.python/python.exp (gdb_py_test_multiple): Add gdb.post_event tests.
Diffstat (limited to 'gdb/python/python.c')
-rw-r--r--gdb/python/python.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 16c3cba..030b142 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -28,6 +28,7 @@
#include "value.h"
#include "language.h"
#include "exceptions.h"
+#include "event-loop.h"
#include <ctype.h>
@@ -548,6 +549,114 @@ source_python_script (FILE *stream, const char *file)
+/* Posting and handling events. */
+
+/* A single event. */
+struct gdbpy_event
+{
+ /* The Python event. This is just a callable object. */
+ PyObject *event;
+ /* The next event. */
+ struct gdbpy_event *next;
+};
+
+/* All pending events. */
+static struct gdbpy_event *gdbpy_event_list;
+/* The final link of the event list. */
+static struct gdbpy_event **gdbpy_event_list_end;
+
+/* We use a file handler, and not an async handler, so that we can
+ wake up the main thread even when it is blocked in poll(). */
+static int gdbpy_event_fds[2];
+
+/* The file handler callback. This reads from the internal pipe, and
+ then processes the Python event queue. This will always be run in
+ the main gdb thread. */
+static void
+gdbpy_run_events (int err, gdb_client_data ignore)
+{
+ struct cleanup *cleanup;
+ char buffer[100];
+ int r;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ /* Just read whatever is available on the fd. It is relatively
+ harmless if there are any bytes left over. */
+ r = read (gdbpy_event_fds[0], buffer, sizeof (buffer));
+
+ while (gdbpy_event_list)
+ {
+ /* Dispatching the event might push a new element onto the event
+ loop, so we update here "atomically enough". */
+ struct gdbpy_event *item = gdbpy_event_list;
+ gdbpy_event_list = gdbpy_event_list->next;
+ if (gdbpy_event_list == NULL)
+ gdbpy_event_list_end = &gdbpy_event_list;
+
+ /* Ignore errors. */
+ if (PyObject_CallObject (item->event, NULL) == NULL)
+ PyErr_Clear ();
+
+ Py_DECREF (item->event);
+ xfree (item);
+ }
+
+ do_cleanups (cleanup);
+}
+
+/* Submit an event to the gdb thread. */
+static PyObject *
+gdbpy_post_event (PyObject *self, PyObject *args)
+{
+ struct gdbpy_event *event;
+ PyObject *func;
+ int wakeup;
+
+ if (!PyArg_ParseTuple (args, "O", &func))
+ return NULL;
+
+ if (!PyCallable_Check (func))
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Posted event is not callable"));
+ return NULL;
+ }
+
+ Py_INCREF (func);
+
+ /* From here until the end of the function, we have the GIL, so we
+ can operate on our global data structures without worrying. */
+ wakeup = gdbpy_event_list == NULL;
+
+ event = XNEW (struct gdbpy_event);
+ event->event = func;
+ event->next = NULL;
+ *gdbpy_event_list_end = event;
+ gdbpy_event_list_end = &event->next;
+
+ /* Wake up gdb when needed. */
+ if (wakeup)
+ {
+ char c = 'q'; /* Anything. */
+ if (write (gdbpy_event_fds[1], &c, 1) != 1)
+ return PyErr_SetFromErrno (PyExc_IOError);
+ }
+
+ Py_RETURN_NONE;
+}
+
+/* Initialize the Python event handler. */
+static void
+gdbpy_initialize_events (void)
+{
+ if (!pipe (gdbpy_event_fds))
+ {
+ gdbpy_event_list_end = &gdbpy_event_list;
+ add_file_handler (gdbpy_event_fds[0], gdbpy_run_events, NULL);
+ }
+}
+
/* Printing. */
/* A python function to write a single string using gdb's filtered
@@ -854,6 +963,7 @@ Enables or disables printing of Python stack traces."),
gdbpy_initialize_lazy_string ();
gdbpy_initialize_thread ();
gdbpy_initialize_inferior ();
+ gdbpy_initialize_events ();
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");
@@ -974,6 +1084,9 @@ gdb.Symtab_and_line objects (or None)."},
Parse String as an expression, evaluate it, and return the result as a Value."
},
+ { "post_event", gdbpy_post_event, METH_VARARGS,
+ "Post an event into gdb's event loop." },
+
{ "target_charset", gdbpy_target_charset, METH_NOARGS,
"target_charset () -> string.\n\
Return the name of the current target charset." },