From 76d711c3b5397b749a67d229150d3c1ff3f33add Mon Sep 17 00:00:00 2001
From: Bram Moolenaar <Bram@vim.org>
Date: Wed, 13 Feb 2013 14:17:08 +0100
Subject: [PATCH] updated for version 7.3.808 Problem:    Python threads still
 do not work properly. Solution:   Fix both Python 2 and 3.  Add tests. (Ken
 Takata)

---
 src/if_python.c       | 15 ++++++++------
 src/if_python3.c      | 25 +++++++++++-----------
 src/testdir/test86.in | 48 +++++++++++++++++++++++++++++++++++++++++++
 src/testdir/test86.ok |  2 ++
 src/testdir/test87.in | 48 +++++++++++++++++++++++++++++++++++++++++++
 src/testdir/test87.ok |  2 ++
 src/version.c         |  2 ++
 7 files changed, 123 insertions(+), 19 deletions(-)

diff --git a/src/if_python.c b/src/if_python.c
index 1bf737fc4c..d0314e2f53 100644
--- a/src/if_python.c
+++ b/src/if_python.c
@@ -741,7 +741,7 @@ Python_Init(void)
 	PyMac_Initialize();
 #endif
 	/* Initialise threads, and below save the state using
-	 * PyGILState_Ensure.  Without the call to PyGILState_Ensure, thread
+	 * PyEval_SaveThread.  Without the call to PyEval_SaveThread, thread
 	 * specific state (such as the system trace hook), will be lost
 	 * between invocations of Python code. */
 	PyEval_InitThreads();
@@ -755,10 +755,6 @@ Python_Init(void)
 	if (PythonMod_Init())
 	    goto fail;
 
-	/* The first python thread is vim's, release the lock. */
-	Python_SaveThread();
-	pygilstate = PyGILState_Ensure();
-
 	globals = PyModule_GetDict(PyImport_AddModule("__main__"));
 
 	/* Remove the element from sys.path that was added because of our
@@ -767,7 +763,14 @@ Python_Init(void)
 	 * the current directory in sys.path. */
 	PyRun_SimpleString("import sys; sys.path = filter(lambda x: x != '/must>not&exist', sys.path)");
 
-	PyGILState_Release(pygilstate);
+	/* lock is created and acquired in PyEval_InitThreads() and thread
+	 * state is created in Py_Initialize()
+	 * there _PyGILState_NoteThreadState() also sets gilcounter to 1
+	 * (python must have threads enabled!)
+	 * so the following does both: unlock GIL and save thread state in TLS
+	 * without deleting thread state
+	 */
+	PyEval_SaveThread();
 
 	initialised = 1;
     }
diff --git a/src/if_python3.c b/src/if_python3.c
index 4067517acd..5311483ddb 100644
--- a/src/if_python3.c
+++ b/src/if_python3.c
@@ -729,13 +729,11 @@ Python3_Init(void)
 #else
 	PyMac_Initialize();
 #endif
-	/* Initialise threads, and save the state using PyGILState_Ensure.
-	 * Without the call to PyGILState_Ensure, thread specific state (such
-	 * as the system trace hook), will be lost between invocations of
-	 * Python code. */
+	/* Initialise threads, and below save the state using
+	 * PyEval_SaveThread.  Without the call to PyEval_SaveThread, thread
+	 * specific state (such as the system trace hook), will be lost
+	 * between invocations of Python code. */
 	PyEval_InitThreads();
-	pygilstate = PyGILState_Ensure();
-
 #ifdef DYNAMIC_PYTHON3
 	get_py3_exceptions();
 #endif
@@ -754,13 +752,14 @@ Python3_Init(void)
 	 */
 	PyRun_SimpleString("import vim; import sys; sys.path = list(filter(lambda x: not x.endswith('must>not&exist'), sys.path))");
 
