Release the GIL while running a gdb command or expression
authorTom Tromey <tom@tromey.com>
Sat, 8 Sep 2018 02:02:21 +0000 (20:02 -0600)
committerTom Tromey <tom@tromey.com>
Wed, 30 Jan 2019 14:06:20 +0000 (07:06 -0700)
PR python/23615 points out that gdb.execute_gdb_command does not
release the Python GIL.  This means that, while the gdb command is
running, other Python threads do not run.

This patch solves the problem by introducing a new RAII class that can
be used to temporarily release and then re-acquire the GIL, then puts
this into the appropriate places in execute_gdb_command and
gdbpy_parse_and_eval.

This does not include a test case, because after some research I could
not find a way to write one that was not racy.

gdb/ChangeLog
2019-01-30  Tom Tromey  <tom@tromey.com>

PR python/23615:
* python/python.c (execute_gdb_command): Use gdbpy_allow_threads.
(gdbpy_parse_and_eval): Likewise.
* python/python-internal.h (gdbpy_allow_threads): New class.

gdb/ChangeLog
gdb/python/python-internal.h
gdb/python/python.c

index 5d5f72b8174c100742137dd4be6777a8c9152851..b06398ab33fdfd982680f71399a9adfb31e9905b 100644 (file)
@@ -1,3 +1,10 @@
+2019-01-30  Tom Tromey  <tom@tromey.com>
+
+       PR python/23615:
+       * python/python.c (execute_gdb_command): Use gdbpy_allow_threads.
+       (gdbpy_parse_and_eval): Likewise.
+       * python/python-internal.h (gdbpy_allow_threads): New class.
+
 2019-01-28  John Baldwin  <jhb@FreeBSD.org>
 
        * aarch64-fbsd-tdep.c (aarch64_fbsd_gregmap)
index b5d9840eb74e1c78dc23725f3af10af766d81654..b157d22aa1f59b12359b7cab2e448d527b2e97e4 100644 (file)
@@ -684,6 +684,31 @@ class gdbpy_enter_varobj : public gdbpy_enter
 
 };
 
+/* The opposite of gdb_enter: this releases the GIL around a region,
+   allowing other Python threads to run.  No Python APIs may be used
+   while this is active.  */
+class gdbpy_allow_threads
+{
+public:
+
+  gdbpy_allow_threads ()
+    : m_save (PyEval_SaveThread ())
+  {
+    gdb_assert (m_save != nullptr);
+  }
+
+  ~gdbpy_allow_threads ()
+  {
+    PyEval_RestoreThread (m_save);
+  }
+
+  DISABLE_COPY_AND_ASSIGN (gdbpy_allow_threads);
+
+private:
+
+  PyThreadState *m_save;
+};
+
 extern struct gdbarch *python_gdbarch;
 extern const struct language_defn *python_language;
 
index b23aede1cdcabbf13090b697fc47b81576f8f38d..c23db2c12618504674e7c156c33c4b60eb0067a5 100644 (file)
@@ -576,6 +576,8 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
 
   TRY
     {
+      gdbpy_allow_threads allow_threads;
+
       struct interp *interp;
 
       std::string arg_copy = arg;
@@ -898,6 +900,7 @@ gdbpy_parse_and_eval (PyObject *self, PyObject *args)
 
   TRY
     {
+      gdbpy_allow_threads allow_threads;
       result = parse_and_eval (expr_str);
     }
   CATCH (except, RETURN_MASK_ALL)