summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles-François Natali <neologix@free.fr>2012-02-02 18:57:19 (GMT)
committerCharles-François Natali <neologix@free.fr>2012-02-02 18:57:19 (GMT)
commite0e88b0483d73c925e8f1809d24031acd6bfdf01 (patch)
tree97a5539362d668c1ee9f9a0e1dacd20d3786f54d
parentda6db4f8b0fd3de3a5adc6b8f856e80bfda0d40a (diff)
downloadcpython-e0e88b0483d73c925e8f1809d24031acd6bfdf01.zip
cpython-e0e88b0483d73c925e8f1809d24031acd6bfdf01.tar.gz
cpython-e0e88b0483d73c925e8f1809d24031acd6bfdf01.tar.bz2
Issue #13817: After fork(), reinit the ad-hoc TLS implementation earlier to fix
a random deadlock when fork() is called in a multithreaded process in debug mode, and make PyOS_AfterFork() more robust.
-rw-r--r--Lib/test/test_threading.py23
-rw-r--r--Modules/signalmodule.c4
2 files changed, 26 insertions, 1 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index bdb7f14..e617fa1 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -635,6 +635,29 @@ class ThreadJoinOnShutdown(BaseTestCase):
output = "end of worker thread\nend of main thread\n"
self.assertScriptHasOutput(script, output)
+ @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
+ def test_reinit_tls_after_fork(self):
+ # Issue #13817: fork() would deadlock in a multithreaded program with
+ # the ad-hoc TLS implementation.
+
+ def do_fork_and_wait():
+ # just fork a child process and wait it
+ pid = os.fork()
+ if pid > 0:
+ os.waitpid(pid, 0)
+ else:
+ os._exit(0)
+
+ # start a bunch of threads that will fork() child processes
+ threads = []
+ for i in range(16):
+ t = threading.Thread(target=do_fork_and_wait)
+ threads.append(t)
+ t.start()
+
+ for t in threads:
+ t.join()
+
class ThreadingExceptionTests(BaseTestCase):
# A RuntimeError should be raised if Thread.start() is called
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index f306bba..908c2ee 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -976,10 +976,12 @@ void
PyOS_AfterFork(void)
{
#ifdef WITH_THREAD
+ /* PyThread_ReInitTLS() must be called early, to make sure that the TLS API
+ * can be called safely. */
+ PyThread_ReInitTLS();
PyEval_ReInitThreads();
main_thread = PyThread_get_thread_ident();
main_pid = getpid();
_PyImport_ReInitLock();
- PyThread_ReInitTLS();
#endif
}