-	// lock is created and acquired in PyEval_InitThreads() and thread
-	// state is created in Py_Initialize()
-	// there _PyGILState_NoteThreadState() also sets gilcounter to 1
-	// (python must have threads enabled!)
-	// so the following does both: unlock GIL and save thread state in TLS
-	// without deleting thread state
-	PyGILState_Release(pygilstate);
+	/* lock is created and acquired in PyEval_InitThreads() and thread
+	 * state is created in Py_Initialize()
+	 * there _PyGILState_NoteThreadState() also sets gilcounter to 1
+	 * (python must have threads enabled!)
+	 * so the following does both: unlock GIL and save thread state in TLS
+	 * without deleting thread state
+	 */
+	PyEval_SaveThread();
 
 	py3initialised = 1;
     }
diff --git a/src/testdir/test86.in b/src/testdir/test86.in
index 1309643d8b..71635bda2f 100644
--- a/src/testdir/test86.in
+++ b/src/testdir/test86.in
@@ -267,6 +267,54 @@ EOF
 :      $put =toput
 :   endtry
 :endfor
+:"
+:" threading
+:let l = [0]
+:py l=vim.bindeval('l')
+:py <<EOF
+import threading
+import time
+
+class T(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+        self.t = 0
+        self.running = True
+
+    def run(self):
+        while self.running:
+            self.t += 1
+            time.sleep(0.1)
+
+t = T()
+t.start()
+EOF
+:sleep 1
+:py t.running = False
+:py t.join()
+:py l[0] = t.t > 8  # check if the background thread is working
+:$put =string(l)
+:"
+:" settrace
+:let l = []
+:py l=vim.bindeval('l')
+:py <<EOF
+import sys
+
+def traceit(frame, event, arg):
+    global l
+    if event == "line":
+        l.extend([frame.f_lineno])
+    return traceit
+
+def trace_main():
+    for i in range(5):
+        pass
+EOF
+:py sys.settrace(traceit)
+:py trace_main()
+:py sys.settrace(None)
+:$put =string(l)
 :endfun
 :"
 :call Test()
diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok
index 5ef8689a24..3dd8d79944 100644
--- a/src/testdir/test86.ok
+++ b/src/testdir/test86.ok
@@ -63,3 +63,5 @@ ll:[1]
 {"\0": 1}:	Vim(let):E859:
 undefined_name:	Vim(let):E858:
 vim:	Vim(let):E859:
+[1]
+[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1]
diff --git a/src/testdir/test87.in b/src/testdir/test87.in
index 1d7ccedd51..5115e5be73 100644
--- a/src/testdir/test87.in
+++ b/src/testdir/test87.in
@@ -267,6 +267,54 @@ EOF
 :      $put =toput
 :   endtry
 :endfor
+:"
+:" threading
+:let l = [0]
+:py3 l=vim.bindeval('l')
+:py3 <<EOF
+import threading
+import time
+
+class T(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+        self.t = 0
+        self.running = True
+
+    def run(self):
+        while self.running:
+            self.t += 1
+            time.sleep(0.1)
+
+t = T()
+t.start()
+EOF
+:sleep 1
+:py3 t.running = False
+:py3 t.join()
+:py3 l[0] = t.t > 8  # check if the background thread is working
+:$put =string(l)
+:"
+:" settrace
+:let l = []
+:py3 l=vim.bindeval('l')
+:py3 <<EOF
+import sys
+
+def traceit(frame, event, arg):
+    global l
+    if event == "line":
+        l += [frame.f_lineno]
+    return traceit
+
+def trace_main():
+    for i in range(5):
+        pass
+EOF
+:py3 sys.settrace(traceit)
+:py3 trace_main()
+:py3 sys.settrace(None)
+:$put =string(l)
 :endfun
 :"
 :call Test()
diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok
index 4c0bb799d7..3dffa26d47 100644
--- a/src/testdir/test87.ok
+++ b/src/testdir/test87.ok
@@ -63,3 +63,5 @@ ll:[1]
 {"\0": 1}:	Vim(let):E861:
 undefined_name:	Vim(let):E860:
 vim:	Vim(let):E861:
+[1]
+[1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1]
diff --git a/src/version.c b/src/version.c
index 1c23a5e873..c716154e23 100644
--- a/src/version.c
+++ b/src/version.c
@@ -725,6 +725,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    808,
 /**/
     807,
 /**/
-- 
GitLab