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
|
@ -1,3 +1,11 @@
|
||||||
|
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 Ken Werner <ken.werner@de.ibm.com>
|
2010-08-11 Ken Werner <ken.werner@de.ibm.com>
|
||||||
|
|
||||||
* gdb/valarith.c (vector_binop): New function.
|
* gdb/valarith.c (vector_binop): New function.
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
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>
|
2010-08-11 Phil Muldoon <pmuldoon@redhat.com>
|
||||||
|
|
||||||
* gdb.texinfo (Basic Python): Describe solib_address and
|
* gdb.texinfo (Basic Python): Describe solib_address and
|
||||||
|
|
|
@ -20525,6 +20525,45 @@ compute values, for example, it is the only way to get the value of a
|
||||||
convenience variable (@pxref{Convenience Vars}) as a @code{gdb.Value}.
|
convenience variable (@pxref{Convenience Vars}) as a @code{gdb.Value}.
|
||||||
@end defun
|
@end defun
|
||||||
|
|
||||||
|
@findex gdb.post_event
|
||||||
|
@defun post_event event
|
||||||
|
Put @var{event}, a callable object taking no arguments, into
|
||||||
|
@value{GDBN}'s internal event queue. This callable will be invoked at
|
||||||
|
some later point, during @value{GDBN}'s event processing. Events
|
||||||
|
posted using @code{post_event} will be run in the order in which they
|
||||||
|
were posted; however, there is no way to know when they will be
|
||||||
|
processed relative to other events inside @value{GDBN}.
|
||||||
|
|
||||||
|
@value{GDBN} is not thread-safe. If your Python program uses multiple
|
||||||
|
threads, you must be careful to only call @value{GDBN}-specific
|
||||||
|
functions in the main @value{GDBN} thread. @code{post_event} ensures
|
||||||
|
this. For example:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
(@value{GDBP}) python
|
||||||
|
>import threading
|
||||||
|
>
|
||||||
|
>class Writer():
|
||||||
|
> def __init__(self, message):
|
||||||
|
> self.message = message;
|
||||||
|
> def __call__(self):
|
||||||
|
> gdb.write(self.message)
|
||||||
|
>
|
||||||
|
>class MyThread1 (threading.Thread):
|
||||||
|
> def run (self):
|
||||||
|
> gdb.post_event(Writer("Hello "))
|
||||||
|
>
|
||||||
|
>class MyThread2 (threading.Thread):
|
||||||
|
> def run (self):
|
||||||
|
> gdb.post_event(Writer("World\n"))
|
||||||
|
>
|
||||||
|
>MyThread1().start()
|
||||||
|
>MyThread2().start()
|
||||||
|
>end
|
||||||
|
(@value{GDBP}) Hello World
|
||||||
|
@end smallexample
|
||||||
|
@end defun
|
||||||
|
|
||||||
@findex gdb.write
|
@findex gdb.write
|
||||||
@defun write string
|
@defun write string
|
||||||
Print a string to @value{GDBN}'s paginated standard output stream.
|
Print a string to @value{GDBN}'s paginated standard output stream.
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "language.h"
|
#include "language.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
|
#include "event-loop.h"
|
||||||
|
|
||||||
#include <ctype.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. */
|
/* Printing. */
|
||||||
|
|
||||||
/* A python function to write a single string using gdb's filtered
|
/* 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_lazy_string ();
|
||||||
gdbpy_initialize_thread ();
|
gdbpy_initialize_thread ();
|
||||||
gdbpy_initialize_inferior ();
|
gdbpy_initialize_inferior ();
|
||||||
|
gdbpy_initialize_events ();
|
||||||
|
|
||||||
PyRun_SimpleString ("import gdb");
|
PyRun_SimpleString ("import gdb");
|
||||||
PyRun_SimpleString ("gdb.pretty_printers = []");
|
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."
|
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", gdbpy_target_charset, METH_NOARGS,
|
||||||
"target_charset () -> string.\n\
|
"target_charset () -> string.\n\
|
||||||
Return the name of the current target charset." },
|
Return the name of the current target charset." },
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2010-08-11 Phil Muldoon <pmuldoon@redhat.com>
|
||||||
|
|
||||||
|
* gdb.python/python.exp (gdb_py_test_multiple): Add gdb.post_event
|
||||||
|
tests.
|
||||||
|
|
||||||
2010-08-11 Ken Werner <ken.werner@de.ibm.com>
|
2010-08-11 Ken Werner <ken.werner@de.ibm.com>
|
||||||
|
|
||||||
* gdb.base/Makefile.in (EXECUTABLES): Add gnu_vector.
|
* gdb.base/Makefile.in (EXECUTABLES): Add gnu_vector.
|
||||||
|
|
|
@ -120,6 +120,20 @@ gdb_test_no_output \
|
||||||
"python x = gdb.execute('printf \"%d\", 23', to_string = True)"
|
"python x = gdb.execute('printf \"%d\", 23', to_string = True)"
|
||||||
gdb_test "python print x" "23"
|
gdb_test "python print x" "23"
|
||||||
|
|
||||||
|
# Test post_event.
|
||||||
|
gdb_py_test_multiple "post event insertion" \
|
||||||
|
"python" "" \
|
||||||
|
"someVal = 0" "" \
|
||||||
|
"class Foo():" "" \
|
||||||
|
" def __call__(self):" "" \
|
||||||
|
" global someVal" "" \
|
||||||
|
" someVal += 1" "" \
|
||||||
|
"gdb.post_event(Foo())" "" \
|
||||||
|
"end" ""
|
||||||
|
|
||||||
|
gdb_test "python print someVal" "1" "test post event execution"
|
||||||
|
gdb_test "python gdb.post_event(str(1))" "RuntimeError: Posted event is not callable.*" "Test non callable class"
|
||||||
|
|
||||||
# Test (no) pagination of the executed command.
|
# Test (no) pagination of the executed command.
|
||||||
gdb_test "show height" {Number of lines gdb thinks are in a page is unlimited\.}
|
gdb_test "show height" {Number of lines gdb thinks are in a page is unlimited\.}
|
||||||
set lines 10
|
set lines 10
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue