Blame SOURCES/gdb-python-gil.patch

7a6771
Index: gdb-7.11.50.20160630/gdb/doc/python.texi
7a6771
===================================================================
7a6771
--- gdb-7.11.50.20160630.orig/gdb/doc/python.texi	2016-07-03 16:30:37.009338358 +0200
7a6771
+++ gdb-7.11.50.20160630/gdb/doc/python.texi	2016-07-03 16:30:42.812387867 +0200
7a6771
@@ -229,6 +229,14 @@
7a6771
 return value is @code{None}.  If @var{to_string} is @code{True}, the
7a6771
 @value{GDBN} virtual terminal will be temporarily set to unlimited width
7a6771
 and height, and its pagination will be disabled; @pxref{Screen Size}.
7a6771
+
7a6771
+The @var{release_gil} flag specifies whether @value{GDBN} ought to
7a6771
+release the Python GIL before executing the command.  This is useful
7a6771
+in multi-threaded Python programs where by default the Python
7a6771
+interpreter will acquire the GIL and lock other threads from
7a6771
+executing.  After the command has completed executing in @value{GDBN}
7a6771
+the Python GIL is reacquired. This flag must be a boolean value.  If
7a6771
+omitted, it defaults to @code{False}.
7a6771
 @end defun
7a6771
 
7a6771
 @findex gdb.breakpoints
7a6771
Index: gdb-7.11.50.20160630/gdb/python/python-internal.h
7a6771
===================================================================
7a6771
--- gdb-7.11.50.20160630.orig/gdb/python/python-internal.h	2016-07-03 16:30:37.010338366 +0200
7a6771
+++ gdb-7.11.50.20160630/gdb/python/python-internal.h	2016-07-03 16:30:42.812387867 +0200
7a6771
@@ -140,6 +140,8 @@
7a6771
 #define PyGILState_Release(ARG) ((void)(ARG))
7a6771
 #define PyEval_InitThreads()
7a6771
 #define PyThreadState_Swap(ARG) ((void)(ARG))
7a6771
+#define PyEval_SaveThread() ((void)(ARG))
7a6771
+#define PyEval_RestoreThread(ARG) ((void)(ARG))
7a6771
 #define PyEval_ReleaseLock()
7a6771
 #endif
7a6771
 
7a6771
Index: gdb-7.11.50.20160630/gdb/python/python.c
7a6771
===================================================================
7a6771
--- gdb-7.11.50.20160630.orig/gdb/python/python.c	2016-07-03 16:30:37.011338375 +0200
7a6771
+++ gdb-7.11.50.20160630/gdb/python/python.c	2016-07-03 16:31:16.324673783 +0200
7a6771
@@ -619,13 +619,18 @@
7a6771
 {
7a6771
   const char *arg;
7a6771
   PyObject *from_tty_obj = NULL, *to_string_obj = NULL;
7a6771
-  int from_tty, to_string;
7a6771
-  static char *keywords[] = {"command", "from_tty", "to_string", NULL };
7a6771
+  PyObject *release_gil_obj = NULL;
7a6771
+  int from_tty, to_string, release_gil;
7a6771
+  static char *keywords[] = {"command", "from_tty", "to_string",
7a6771
+			     "release_gil", NULL };
7a6771
   char *result = NULL;
7a6771
+  /* Initialize it just to avoid a GCC false warning.  */
7a6771
+  PyThreadState *state = NULL;
7a6771
 
7a6771
-  if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!", keywords, &arg,
7a6771
+  if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!O!O!", keywords, &arg,
7a6771
 				     &PyBool_Type, &from_tty_obj,
7a6771
-				     &PyBool_Type, &to_string_obj))
7a6771
+				     &PyBool_Type, &to_string_obj,
7a6771
+				     &PyBool_Type, &release_gil_obj))
7a6771
     return NULL;
7a6771
 
7a6771
   from_tty = 0;
7a6771
@@ -646,6 +651,15 @@
7a6771
       to_string = cmp;
7a6771
     }
7a6771
 
7a6771
+  release_gil = 0;
7a6771
+  if (release_gil_obj)
7a6771
+    {
7a6771
+      int cmp = PyObject_IsTrue (release_gil_obj);
7a6771
+      if (cmp < 0)
7a6771
+	return NULL;
7a6771
+      release_gil = cmp;
7a6771
+    }
7a6771
+
7a6771
   TRY
7a6771
     {
7a6771
       /* Copy the argument text in case the command modifies it.  */
7a6771
@@ -653,6 +667,13 @@
7a6771
       struct cleanup *cleanup = make_cleanup (xfree, copy);
7a6771
       struct interp *interp;
7a6771
 
7a6771
+      /* In the case of long running GDB commands, allow the user to
7a6771
+	 release the Python GIL acquired by Python.  Restore the GIL
7a6771
+	 after the command has completed before handing back to
7a6771
+	 Python.  */
7a6771
+      if (release_gil)
7a6771
+	state = PyEval_SaveThread();
7a6771
+
7a6771
       make_cleanup_restore_integer (&current_ui->async);
7a6771
       current_ui->async = 0;
7a6771
 
7a6771
@@ -671,11 +692,23 @@
7a6771
 	  execute_command (copy, from_tty);
7a6771
 	}
7a6771
 
7a6771
+      /* Reacquire the GIL if it was released earlier.  */
7a6771
+      if (release_gil)
7a6771
+	PyEval_RestoreThread (state);
7a6771
+
7a6771
       do_cleanups (cleanup);
7a6771
     }
7a6771
   CATCH (except, RETURN_MASK_ALL)
