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.
This commit is contained in:
Phil Muldoon 2010-08-11 20:54:12 +00:00
parent 7346b668d7
commit ca5c20b6d3
6 changed files with 184 additions and 0 deletions

View file

@ -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." },