From 0d2fda651f1e54756a48a2a618cd4bee6706e236 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Aug 13 2014 20:56:01 +0000 Subject: Fix Python GIL with gdb.execute("continue") (Phil Muldoon, BZ 1116957). --- 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 ++ ++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 . ++ ++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 - 7.8-17.fc21 +- Fix Python GIL with gdb.execute("continue") (Phil Muldoon, BZ 1116957). + * Mon Aug 4 2014 Jan Kratochvil - 7.8-16.fc21 - Enable babeltrace compile-time feature.