7a6771
     {
7a6771
-      GDB_PY_HANDLE_EXCEPTION (except);
7a6771
+      if (except.reason < 0)
7a6771
+	{
7a6771
+	  /* Reacquire the GIL if it was released earlier.  */
7a6771
+	  if (release_gil)
7a6771
+	    PyEval_RestoreThread (state);
7a6771
+
7a6771
+	  gdbpy_convert_exception (except);
7a6771
+	  return NULL;
7a6771
+	}
7a6771
     }
7a6771
   END_CATCH
7a6771
 
7a6771
--- /dev/null	2016-09-12 21:37:05.332693927 +0200
7a6771
+++ gdb-7.11.90.20160907/gdb/testsuite/gdb.python/py-gil-mthread.c	2016-09-12 21:51:53.750317187 +0200
7a6771
@@ -0,0 +1,13 @@
7a6771
+#include <stdio.h>
7a6771
+#include <unistd.h>
7a6771
+
7a6771
+int
7a6771
+main (void)
7a6771
+{
7a6771
+  int i;
7a6771
+  for (i = 0; i < 10; i++)
7a6771
+    {
7a6771
+      sleep (1); /* break-here */
7a6771
+      printf ("Sleeping %d\n", i);
7a6771
+    }
7a6771
+}
7a6771
--- /dev/null	2016-09-12 21:37:05.332693927 +0200
7a6771
+++ gdb-7.11.90.20160907/gdb/testsuite/gdb.python/py-gil-mthread.exp	2016-09-12 21:52:38.605750360 +0200
7a6771
@@ -0,0 +1,69 @@
7a6771
+# Copyright (C) 2014 Free Software Foundation, Inc.
7a6771
+
7a6771
+# This program is free software; you can redistribute it and/or modify
7a6771
+# it under the terms of the GNU General Public License as published by
7a6771
+# the Free Software Foundation; either version 3 of the License, or
7a6771
+# (at your option) any later version.
7a6771
+#
7a6771
+# This program is distributed in the hope that it will be useful,
7a6771
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
7a6771
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7a6771
+# GNU General Public License for more details.
7a6771
+#
7a6771
+# You should have received a copy of the GNU General Public License
7a6771
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
7a6771
+
7a6771
+standard_testfile .c .py
7a6771
+set executable $testfile
7a6771
+
7a6771
+if { [prepare_for_testing $testfile.exp $executable $srcfile] } {
7a6771
+    return -1
7a6771
+}
7a6771
+
7a6771
+# Skip all tests if Python scripting is not enabled.
7a6771
+if { [skip_python_tests] } { continue }
7a6771
+
7a6771
+if ![runto_main] {
7a6771
+    return -1
7a6771
+}
7a6771
+
7a6771
+gdb_breakpoint $srcfile:[gdb_get_line_number "break-here"] temporary
7a6771
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
7a6771
+
7a6771
+set test "response"
7a6771
+set timeout 60
7a6771
+set sleeping_last -1
7a6771
+set hello_last 0
7a6771
+set minimal 5
7a6771
+gdb_test_multiple "python exec (open ('$srcdir/$subdir/$srcfile2').read ())" $test {
7a6771
+    -re "Error: unable to start thread\r\n" {
7a6771
+	fail $test
7a6771
+	# Not $gdb_prompt-synced!
7a6771
+    }
7a6771
+    -re "Sleeping (\[0-9\]+)\r\n" {
7a6771
+	set n $expect_out(1,string)
7a6771
+	if { $sleeping_last + 1 != $n } {
7a6771
+	    fail $test
7a6771
+	} else {
7a6771
+	    set sleeping_last $n
7a6771
+	    if { $sleeping_last >= $minimal && $hello_last >= $minimal } {
7a6771
+		pass $test
7a6771
+	    } else {
7a6771
+		exp_continue
7a6771
+	    }
7a6771
+	}
7a6771
+    }
7a6771
+    -re "Hello \\( (\[0-9\]+) \\)\r\n" {
7a6771
+	set n $expect_out(1,string)
7a6771
+	if { $hello_last + 1 != $n } {
7a6771
+	    fail $test
7a6771
+	} else {
7a6771
+	    set hello_last $n
7a6771
+	    if { $sleeping_last >= $minimal && $hello_last >= $minimal } {
7a6771
+		pass $test
7a6771
+	    } else {
7a6771
+		exp_continue
7a6771
+	    }
7a6771
+	}
7a6771
+    }
7a6771
+}
7a6771
--- /dev/null	2016-09-12 21:37:05.332693927 +0200
7a6771
+++ gdb-7.11.90.20160907/gdb/testsuite/gdb.python/py-gil-mthread.py	2016-09-12 21:59:02.668459286 +0200
7a6771
@@ -0,0 +1,28 @@
7a6771
+try:
7a6771
+   import thread
7a6771
+except:
7a6771
+   import _thread
7a6771
+import time
7a6771
+import gdb
7a6771
+
7a6771
+# Define a function for the thread
7a6771
+def print_thread_hello():
7a6771
+   count = 0
7a6771
+   while count < 10:
7a6771
+      time.sleep(1)
7a6771
+      count += 1
7a6771
+      print ("Hello (", count, ")")
7a6771
+
7a6771
+# Create a threads a continue
7a6771
+try:
7a6771
+   thread.start_new_thread (print_thread_hello, ())
7a6771
+   gdb.execute ("continue", release_gil=True)
7a6771
+except:
7a6771
+   try:
7a6771
+      _thread.start_new_thread (print_thread_hello, ())
7a6771
+      gdb.execute ("continue", release_gil=True)
7a6771
+   except:
7a6771
+      print ("Error: unable to start thread")
7a6771
+
7a6771
+while 1:
7a6771
+   pass