[gdb] Fix Python GIL with gdb.execute("continue") (Phil Muldoon, BZ 1116957).
Jan Kratochvil
jankratochvil at fedoraproject.org
Wed Aug 13 20:56:01 UTC 2014
commit 0d2fda651f1e54756a48a2a618cd4bee6706e236
Author: Jan Kratochvil <jan.kratochvil at redhat.com>
Date: Wed Aug 13 22:56:01 2014 +0200
Fix Python GIL with gdb.execute("continue") (Phil Muldoon, BZ 1116957).
gdb-python-gil.patch | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++
gdb.spec | 9 ++-
2 files changed, 231 insertions(+), 1 deletions(-)
---
diff --git a/gdb-python-gil.patch b/gdb-python-gil.patch
new file mode 100644
index 0000000..d839b6b
--- /dev/null
+++ b/gdb-python-gil.patch
@@ -0,0 +1,223 @@
+diff -dup -ruNp gdb-7.8-orig/gdb/doc/python.texi gdb-7.8/gdb/doc/python.texi
+--- gdb-7.8-orig/gdb/doc/python.texi 2014-08-13 22:04:14.162441271 +0200
++++ gdb-7.8/gdb/doc/python.texi 2014-08-13 22:07:20.894643853 +0200
+@@ -228,6 +228,14 @@ returned as a string. The default is @c
+ return value is @code{None}. If @var{to_string} is @code{True}, the
+ @value{GDBN} virtual terminal will be temporarily set to unlimited width
+ and height, and its pagination will be disabled; @pxref{Screen Size}.
++
++The @var{release_gil} flag specifies whether @value{GDBN} ought to
++release the Python GIL before executing the command. This is useful
++in multi-threaded Python programs where by default the Python
++interpreter will acquire the GIL and lock other threads from
++executing. After the command has completed executing in @value{GDBN}
++the Python GIL is reacquired. This flag must be a boolean value. If
++omitted, it defaults to @code{False}.
+ @end defun
+
+ @findex gdb.breakpoints
+diff -dup -ruNp gdb-7.8-orig/gdb/python/python-internal.h gdb-7.8/gdb/python/python-internal.h
+--- gdb-7.8-orig/gdb/python/python-internal.h 2014-08-13 22:04:14.835441977 +0200
++++ gdb-7.8/gdb/python/python-internal.h 2014-08-13 22:07:20.895643867 +0200
+@@ -143,6 +143,8 @@ typedef int Py_ssize_t;
+ #define PyGILState_Release(ARG) ((void)(ARG))
+ #define PyEval_InitThreads()
+ #define PyThreadState_Swap(ARG) ((void)(ARG))
++#define PyEval_SaveThread() ((void)(ARG))
++#define PyEval_RestoreThread(ARG) ((void)(ARG))
+ #define PyEval_ReleaseLock()
+ #endif
+
+diff -dup -ruNp gdb-7.8-orig/gdb/python/python.c gdb-7.8/gdb/python/python.c
+--- gdb-7.8-orig/gdb/python/python.c 2014-08-13 22:04:14.164441273 +0200
++++ gdb-7.8/gdb/python/python.c 2014-08-13 22:07:20.895643867 +0200
+@@ -620,14 +620,18 @@ execute_gdb_command (PyObject *self, PyO
+ {
+ const char *arg;
+ PyObject *from_tty_obj = NULL, *to_string_obj = NULL;
+- int from_tty, to_string;
++ PyObject *release_gil_obj = NULL;
++ int from_tty, to_string, release_gil;
+ volatile struct gdb_exception except;
+- static char *keywords[] = {"command", "from_tty", "to_string", NULL };
++ static char *keywords[] = {"command", "from_tty", "to_string",
++ "release_gil", NULL };
+ char *result = NULL;
++ PyThreadState *state;
+
+- if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!", keywords, &arg,
++ if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!O!", keywords, &arg,
+ &PyBool_Type, &from_tty_obj,
+- &PyBool_Type, &to_string_obj))
++ &PyBool_Type, &to_string_obj,
++ &PyBool_Type, &release_gil_obj))
+ return NULL;
+
+ from_tty = 0;
+@@ -648,12 +652,28 @@ execute_gdb_command (PyObject *self, PyO
+ to_string = cmp;
+ }
+
++ release_gil = 0;
++ if (release_gil_obj)
++ {
++ int cmp = PyObject_IsTrue (release_gil_obj);
++ if (cmp < 0)
++ return NULL;
++ release_gil = cmp;
++ }
++
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ /* Copy the argument text in case the command modifies it. */
+ char *copy = xstrdup (arg);
+ struct cleanup *cleanup = make_cleanup (xfree, copy);
+
++ /* In the case of long running GDB commands, allow the user to
++ release the Python GIL acquired by Python. Restore the GIL
++ after the command has completed before handing back to
++ Python. */
++ if (release_gil)
++ state = PyEval_SaveThread();
++
+ make_cleanup_restore_integer (&interpreter_async);
+ interpreter_async = 0;
+
+@@ -666,9 +686,21 @@ execute_gdb_command (PyObject *self, PyO
+ execute_command (copy, from_tty);
+ }
+
++ /* Reacquire the GIL if it was released earlier. */
++ if (release_gil)
++ PyEval_RestoreThread (state);
++
+ do_cleanups (cleanup);
+ }
+- GDB_PY_HANDLE_EXCEPTION (except);
++ if (except.reason < 0)
++ {
++ /* Reacquire the GIL if it was released earlier. */
++ if (release_gil)
++ PyEval_RestoreThread (state);
++
++ gdbpy_convert_exception (except);
++ return NULL;
++ }
+
+ /* Do any commands attached to breakpoint we stopped at. */
+ bpstat_do_actions ();
+diff -dup -ruNp gdb-7.8-orig/gdb/testsuite/gdb.python/py-gil-mthread.c gdb-7.8/gdb/testsuite/gdb.python/py-gil-mthread.c
+--- gdb-7.8-orig/gdb/testsuite/gdb.python/py-gil-mthread.c 1970-01-01 01:00:00.000000000 +0100
++++ gdb-7.8/gdb/testsuite/gdb.python/py-gil-mthread.c 2014-08-13 22:33:05.052648912 +0200
+@@ -0,0 +1,12 @@
++#include <stdio.h>
++
++int
++main (void)
++{
++ int i;
++ for (i = 0; i < 10; i++)
++ {
++ sleep (1); /* break-here */
++ printf ("Sleeping %d\n", i);
++ }
++}
+diff -dup -ruNp gdb-7.8-orig/gdb/testsuite/gdb.python/py-gil-mthread.exp gdb-7.8/gdb/testsuite/gdb.python/py-gil-mthread.exp
+--- gdb-7.8-orig/gdb/testsuite/gdb.python/py-gil-mthread.exp 1970-01-01 01:00:00.000000000 +0100
++++ gdb-7.8/gdb/testsuite/gdb.python/py-gil-mthread.exp 2014-08-13 22:33:00.660641300 +0200
+@@ -0,0 +1,69 @@
++# Copyright (C) 2014 Free Software Foundation, Inc.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++standard_testfile .c .py
++set executable $testfile
++
++if { [prepare_for_testing $testfile.exp $executable $srcfile] } {
++ return -1
++}
++
++# Skip all tests if Python scripting is not enabled.
++if { [skip_python_tests] } { continue }
++
++if ![runto_main] {
++ return -1
++}
++
++gdb_breakpoint $srcfile:[gdb_get_line_number "break-here"] temporary
++gdb_continue_to_breakpoint "break-here" ".* break-here .*"
++
++set test "response"
++set timeout 60
++set sleeping_last -1
++set hello_last 0
++set minimal 5
++gdb_test_multiple "python execfile('$srcdir/$subdir/$srcfile2')" $test {
++ -re "Error: unable to start thread\r\n" {
++ fail $test
++ # Not $gdb_prompt-synced!
++ }
++ -re "Sleeping (\[0-9\]+)\r\n" {
++ set n $expect_out(1,string)
++ if { $sleeping_last + 1 != $n } {
++ fail $test
++ } else {
++ set sleeping_last $n
++ if { $sleeping_last >= $minimal && $hello_last >= $minimal } {
++ pass $test
++ } else {
++ exp_continue
++ }
++ }
++ }
++ -re "Hello \\( (\[0-9\]+) \\)\r\n" {
++ set n $expect_out(1,string)
++ if { $hello_last + 1 != $n } {
++ fail $test
++ } else {
++ set hello_last $n
++ if { $sleeping_last >= $minimal && $hello_last >= $minimal } {
++ pass $test
++ } else {
++ exp_continue
++ }
++ }
++ }
++}
+diff -dup -ruNp gdb-7.8-orig/gdb/testsuite/gdb.python/py-gil-mthread.py gdb-7.8/gdb/testsuite/gdb.python/py-gil-mthread.py
+--- gdb-7.8-orig/gdb/testsuite/gdb.python/py-gil-mthread.py 1970-01-01 01:00:00.000000000 +0100
++++ gdb-7.8/gdb/testsuite/gdb.python/py-gil-mthread.py 2014-08-13 22:33:08.996654320 +0200
+@@ -0,0 +1,22 @@
++import thread
++import time
++import gdb
++
++# Define a function for the thread
++def print_thread_hello():
++ count = 0
++ while count < 10:
++ time.sleep(1)
++ count += 1
++ print "Hello (", count, ")"
++
++# Create a threads a continue
++try:
++ thread.start_new_thread( print_thread_hello, ())
++ gdb.execute ("continue", release_gil=True)
++
++except:
++ print "Error: unable to start thread"
++
++while 1:
++ pass
diff --git a/gdb.spec b/gdb.spec
index 41cdc11..a073c81 100644
--- a/gdb.spec
+++ b/gdb.spec
@@ -26,7 +26,7 @@ Version: 7.8
# The release always contains a leading reserved number, start it at 1.
# `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
-Release: 16%{?dist}
+Release: 17%{?dist}
License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and BSD and Public Domain and GFDL
Group: Development/Debuggers
@@ -527,6 +527,9 @@ Patch925: gdb-fortran-frame-string.patch
# Fix -Werror=unused-variable error configuring babeltrace.
Patch926: gdb-babeltrace-configure.patch
+# Fix Python GIL with gdb.execute("continue") (Phil Muldoon, BZ 1116957).
+Patch927: gdb-python-gil.patch
+
%if 0%{!?rhel:1} || 0%{?rhel} > 6
# RL_STATE_FEDORA_GDB would not be found for:
# Patch642: gdb-readline62-ask-more-rh.patch
@@ -811,6 +814,7 @@ find -name "*.info*"|xargs rm -f
%patch921 -p1
%patch925 -p1
%patch926 -p1
+%patch927 -p1
%patch848 -p1
%if 0%{!?el6:1}
@@ -1306,6 +1310,9 @@ then
fi
%changelog
+* Wed Aug 13 2014 Jan Kratochvil <jan.kratochvil at redhat.com> - 7.8-17.fc21
+- Fix Python GIL with gdb.execute("continue") (Phil Muldoon, BZ 1116957).
+
* Mon Aug 4 2014 Jan Kratochvil <jan.kratochvil at redhat.com> - 7.8-16.fc21
- Enable babeltrace compile-time feature.
More information about the scm-commits
mailing list