Skip to content

Commit 8b8aea1

Browse files
author
amaury.forgeotdarc
committed
Issue #1402: PyInterpreterState_Clear() may still invoke user code
(in deallocation of running threads, for example), so the PyGILState_Release() function must still be functional. On the other hand, _PyGILState_Fini() only frees memory, and can be called later. Backport candidate, but only after some experts comment on it. git-svn-id: http://svn.python.org/projects/python/trunk@59231 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent e7aa8c9 commit 8b8aea1

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

Lib/test/test_threading.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,40 @@ def run(self):
202202
t.join()
203203
# else the thread is still running, and we have no way to kill it
204204

205+
def test_finalize_runnning_thread(self):
206+
# Issue 1402: the PyGILState_Ensure / _Release functions may be called
207+
# very late on python exit: on deallocation of a running thread for
208+
# example.
209+
try:
210+
import ctypes
211+
except ImportError:
212+
if verbose:
213+
print("test_finalize_with_runnning_thread can't import ctypes")
214+
return # can't do anything
215+
216+
import subprocess
217+
rc = subprocess.call([sys.executable, "-c", """if 1:
218+
import ctypes, sys, time, thread
219+
220+
# Module globals are cleared before __del__ is run
221+
# So we save the functions in class dict
222+
class C:
223+
ensure = ctypes.pythonapi.PyGILState_Ensure
224+
release = ctypes.pythonapi.PyGILState_Release
225+
def __del__(self):
226+
state = self.ensure()
227+
self.release(state)
228+
229+
def waitingThread():
230+
x = C()
231+
time.sleep(100)
232+
233+
thread.start_new_thread(waitingThread, ())
234+
time.sleep(1) # be sure the other thread is waiting
235+
sys.exit(42)
236+
"""])
237+
self.assertEqual(rc, 42)
238+
205239
class ThreadingExceptionTests(unittest.TestCase):
206240
# A RuntimeError should be raised if Thread.start() is called
207241
# multiple times.

Python/pythonrun.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -437,11 +437,6 @@ Py_Finalize(void)
437437
_Py_PrintReferences(stderr);
438438
#endif /* Py_TRACE_REFS */
439439

440-
/* Cleanup auto-thread-state */
441-
#ifdef WITH_THREAD
442-
_PyGILState_Fini();
443-
#endif /* WITH_THREAD */
444-
445440
/* Clear interpreter state */
446441
PyInterpreterState_Clear(interp);
447442

@@ -453,6 +448,11 @@ Py_Finalize(void)
453448

454449
_PyExc_Fini();
455450

451+
/* Cleanup auto-thread-state */
452+
#ifdef WITH_THREAD
453+
_PyGILState_Fini();
454+
#endif /* WITH_THREAD */
455+
456456
/* Delete current thread */
457457
PyThreadState_Swap(NULL);
458458
PyInterpreterState_Delete(interp);

0 commit comments

Comments
 (0)