public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tom@tromey.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tom@tromey.com>
Subject: [PATCH v4 11/11] Use run_on_main_thread in gdb.post_event
Date: Tue, 01 Oct 2019 20:12:00 -0000	[thread overview]
Message-ID: <20191001201227.8519-12-tom@tromey.com> (raw)
In-Reply-To: <20191001201227.8519-1-tom@tromey.com>

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.

gdb/ChangeLog
2019-10-01  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.
---
 gdb/ChangeLog       |   8 +++
 gdb/python/python.c | 131 +++++++++++++++++++++-----------------------
 2 files changed, 70 insertions(+), 69 deletions(-)

diff --git a/gdb/python/python.c b/gdb/python/python.c
index ddf0e72d26f..1e054578900 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -28,7 +28,6 @@
 #include "value.h"
 #include "language.h"
 #include "event-loop.h"
-#include "serial.h"
 #include "readline/tilde.h"
 #include "python.h"
 #include "extension-priv.h"
@@ -940,63 +939,81 @@ gdbpy_source_script (const struct extension_language_defn *extlang,
 
 /* 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.  */
 struct gdbpy_event
 {
-  /* The Python event.  This is just a callable object.  */
-  PyObject *event;
-  /* The next event.  */
-  struct gdbpy_event *next;
-};
+  gdbpy_event (gdbpy_ref<> &&func)
+    : m_func (func.release ())
+  {
+  }
 
-/* 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;
+  gdbpy_event (gdbpy_event &&other)
+    : m_func (other.m_func)
+  {
+    other.m_func = nullptr;
+  }
 
-/* So that we can wake up the main thread even when it is blocked in
-   poll().  */
-static struct serial_event *gdbpy_serial_event;
+  gdbpy_event (const gdbpy_event &other)
+    : m_func (other.m_func)
+  {
+    gdbpy_gil gil;
+    Py_XINCREF (m_func);
+  }
 
-/* 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.  */
+  ~gdbpy_event ()
+  {
+    gdbpy_gil gil;
+    Py_XDECREF (m_func);
+  }
 
-static void
-gdbpy_run_events (int error, gdb_client_data client_data)
-{
-  gdbpy_enter enter_py (get_current_arch (), current_language);
+  gdbpy_event &operator= (const gdbpy_event &other) = delete;
 
-  /* 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);
+  void operator() ()
+  {
+    gdbpy_enter enter_py (get_current_arch (), current_language);
 
-  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 ();
+    gdbpy_ref<> call_result (PyObject_CallObject (m_func, NULL));
+    if (call_result == NULL)
+      gdbpy_print_stack ();
+  }
 
-      Py_DECREF (item->event);
-      xfree (item);
-    }
-}
+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;
+};
 
 /* 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;
@@ -1010,36 +1027,13 @@ gdbpy_post_event (PyObject *self, PyObject *args)
 
   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)
-    serial_event_set (gdbpy_serial_event);
+  gdbpy_ref<> func_ref = gdbpy_ref<>::new_reference (func);
+  gdbpy_event event (std::move (func_ref));
+  run_on_main_thread (event);
 
   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;
-}
-
 \f
 
 /* This is the extension_language_ops.before_prompt "method".  */
@@ -1704,7 +1698,6 @@ do_start_initialization ()
       || gdbpy_initialize_linetable () < 0
       || gdbpy_initialize_thread () < 0
       || gdbpy_initialize_inferior () < 0
-      || gdbpy_initialize_events () < 0
       || gdbpy_initialize_eventregistry () < 0
       || gdbpy_initialize_py_events () < 0
       || gdbpy_initialize_event () < 0
-- 
2.17.2

  parent reply	other threads:[~2019-10-01 20:12 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-01 20:16 [PATCH v4 00/11] Demangle minimal symbol names in worker threads Tom Tromey
2019-10-01 20:12 ` [PATCH v4 04/11] Add RAII class for blocking gdb signals Tom Tromey
2019-10-01 20:12 ` [PATCH v4 09/11] Demangle minsyms in parallel Tom Tromey
2019-10-01 20:12 ` [PATCH v4 10/11] Add maint set/show max-worker-threads Tom Tromey
2019-10-02 14:54   ` Eli Zaretskii
2019-10-01 20:12 ` [PATCH v4 08/11] Introduce thread-safe way to handle SIGSEGV Tom Tromey
2019-10-01 20:12 ` [PATCH v4 01/11] Use m4_include, not sinclude in .m4 files Tom Tromey
2019-10-01 20:12 ` [PATCH v4 03/11] Add configure check for std::thread Tom Tromey
2019-10-01 20:12 ` [PATCH v4 05/11] Introduce alternate_signal_stack RAII class Tom Tromey
2019-10-01 20:12 ` [PATCH v4 07/11] Introduce run_on_main_thread Tom Tromey
2019-10-01 20:12 ` Tom Tromey [this message]
2019-10-01 20:16 ` [PATCH v4 02/11] Defer minimal symbol name-setting Tom Tromey
2019-10-01 20:16 ` [PATCH v4 06/11] Lock the demangled hash table Tom Tromey
2019-10-06 22:34 ` [PATCH v4 00/11] Demangle minimal symbol names in worker threads Christian Biesinger via gdb-patches
2019-10-07  0:58   ` Tom Tromey
2019-10-08  2:01     ` Christian Biesinger via gdb-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191001201227.8519-12-tom@tromey.com \
    --to=tom@tromey.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).