mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									03c29f90c3
								
							
						
					
					
						commit
						6d0d24e359
					
				
					 2 changed files with 26 additions and 1 deletions
				
			
		| 
						 | 
					@ -666,6 +666,29 @@ def main():
 | 
				
			||||||
        rc, out, err = assert_python_ok('-c', script)
 | 
					        rc, out, err = assert_python_ok('-c', script)
 | 
				
			||||||
        self.assertFalse(err)
 | 
					        self.assertFalse(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @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):
 | 
					class ThreadingExceptionTests(BaseTestCase):
 | 
				
			||||||
    # A RuntimeError should be raised if Thread.start() is called
 | 
					    # A RuntimeError should be raised if Thread.start() is called
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -991,11 +991,13 @@ void
 | 
				
			||||||
PyOS_AfterFork(void)
 | 
					PyOS_AfterFork(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef WITH_THREAD
 | 
					#ifdef WITH_THREAD
 | 
				
			||||||
 | 
					    /* PyThread_ReInitTLS() must be called early, to make sure that the TLS API
 | 
				
			||||||
 | 
					     * can be called safely. */
 | 
				
			||||||
 | 
					    PyThread_ReInitTLS();
 | 
				
			||||||
    _PyGILState_Reinit();
 | 
					    _PyGILState_Reinit();
 | 
				
			||||||
    PyEval_ReInitThreads();
 | 
					    PyEval_ReInitThreads();
 | 
				
			||||||
    main_thread = PyThread_get_thread_ident();
 | 
					    main_thread = PyThread_get_thread_ident();
 | 
				
			||||||
    main_pid = getpid();
 | 
					    main_pid = getpid();
 | 
				
			||||||
    _PyImport_ReInitLock();
 | 
					    _PyImport_ReInitLock();
 | 
				
			||||||
    PyThread_ReInitTLS();
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue