Use run_on_main_thread in gdb.post_event
This changes gdb.post_event to use the new run_on_main_thread function. This is somewhat tricky because the Python GIL must be held while manipulating reference counts. 2019-11-26 Tom Tromey <tom@tromey.com> * python/python.c (class gdbpy_gil): New. (struct gdbpy_event): Add constructor, destructor, operator(). (gdbpy_post_event): Use run_on_main_thread. (gdbpy_initialize_events): Remove. (do_start_initialization): Update. Change-Id: Ie4431e60f328dae48bd96b6c6a8e875e70bda1de
This commit is contained in:
parent
22138db609
commit
971db5e21e
2 changed files with 77 additions and 78 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2019-11-26 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
|
* python/python.c (class gdbpy_gil): New.
|
||||||
|
(struct gdbpy_event): Add constructor, destructor, operator().
|
||||||
|
(gdbpy_post_event): Use run_on_main_thread.
|
||||||
|
(gdbpy_initialize_events): Remove.
|
||||||
|
(do_start_initialization): Update.
|
||||||
|
|
||||||
2019-11-26 Tom Tromey <tom@tromey.com>
|
2019-11-26 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
* NEWS: Add entry.
|
* NEWS: Add entry.
|
||||||
|
|
|
@ -28,14 +28,13 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "language.h"
|
#include "language.h"
|
||||||
#include "event-loop.h"
|
#include "event-loop.h"
|
||||||
#include "serial.h"
|
|
||||||
#include "readline/tilde.h"
|
#include "readline/tilde.h"
|
||||||
#include "python.h"
|
#include "python.h"
|
||||||
#include "extension-priv.h"
|
#include "extension-priv.h"
|
||||||
#include "cli/cli-utils.h"
|
#include "cli/cli-utils.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "location.h"
|
#include "location.h"
|
||||||
#include "ser-event.h"
|
#include "run-on-main-thread.h"
|
||||||
|
|
||||||
/* Declared constants and enum for python stack printing. */
|
/* Declared constants and enum for python stack printing. */
|
||||||
static const char python_excp_none[] = "none";
|
static const char python_excp_none[] = "none";
|
||||||
|
@ -940,63 +939,81 @@ gdbpy_source_script (const struct extension_language_defn *extlang,
|
||||||
|
|
||||||
/* Posting and handling events. */
|
/* Posting and handling events. */
|
||||||
|
|
||||||
|
/* A helper class to save and restore the GIL, but without touching
|
||||||
|
the other globals that are handled by gdbpy_enter. */
|
||||||
|
|
||||||
|
class gdbpy_gil
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
gdbpy_gil ()
|
||||||
|
: m_state (PyGILState_Ensure ())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~gdbpy_gil ()
|
||||||
|
{
|
||||||
|
PyGILState_Release (m_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
DISABLE_COPY_AND_ASSIGN (gdbpy_gil);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
PyGILState_STATE m_state;
|
||||||
|
};
|
||||||
|
|
||||||
/* A single event. */
|
/* A single event. */
|
||||||
struct gdbpy_event
|
struct gdbpy_event
|
||||||
{
|
{
|
||||||
/* The Python event. This is just a callable object. */
|
gdbpy_event (gdbpy_ref<> &&func)
|
||||||
PyObject *event;
|
: m_func (func.release ())
|
||||||
/* The next event. */
|
{
|
||||||
struct gdbpy_event *next;
|
}
|
||||||
|
|
||||||
|
gdbpy_event (gdbpy_event &&other)
|
||||||
|
: m_func (other.m_func)
|
||||||
|
{
|
||||||
|
other.m_func = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdbpy_event (const gdbpy_event &other)
|
||||||
|
: m_func (other.m_func)
|
||||||
|
{
|
||||||
|
gdbpy_gil gil;
|
||||||
|
Py_XINCREF (m_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
~gdbpy_event ()
|
||||||
|
{
|
||||||
|
gdbpy_gil gil;
|
||||||
|
Py_XDECREF (m_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
gdbpy_event &operator= (const gdbpy_event &other) = delete;
|
||||||
|
|
||||||
|
void operator() ()
|
||||||
|
{
|
||||||
|
gdbpy_enter enter_py (get_current_arch (), current_language);
|
||||||
|
|
||||||
|
gdbpy_ref<> call_result (PyObject_CallObject (m_func, NULL));
|
||||||
|
if (call_result == NULL)
|
||||||
|
gdbpy_print_stack ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* The Python event. This is just a callable object. Note that
|
||||||
|
this is not a gdbpy_ref<>, because we have to take particular
|
||||||
|
care to only destroy the reference when holding the GIL. */
|
||||||
|
PyObject *m_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* So that we can wake up the main thread even when it is blocked in
|
|
||||||
poll(). */
|
|
||||||
static struct serial_event *gdbpy_serial_event;
|
|
||||||
|
|
||||||
/* 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 error, gdb_client_data client_data)
|
|
||||||
{
|
|
||||||
gdbpy_enter enter_py (get_current_arch (), current_language);
|
|
||||||
|
|
||||||
/* Clear the event fd. Do this before flushing the events list, so
|
|
||||||
that any new event post afterwards is sure to re-awake the event
|
|
||||||
loop. */
|
|
||||||
serial_event_clear (gdbpy_serial_event);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
gdbpy_ref<> call_result (PyObject_CallObject (item->event, NULL));
|
|
||||||
if (call_result == NULL)
|
|
||||||
gdbpy_print_stack ();
|
|
||||||
|
|
||||||
Py_DECREF (item->event);
|
|
||||||
xfree (item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Submit an event to the gdb thread. */
|
/* Submit an event to the gdb thread. */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
gdbpy_post_event (PyObject *self, PyObject *args)
|
gdbpy_post_event (PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
struct gdbpy_event *event;
|
|
||||||
PyObject *func;
|
PyObject *func;
|
||||||
int wakeup;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple (args, "O", &func))
|
if (!PyArg_ParseTuple (args, "O", &func))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1008,38 +1025,13 @@ gdbpy_post_event (PyObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_INCREF (func);
|
gdbpy_ref<> func_ref = gdbpy_ref<>::new_reference (func);
|
||||||
|
gdbpy_event event (std::move (func_ref));
|
||||||
/* From here until the end of the function, we have the GIL, so we
|
run_on_main_thread (event);
|
||||||
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)
|
|
||||||
serial_event_set (gdbpy_serial_event);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the Python event handler. */
|
|
||||||
static int
|
|
||||||
gdbpy_initialize_events (void)
|
|
||||||
{
|
|
||||||
gdbpy_event_list_end = &gdbpy_event_list;
|
|
||||||
|
|
||||||
gdbpy_serial_event = make_serial_event ();
|
|
||||||
add_file_handler (serial_event_fd (gdbpy_serial_event),
|
|
||||||
gdbpy_run_events, NULL);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* This is the extension_language_ops.before_prompt "method". */
|
/* This is the extension_language_ops.before_prompt "method". */
|
||||||
|
@ -1704,7 +1696,6 @@ do_start_initialization ()
|
||||||
|| gdbpy_initialize_linetable () < 0
|
|| gdbpy_initialize_linetable () < 0
|
||||||
|| gdbpy_initialize_thread () < 0
|
|| gdbpy_initialize_thread () < 0
|
||||||
|| gdbpy_initialize_inferior () < 0
|
|| gdbpy_initialize_inferior () < 0
|
||||||
|| gdbpy_initialize_events () < 0
|
|
||||||
|| gdbpy_initialize_eventregistry () < 0
|
|| gdbpy_initialize_eventregistry () < 0
|
||||||
|| gdbpy_initialize_py_events () < 0
|
|| gdbpy_initialize_py_events () < 0
|
||||||
|| gdbpy_initialize_event () < 0
|
|| gdbpy_initialize_event () < 0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue