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:
parent
7346b668d7
commit
ca5c20b6d3
6 changed files with 184 additions and 0 deletions
|
@ -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." },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue