|
|
4c2ad1 |
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
|
|
|
4c2ad1 |
From: Fedora GDB patches <invalid@email.com>
|
|
|
4c2ad1 |
Date: Fri, 27 Oct 2017 21:07:50 +0200
|
|
|
4c2ad1 |
Subject: gdb-python-gil.patch
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
;; Fix Python GIL with gdb.execute("continue") (Phil Muldoon, BZ 1116957).
|
|
|
4c2ad1 |
;;=push
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
|
|
|
4c2ad1 |
--- a/gdb/doc/python.texi
|
|
|
4c2ad1 |
+++ b/gdb/doc/python.texi
|
|
|
4c2ad1 |
@@ -232,6 +232,14 @@ returned as a string. The default is @code{False}, in which case the
|
|
|
4c2ad1 |
return value is @code{None}. If @var{to_string} is @code{True}, the
|
|
|
4c2ad1 |
@value{GDBN} virtual terminal will be temporarily set to unlimited width
|
|
|
4c2ad1 |
and height, and its pagination will be disabled; @pxref{Screen Size}.
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+The @var{release_gil} flag specifies whether @value{GDBN} ought to
|
|
|
4c2ad1 |
+release the Python GIL before executing the command. This is useful
|
|
|
4c2ad1 |
+in multi-threaded Python programs where by default the Python
|
|
|
4c2ad1 |
+interpreter will acquire the GIL and lock other threads from
|
|
|
4c2ad1 |
+executing. After the command has completed executing in @value{GDBN}
|
|
|
4c2ad1 |
+the Python GIL is reacquired. This flag must be a boolean value. If
|
|
|
4c2ad1 |
+omitted, it defaults to @code{False}.
|
|
|
4c2ad1 |
@end defun
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
@findex gdb.breakpoints
|
|
|
4c2ad1 |
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
|
|
|
4c2ad1 |
--- a/gdb/python/python-internal.h
|
|
|
4c2ad1 |
+++ b/gdb/python/python-internal.h
|
|
|
4c2ad1 |
@@ -148,6 +148,8 @@ typedef int Py_ssize_t;
|
|
|
4c2ad1 |
#define PyGILState_Release(ARG) ((void)(ARG))
|
|
|
4c2ad1 |
#define PyEval_InitThreads()
|
|
|
4c2ad1 |
#define PyThreadState_Swap(ARG) ((void)(ARG))
|
|
|
4c2ad1 |
+#define PyEval_SaveThread() ((void)(ARG))
|
|
|
4c2ad1 |
+#define PyEval_RestoreThread(ARG) ((void)(ARG))
|
|
|
4c2ad1 |
#define PyEval_ReleaseLock()
|
|
|
4c2ad1 |
#endif
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
diff --git a/gdb/python/python.c b/gdb/python/python.c
|
|
|
4c2ad1 |
--- a/gdb/python/python.c
|
|
|
4c2ad1 |
+++ b/gdb/python/python.c
|
|
|
4c2ad1 |
@@ -556,12 +556,16 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
|
|
|
4c2ad1 |
{
|
|
|
4c2ad1 |
const char *arg;
|
|
|
4c2ad1 |
PyObject *from_tty_obj = NULL, *to_string_obj = NULL;
|
|
|
4c2ad1 |
- int from_tty, to_string;
|
|
|
4c2ad1 |
- static const char *keywords[] = { "command", "from_tty", "to_string", NULL };
|
|
|
4c2ad1 |
+ int from_tty, to_string, release_gil;
|
|
|
4c2ad1 |
+ static const char *keywords[] = {"command", "from_tty", "to_string", "release_gil", NULL };
|
|
|
4c2ad1 |
+ PyObject *release_gil_obj = NULL;
|
|
|
4c2ad1 |
+ /* Initialize it just to avoid a GCC false warning. */
|
|
|
4c2ad1 |
+ PyThreadState *state = NULL;
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
- if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!", keywords, &arg,
|
|
|
4c2ad1 |
+ if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!O!", keywords, &arg,
|
|
|
4c2ad1 |
&PyBool_Type, &from_tty_obj,
|
|
|
4c2ad1 |
- &PyBool_Type, &to_string_obj))
|
|
|
4c2ad1 |
+ &PyBool_Type, &to_string_obj,
|
|
|
4c2ad1 |
+ &PyBool_Type, &release_gil_obj))
|
|
|
4c2ad1 |
return NULL;
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
from_tty = 0;
|
|
|
4c2ad1 |
@@ -582,6 +586,15 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
|
|
|
4c2ad1 |
to_string = cmp;
|
|
|
4c2ad1 |
}
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
+ release_gil = 0;
|
|
|
4c2ad1 |
+ if (release_gil_obj)
|
|
|
4c2ad1 |
+ {
|
|
|
4c2ad1 |
+ int cmp = PyObject_IsTrue (release_gil_obj);
|
|
|
4c2ad1 |
+ if (cmp < 0)
|
|
|
4c2ad1 |
+ return NULL;
|
|
|
4c2ad1 |
+ release_gil = cmp;
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
std::string to_string_res;
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
TRY
|
|
|
4c2ad1 |
@@ -602,6 +615,13 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
counted_command_line lines = read_command_lines_1 (reader, 1, nullptr);
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
+ /* In the case of long running GDB commands, allow the user to
|
|
|
4c2ad1 |
+ release the Python GIL acquired by Python. Restore the GIL
|
|
|
4c2ad1 |
+ after the command has completed before handing back to
|
|
|
4c2ad1 |
+ Python. */
|
|
|
4c2ad1 |
+ if (release_gil)
|
|
|
4c2ad1 |
+ state = PyEval_SaveThread();
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0);
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
scoped_restore save_uiout = make_scoped_restore (¤t_uiout);
|
|
|
4c2ad1 |
@@ -617,10 +637,22 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
|
|
|
4c2ad1 |
from_tty);
|
|
|
4c2ad1 |
else
|
|
|
4c2ad1 |
execute_control_commands (lines.get (), from_tty);
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+ /* Reacquire the GIL if it was released earlier. */
|
|
|
4c2ad1 |
+ if (release_gil)
|
|
|
4c2ad1 |
+ PyEval_RestoreThread (state);
|
|
|
4c2ad1 |
}
|
|
|
4c2ad1 |
CATCH (except, RETURN_MASK_ALL)
|
|
|
4c2ad1 |
{
|
|
|
4c2ad1 |
- GDB_PY_HANDLE_EXCEPTION (except);
|
|
|
4c2ad1 |
+ if (except.reason < 0)
|
|
|
4c2ad1 |
+ {
|
|
|
4c2ad1 |
+ /* Reacquire the GIL if it was released earlier. */
|
|
|
4c2ad1 |
+ if (release_gil)
|
|
|
4c2ad1 |
+ PyEval_RestoreThread (state);
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+ gdbpy_convert_exception (except);
|
|
|
4c2ad1 |
+ return NULL;
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
}
|
|
|
4c2ad1 |
END_CATCH
|
|
|
4c2ad1 |
|
|
|
4c2ad1 |
diff --git a/gdb/testsuite/gdb.python/py-gil-mthread.c b/gdb/testsuite/gdb.python/py-gil-mthread.c
|
|
|
4c2ad1 |
new file mode 100644
|
|
|
4c2ad1 |
--- /dev/null
|
|
|
4c2ad1 |
+++ b/gdb/testsuite/gdb.python/py-gil-mthread.c
|
|
|
4c2ad1 |
@@ -0,0 +1,13 @@
|
|
|
4c2ad1 |
+#include <stdio.h>
|
|
|
4c2ad1 |
+#include <unistd.h>
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+int
|
|
|
4c2ad1 |
+main (void)
|
|
|
4c2ad1 |
+{
|
|
|
4c2ad1 |
+ int i;
|
|
|
4c2ad1 |
+ for (i = 0; i < 10; i++)
|
|
|
4c2ad1 |
+ {
|
|
|
4c2ad1 |
+ sleep (1); /* break-here */
|
|
|
4c2ad1 |
+ printf ("Sleeping %d\n", i);
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+}
|
|
|
4c2ad1 |
diff --git a/gdb/testsuite/gdb.python/py-gil-mthread.exp b/gdb/testsuite/gdb.python/py-gil-mthread.exp
|
|
|
4c2ad1 |
new file mode 100644
|
|
|
4c2ad1 |
--- /dev/null
|
|
|
4c2ad1 |
+++ b/gdb/testsuite/gdb.python/py-gil-mthread.exp
|
|
|
4c2ad1 |
@@ -0,0 +1,69 @@
|
|
|
4c2ad1 |
+# Copyright (C) 2014 Free Software Foundation, Inc.
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+# This program is free software; you can redistribute it and/or modify
|
|
|
4c2ad1 |
+# it under the terms of the GNU General Public License as published by
|
|
|
4c2ad1 |
+# the Free Software Foundation; either version 3 of the License, or
|
|
|
4c2ad1 |
+# (at your option) any later version.
|
|
|
4c2ad1 |
+#
|
|
|
4c2ad1 |
+# This program is distributed in the hope that it will be useful,
|
|
|
4c2ad1 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
4c2ad1 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
4c2ad1 |
+# GNU General Public License for more details.
|
|
|
4c2ad1 |
+#
|
|
|
4c2ad1 |
+# You should have received a copy of the GNU General Public License
|
|
|
4c2ad1 |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+standard_testfile .c .py
|
|
|
4c2ad1 |
+set executable $testfile
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+if { [prepare_for_testing $testfile.exp $executable $srcfile] } {
|
|
|
4c2ad1 |
+ return -1
|
|
|
4c2ad1 |
+}
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+# Skip all tests if Python scripting is not enabled.
|
|
|
4c2ad1 |
+if { [skip_python_tests] } { continue }
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+if ![runto_main] {
|
|
|
4c2ad1 |
+ return -1
|
|
|
4c2ad1 |
+}
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+gdb_breakpoint $srcfile:[gdb_get_line_number "break-here"] temporary
|
|
|
4c2ad1 |
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+set test "response"
|
|
|
4c2ad1 |
+set timeout 60
|
|
|
4c2ad1 |
+set sleeping_last -1
|
|
|
4c2ad1 |
+set hello_last 0
|
|
|
4c2ad1 |
+set minimal 5
|
|
|
4c2ad1 |
+gdb_test_multiple "python exec (open ('$srcdir/$subdir/$srcfile2').read ())" $test {
|
|
|
4c2ad1 |
+ -re "Error: unable to start thread\r\n" {
|
|
|
4c2ad1 |
+ fail $test
|
|
|
4c2ad1 |
+ # Not $gdb_prompt-synced!
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+ -re "Sleeping (\[0-9\]+)\r\n" {
|
|
|
4c2ad1 |
+ set n $expect_out(1,string)
|
|
|
4c2ad1 |
+ if { $sleeping_last + 1 != $n } {
|
|
|
4c2ad1 |
+ fail $test
|
|
|
4c2ad1 |
+ } else {
|
|
|
4c2ad1 |
+ set sleeping_last $n
|
|
|
4c2ad1 |
+ if { $sleeping_last >= $minimal && $hello_last >= $minimal } {
|
|
|
4c2ad1 |
+ pass $test
|
|
|
4c2ad1 |
+ } else {
|
|
|
4c2ad1 |
+ exp_continue
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+ -re "Hello \\( (\[0-9\]+) \\)\r\n" {
|
|
|
4c2ad1 |
+ set n $expect_out(1,string)
|
|
|
4c2ad1 |
+ if { $hello_last + 1 != $n } {
|
|
|
4c2ad1 |
+ fail $test
|
|
|
4c2ad1 |
+ } else {
|
|
|
4c2ad1 |
+ set hello_last $n
|
|
|
4c2ad1 |
+ if { $sleeping_last >= $minimal && $hello_last >= $minimal } {
|
|
|
4c2ad1 |
+ pass $test
|
|
|
4c2ad1 |
+ } else {
|
|
|
4c2ad1 |
+ exp_continue
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+ }
|
|
|
4c2ad1 |
+}
|
|
|
4c2ad1 |
diff --git a/gdb/testsuite/gdb.python/py-gil-mthread.py b/gdb/testsuite/gdb.python/py-gil-mthread.py
|
|
|
4c2ad1 |
new file mode 100644
|
|
|
4c2ad1 |
--- /dev/null
|
|
|
4c2ad1 |
+++ b/gdb/testsuite/gdb.python/py-gil-mthread.py
|
|
|
4c2ad1 |
@@ -0,0 +1,28 @@
|
|
|
4c2ad1 |
+try:
|
|
|
4c2ad1 |
+ import thread
|
|
|
4c2ad1 |
+except:
|
|
|
4c2ad1 |
+ import _thread
|
|
|
4c2ad1 |
+import time
|
|
|
4c2ad1 |
+import gdb
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+# Define a function for the thread
|
|
|
4c2ad1 |
+def print_thread_hello():
|
|
|
4c2ad1 |
+ count = 0
|
|
|
4c2ad1 |
+ while count < 10:
|
|
|
4c2ad1 |
+ time.sleep(1)
|
|
|
4c2ad1 |
+ count += 1
|
|
|
4c2ad1 |
+ print ("Hello ( %d )" % count)
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+# Create a threads a continue
|
|
|
4c2ad1 |
+try:
|
|
|
4c2ad1 |
+ thread.start_new_thread (print_thread_hello, ())
|
|
|
4c2ad1 |
+ gdb.execute ("continue", release_gil=True)
|
|
|
4c2ad1 |
+except:
|
|
|
4c2ad1 |
+ try:
|
|
|
4c2ad1 |
+ _thread.start_new_thread (print_thread_hello, ())
|
|
|
4c2ad1 |
+ gdb.execute ("continue", release_gil=True)
|
|
|
4c2ad1 |
+ except:
|
|
|
4c2ad1 |
+ print ("Error: unable to start thread")
|
|
|
4c2ad1 |
+
|
|
|
4c2ad1 |
+while 1:
|
|
|
4c2ad1 |
+ pass
|