10a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# Very rudimentary test of threading module 20a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 30a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport test.test_support 40a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom test.test_support import verbose 50a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom test.script_helper import assert_python_ok 60a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 70a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport random 80a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport re 90a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport sys 100a8c90248264a8b26970b4473770bcc3df8515fJosh Gaothread = test.test_support.import_module('thread') 110a8c90248264a8b26970b4473770bcc3df8515fJosh Gaothreading = test.test_support.import_module('threading') 120a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport time 130a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport unittest 140a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport weakref 150a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport os 160a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport subprocess 170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 180a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom test import lock_tests 190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# A trivial mutable counter. 210a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass Counter(object): 220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self): 230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.value = 0 240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def inc(self): 250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.value += 1 260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def dec(self): 270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.value -= 1 280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def get(self): 290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return self.value 300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 310a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass TestThread(threading.Thread): 320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self, name, testcase, sema, mutex, nrunning): 330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.Thread.__init__(self, name=name) 340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.testcase = testcase 350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.sema = sema 360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.mutex = mutex 370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.nrunning = nrunning 380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def run(self): 400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao delay = random.random() / 10000.0 410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'task %s will run for %.1f usec' % ( 430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.name, delay * 1e6) 440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao with self.sema: 460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao with self.mutex: 470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.nrunning.inc() 480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print self.nrunning.get(), 'tasks are running' 500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.testcase.assertTrue(self.nrunning.get() <= 3) 510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(delay) 530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'task', self.name, 'done' 550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao with self.mutex: 570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.nrunning.dec() 580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.testcase.assertTrue(self.nrunning.get() >= 0) 590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print '%s is finished. %d tasks are running' % ( 610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.name, self.nrunning.get()) 620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 630a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass BaseTestCase(unittest.TestCase): 640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def setUp(self): 650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._threads = test.test_support.threading_setup() 660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def tearDown(self): 680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test.test_support.threading_cleanup(*self._threads) 690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test.test_support.reap_children() 700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 720a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass ThreadTests(BaseTestCase): 730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Create a bunch of threads, let each do some work, wait until all are 750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # done. 760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_various_ops(self): 770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # This takes about n/3 seconds to run (about n/3 clumps of tasks, 780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # times about 1 second per clump). 790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao NUMTASKS = 10 800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # no more than 3 of the 10 can run at once 820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sema = threading.BoundedSemaphore(value=3) 830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao mutex = threading.RLock() 840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao numrunning = Counter() 850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threads = [] 870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for i in range(NUMTASKS): 890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = TestThread("<thread %d>"%i, self, sema, mutex, numrunning) 900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threads.append(t) 910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(t.ident, None) 920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(re.match('<TestThread\(.*, initial\)>', repr(t))) 930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'waiting for all tasks to complete' 970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for t in threads: 980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.join(NUMTASKS) 990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(not t.is_alive()) 1000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertNotEqual(t.ident, 0) 1010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertFalse(t.ident is None) 1020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(re.match('<TestThread\(.*, \w+ -?\d+\)>', repr(t))) 1030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 1040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'all tasks done' 1050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(numrunning.get(), 0) 1060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_ident_of_no_threading_threads(self): 1080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # The ident still must work for the main thread and dummy threads. 1090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertFalse(threading.currentThread().ident is None) 1100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def f(): 1110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ident.append(threading.currentThread().ident) 1120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao done.set() 1130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao done = threading.Event() 1140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ident = [] 1150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread.start_new_thread(f, ()) 1160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao done.wait() 1170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertFalse(ident[0] is None) 1180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Kill the "immortal" _DummyThread 1190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao del threading._active[ident[0]] 1200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # run with a small(ish) thread stack size (256kB) 1220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_various_ops_small_stack(self): 1230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 1240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'with 256kB thread stack size...' 1250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.stack_size(262144) 1270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except thread.error: 1280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 1290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'platform does not support changing thread stack size' 1300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return 1310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.test_various_ops() 1320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.stack_size(0) 1330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # run with a large thread stack size (1MB) 1350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_various_ops_large_stack(self): 1360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 1370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'with 1MB thread stack size...' 1380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.stack_size(0x100000) 1400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except thread.error: 1410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 1420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'platform does not support changing thread stack size' 1430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return 1440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.test_various_ops() 1450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.stack_size(0) 1460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_foreign_thread(self): 1480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Check that a "foreign" thread can use the threading module. 1490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def f(mutex): 1500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Calling current_thread() forces an entry for the foreign 1510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # thread to get made in the threading._active map. 1520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.current_thread() 1530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao mutex.release() 1540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao mutex = threading.Lock() 1560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao mutex.acquire() 1570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao tid = thread.start_new_thread(f, (mutex,)) 1580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Wait for the thread to finish. 1590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao mutex.acquire() 1600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertIn(tid, threading._active) 1610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertIsInstance(threading._active[tid], threading._DummyThread) 1620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao del threading._active[tid] 1630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently) 1650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # exposed at the Python level. This test relies on ctypes to get at it. 1660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_PyThreadState_SetAsyncExc(self): 1670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import ctypes 1690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except ImportError: 1700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 1710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print "test_PyThreadState_SetAsyncExc can't import ctypes" 1720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return # can't do anything 1730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc 1750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao class AsyncExc(Exception): 1770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 1780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao exception = ctypes.py_object(AsyncExc) 1800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # First check it works when setting the exception from the same thread. 1820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao tid = thread.get_ident() 1830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 1840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao result = set_async_exc(ctypes.c_long(tid), exception) 1860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # The exception is async, so we might have to keep the VM busy until 1870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # it notices. 1880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao while True: 1890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 1900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except AsyncExc: 1910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 1920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 1930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # This code is unreachable but it reflects the intent. If we wanted 1940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # to be smarter the above loop wouldn't be infinite. 1950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.fail("AsyncExc not raised") 1960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 1970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(result, 1) # one thread state modified 1980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except UnboundLocalError: 1990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # The exception was raised too quickly for us to get the result. 2000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 2010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # `worker_started` is set by the thread when it's inside a try/except 2030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # block waiting to catch the asynchronously set AsyncExc exception. 2040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # `worker_saw_exception` is set by the thread upon catching that 2050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # exception. 2060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao worker_started = threading.Event() 2070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao worker_saw_exception = threading.Event() 2080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao class Worker(threading.Thread): 2100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def run(self): 2110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.id = thread.get_ident() 2120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.finished = False 2130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 2150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao while True: 2160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao worker_started.set() 2170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(0.1) 2180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except AsyncExc: 2190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.finished = True 2200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao worker_saw_exception.set() 2210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = Worker() 2230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.daemon = True # so if this fails, we don't hang Python at shutdown 2240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 2250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print " started worker thread" 2270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Try a thread id that doesn't make sense. 2290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print " trying nonsensical thread id" 2310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao result = set_async_exc(ctypes.c_long(-1), exception) 2320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(result, 0) # no thread states modified 2330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Now raise an exception in the worker thread. 2350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print " waiting for worker thread to get started" 2370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ret = worker_started.wait() 2380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(ret) 2390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print " verifying worker hasn't exited" 2410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(not t.finished) 2420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print " attempting to raise asynch exception in worker" 2440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao result = set_async_exc(ctypes.c_long(t.id), exception) 2450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(result, 1) # one thread state modified 2460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print " waiting for worker to say it caught the exception" 2480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao worker_saw_exception.wait(timeout=10) 2490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(t.finished) 2500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print " all OK -- joining worker" 2520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if t.finished: 2530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.join() 2540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # else the thread is still running, and we have no way to kill it 2550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_limbo_cleanup(self): 2570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Issue 7481: Failure to start thread should cleanup the limbo map. 2580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def fail_new_thread(*args): 2590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise thread.error() 2600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao _start_new_thread = threading._start_new_thread 2610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading._start_new_thread = fail_new_thread 2620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 2630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = threading.Thread(target=lambda: None) 2640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertRaises(thread.error, t.start) 2650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertFalse( 2660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t in threading._limbo, 2670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "Failed to cleanup _limbo map on failure of Thread.start().") 2680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao finally: 2690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading._start_new_thread = _start_new_thread 2700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_finalize_runnning_thread(self): 2720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Issue 1402: the PyGILState_Ensure / _Release functions may be called 2730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # very late on python exit: on deallocation of a running thread for 2740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # example. 2750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 2760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import ctypes 2770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except ImportError: 2780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if verbose: 2790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print("test_finalize_with_runnning_thread can't import ctypes") 2800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return # can't do anything 2810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao rc = subprocess.call([sys.executable, "-c", """if 1: 2830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import ctypes, sys, time, thread 2840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # This lock is used as a simple event variable. 2860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ready = thread.allocate_lock() 2870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ready.acquire() 2880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Module globals are cleared before __del__ is run 2900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # So we save the functions in class dict 2910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao class C: 2920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ensure = ctypes.pythonapi.PyGILState_Ensure 2930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao release = ctypes.pythonapi.PyGILState_Release 2940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __del__(self): 2950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao state = self.ensure() 2960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.release(state) 2970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 2980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def waitingThread(): 2990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao x = C() 3000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ready.release() 3010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(100) 3020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread.start_new_thread(waitingThread, ()) 3040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ready.acquire() # Be sure the other thread is waiting. 3050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.exit(42) 3060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """]) 3070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(rc, 42) 3080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_finalize_with_trace(self): 3100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Issue1733757 3110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Avoid a deadlock when sys.settrace steps into threading._shutdown 3120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p = subprocess.Popen([sys.executable, "-c", """if 1: 3130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import sys, threading 3140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # A deadlock-killer, to prevent the 3160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # testsuite to hang forever 3170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def killer(): 3180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import os, time 3190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(2) 3200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'program blocked; aborting' 3210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os._exit(2) 3220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = threading.Thread(target=killer) 3230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.daemon = True 3240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 3250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # This is the trace function 3270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def func(frame, event, arg): 3280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.current_thread() 3290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return func 3300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.settrace(func) 3320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """], 3330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stdout=subprocess.PIPE, 3340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stderr=subprocess.PIPE) 3350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.addCleanup(p.stdout.close) 3360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.addCleanup(p.stderr.close) 3370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stdout, stderr = p.communicate() 3380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao rc = p.returncode 3390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertFalse(rc == 2, "interpreted was blocked") 3400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(rc == 0, 3410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "Unexpected error: " + repr(stderr)) 3420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_join_nondaemon_on_shutdown(self): 3440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Issue 1722344 3450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Raising SystemExit skipped threading._shutdown 3460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p = subprocess.Popen([sys.executable, "-c", """if 1: 3470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import threading 3480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao from time import sleep 3490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def child(): 3510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sleep(1) 3520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # As a non-daemon thread we SHOULD wake up and nothing 3530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # should be torn down yet 3540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print "Woke up, sleep function is:", sleep 3550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.Thread(target=child).start() 3570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise SystemExit 3580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """], 3590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stdout=subprocess.PIPE, 3600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stderr=subprocess.PIPE) 3610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.addCleanup(p.stdout.close) 3620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.addCleanup(p.stderr.close) 3630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stdout, stderr = p.communicate() 3640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(stdout.strip(), 3650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "Woke up, sleep function is: <built-in function sleep>") 3660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stderr = re.sub(r"^\[\d+ refs\]", "", stderr, re.MULTILINE).strip() 3670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(stderr, "") 3680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_enumerate_after_join(self): 3700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Try hard to trigger #1703448: a thread is still returned in 3710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # threading.enumerate() after it has been join()ed. 3720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao enum = threading.enumerate 3730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao old_interval = sys.getcheckinterval() 3740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 3750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for i in xrange(1, 100): 3760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Try a couple times at each thread-switching interval 3770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # to get more interleavings. 3780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.setcheckinterval(i // 5) 3790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = threading.Thread(target=lambda: None) 3800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 3810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.join() 3820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao l = enum() 3830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertNotIn(t, l, 3840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao "#1703448 triggered after %d trials: %s" % (i, l)) 3850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao finally: 3860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.setcheckinterval(old_interval) 3870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_no_refcycle_through_target(self): 3890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao class RunSelfFunction(object): 3900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def __init__(self, should_raise): 3910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # The links in this refcycle from Thread back to self 3920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # should be cleaned up when the thread completes. 3930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.should_raise = should_raise 3940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.thread = threading.Thread(target=self._run, 3950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao args=(self,), 3960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao kwargs={'yet_another':self}) 3970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.thread.start() 3980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 3990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def _run(self, other_ref, yet_another): 4000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if self.should_raise: 4010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raise SystemExit 4020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao cyclic_object = RunSelfFunction(should_raise=False) 4040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao weak_cyclic_object = weakref.ref(cyclic_object) 4050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao cyclic_object.thread.join() 4060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao del cyclic_object 4070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(None, weak_cyclic_object(), 4080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao msg=('%d references still around' % 4090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.getrefcount(weak_cyclic_object()))) 4100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raising_cyclic_object = RunSelfFunction(should_raise=True) 4120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao weak_raising_cyclic_object = weakref.ref(raising_cyclic_object) 4130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao raising_cyclic_object.thread.join() 4140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao del raising_cyclic_object 4150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(None, weak_raising_cyclic_object(), 4160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao msg=('%d references still around' % 4170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.getrefcount(weak_raising_cyclic_object()))) 4180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()') 4200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_dummy_thread_after_fork(self): 4210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Issue #14308: a dummy thread in the active list doesn't mess up 4220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # the after-fork mechanism. 4230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao code = """if 1: 4240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import thread, threading, os, time 4250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def background_thread(evt): 4270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Creates and registers the _DummyThread instance 4280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threading.current_thread() 4290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao evt.set() 4300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(10) 4310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao evt = threading.Event() 4330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread.start_new_thread(background_thread, (evt,)) 4340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao evt.wait() 4350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao assert threading.active_count() == 2, threading.active_count() 4360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if os.fork() == 0: 4370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao assert threading.active_count() == 1, threading.active_count() 4380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os._exit(0) 4390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 4400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os.wait() 4410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 4420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao _, out, err = assert_python_ok("-c", code) 4430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(out, '') 4440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(err, '') 4450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4470a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass ThreadJoinOnShutdown(BaseTestCase): 4480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Between fork() and exec(), only async-safe functions are allowed (issues 4500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # #12316 and #11870), and fork() from a worker thread is known to trigger 4510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # problems with some operating systems (issue #3863): skip problematic tests 4520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # on platforms known to behave badly. 4530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao platforms_to_skip = ('freebsd4', 'freebsd5', 'freebsd6', 'netbsd5', 4540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 'os2emx') 4550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def _run_and_join(self, script): 4570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao script = """if 1: 4580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import sys, os, time, threading 4590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # a thread, which waits for the main program to terminate 4610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def joiningfunc(mainthread): 4620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao mainthread.join() 4630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'end of thread' 4640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao \n""" + script 4650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE) 4670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao rc = p.wait() 4680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao data = p.stdout.read().replace('\r', '') 4690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p.stdout.close() 4700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(data, "end of main\nend of thread\n") 4710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertFalse(rc == 2, "interpreter was blocked") 4720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertTrue(rc == 0, "Unexpected error") 4730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_1_join_on_shutdown(self): 4750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # The usual case: on exit, wait for a non-daemon thread 4760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao script = """if 1: 4770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import os 4780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = threading.Thread(target=joiningfunc, 4790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao args=(threading.current_thread(),)) 4800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 4810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(0.1) 4820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'end of main' 4830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 4840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._run_and_join(script) 4850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") 4880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") 4890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_2_join_in_forked_process(self): 4900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Like the test above, but from a forked interpreter 4910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao script = """if 1: 4920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao childpid = os.fork() 4930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if childpid != 0: 4940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os.waitpid(childpid, 0) 4950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.exit(0) 4960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 4970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = threading.Thread(target=joiningfunc, 4980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao args=(threading.current_thread(),)) 4990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 5000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'end of main' 5010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 5020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._run_and_join(script) 5030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") 5050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") 5060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_3_join_in_forked_from_thread(self): 5070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Like the test above, but fork() was called from a worker thread 5080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # In the forked process, the main Thread object must be marked as stopped. 5090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao script = """if 1: 5100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao main_thread = threading.current_thread() 5110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def worker(): 5120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao childpid = os.fork() 5130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if childpid != 0: 5140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os.waitpid(childpid, 0) 5150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao sys.exit(0) 5160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = threading.Thread(target=joiningfunc, 5180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao args=(main_thread,)) 5190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print 'end of main' 5200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 5210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.join() # Should not block: main_thread is already stopped 5220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w = threading.Thread(target=worker) 5240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w.start() 5250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 5260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self._run_and_join(script) 5270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def assertScriptHasOutput(self, script, expected_output): 5290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p = subprocess.Popen([sys.executable, "-c", script], 5300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stdout=subprocess.PIPE) 5310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao rc = p.wait() 5320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao data = p.stdout.read().decode().replace('\r', '') 5330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(rc, 0, "Unexpected error") 5340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(data, expected_output) 5350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") 5370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") 5380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_4_joining_across_fork_in_worker_thread(self): 5390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # There used to be a possible deadlock when forking from a child 5400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # thread. See http://bugs.python.org/issue6643. 5410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # The script takes the following steps: 5430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # - The main thread in the parent process starts a new thread and then 5440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # tries to join it. 5450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # - The join operation acquires the Lock inside the thread's _block 5460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Condition. (See threading.py:Thread.join().) 5470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # - We stub out the acquire method on the condition to force it to wait 5480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # until the child thread forks. (See LOCK ACQUIRED HERE) 5490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # - The child thread forks. (See LOCK HELD and WORKER THREAD FORKS 5500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # HERE) 5510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # - The main thread of the parent process enters Condition.wait(), 5520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # which releases the lock on the child thread. 5530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # - The child process returns. Without the necessary fix, when the 5540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # main thread of the child process (which used to be the child thread 5550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # in the parent process) attempts to exit, it will try to acquire the 5560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # lock in the Thread._block Condition object and hang, because the 5570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # lock was held across the fork. 5580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao script = """if 1: 5600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import os, time, threading 5610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao finish_join = False 5630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao start_fork = False 5640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def worker(): 5660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Wait until this thread's lock is acquired before forking to 5670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # create the deadlock. 5680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao global finish_join 5690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao while not start_fork: 5700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(0.01) 5710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # LOCK HELD: Main thread holds lock across this call. 5720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao childpid = os.fork() 5730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao finish_join = True 5740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if childpid != 0: 5750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Parent process just waits for child. 5760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os.waitpid(childpid, 0) 5770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Child process should just return. 5780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w = threading.Thread(target=worker) 5800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 5810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Stub out the private condition variable's lock acquire method. 5820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # This acquires the lock and then waits until the child has forked 5830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # before returning, which will release the lock soon after. If 5840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # someone else tries to fix this test case by acquiring this lock 5850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # before forking instead of resetting it, the test case will 5860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # deadlock when it shouldn't. 5870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao condition = w._block 5880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao orig_acquire = condition.acquire 5890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao call_count_lock = threading.Lock() 5900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao call_count = 0 5910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def my_acquire(): 5920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao global call_count 5930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao global start_fork 5940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao orig_acquire() # LOCK ACQUIRED HERE 5950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao start_fork = True 5960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if call_count == 0: 5970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao while not finish_join: 5980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(0.01) # WORKER THREAD FORKS HERE 5990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao with call_count_lock: 6000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao call_count += 1 6010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao condition.acquire = my_acquire 6020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w.start() 6040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w.join() 6050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print('end of main') 6060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 6070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertScriptHasOutput(script, "end of main\n") 6080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") 6100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") 6110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_5_clear_waiter_locks_to_avoid_crash(self): 6120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Check that a spawned thread that forks doesn't segfault on certain 6130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # platforms, namely OS X. This used to happen if there was a waiter 6140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # lock in the thread's condition variable's waiters list. Even though 6150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # we know the lock will be held across the fork, it is not safe to 6160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # release locks held across forks on all platforms, so releasing the 6170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # waiter lock caused a segfault on OS X. Furthermore, since locks on 6180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # OS X are (as of this writing) implemented with a mutex + condition 6190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # variable instead of a semaphore, while we know that the Python-level 6200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # lock will be acquired, we can't know if the internal mutex will be 6210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # acquired at the time of the fork. 6220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao script = """if True: 6240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import os, time, threading 6250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao start_fork = False 6270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def worker(): 6290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Wait until the main thread has attempted to join this thread 6300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # before continuing. 6310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao while not start_fork: 6320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao time.sleep(0.01) 6330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao childpid = os.fork() 6340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if childpid != 0: 6350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Parent process just waits for child. 6360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao (cpid, rc) = os.waitpid(childpid, 0) 6370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao assert cpid == childpid 6380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao assert rc == 0 6390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print('end of worker thread') 6400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 6410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Child process should just return. 6420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 6430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w = threading.Thread(target=worker) 6450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Stub out the private condition variable's _release_save method. 6470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # This releases the condition's lock and flips the global that 6480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # causes the worker to fork. At this point, the problematic waiter 6490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # lock has been acquired once by the waiter and has been put onto 6500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # the waiters list. 6510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao condition = w._block 6520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao orig_release_save = condition._release_save 6530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def my_release_save(): 6540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao global start_fork 6550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao orig_release_save() 6560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Waiter lock held here, condition lock released. 6570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao start_fork = True 6580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao condition._release_save = my_release_save 6590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w.start() 6610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w.join() 6620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print('end of main thread') 6630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 6640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao output = "end of worker thread\nend of main thread\n" 6650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertScriptHasOutput(script, output) 6660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") 6680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") 6690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_reinit_tls_after_fork(self): 6700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Issue #13817: fork() would deadlock in a multithreaded program with 6710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # the ad-hoc TLS implementation. 6720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def do_fork_and_wait(): 6740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # just fork a child process and wait it 6750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pid = os.fork() 6760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao if pid > 0: 6770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os.waitpid(pid, 0) 6780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao else: 6790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao os._exit(0) 6800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # start a bunch of threads that will fork() child processes 6820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threads = [] 6830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for i in range(16): 6840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t = threading.Thread(target=do_fork_and_wait) 6850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao threads.append(t) 6860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.start() 6870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao for t in threads: 6890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao t.join() 6900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 6920a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass ThreadingExceptionTests(BaseTestCase): 6930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # A RuntimeError should be raised if Thread.start() is called 6940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # multiple times. 6950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_start_thread_again(self): 6960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread = threading.Thread() 6970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread.start() 6980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertRaises(RuntimeError, thread.start) 6990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_joining_current_thread(self): 7010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao current_thread = threading.current_thread() 7020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertRaises(RuntimeError, current_thread.join); 7030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_joining_inactive_thread(self): 7050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread = threading.Thread() 7060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertRaises(RuntimeError, thread.join) 7070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_daemonize_active_thread(self): 7090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread = threading.Thread() 7100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao thread.start() 7110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertRaises(RuntimeError, setattr, thread, "daemon", True) 7120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7140a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass LockTests(lock_tests.LockTests): 7150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao locktype = staticmethod(threading.Lock) 7160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7170a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass RLockTests(lock_tests.RLockTests): 7180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao locktype = staticmethod(threading.RLock) 7190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7200a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass EventTests(lock_tests.EventTests): 7210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao eventtype = staticmethod(threading.Event) 7220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7230a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass ConditionAsRLockTests(lock_tests.RLockTests): 7240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # An Condition uses an RLock by default and exports its API. 7250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao locktype = staticmethod(threading.Condition) 7260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7270a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass ConditionTests(lock_tests.ConditionTests): 7280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao condtype = staticmethod(threading.Condition) 7290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7300a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass SemaphoreTests(lock_tests.SemaphoreTests): 7310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao semtype = staticmethod(threading.Semaphore) 7320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7330a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass BoundedSemaphoreTests(lock_tests.BoundedSemaphoreTests): 7340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao semtype = staticmethod(threading.BoundedSemaphore) 7350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao @unittest.skipUnless(sys.platform == 'darwin', 'test macosx problem') 7370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def test_recursion_limit(self): 7380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # Issue 9670 7390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # test that excessive recursion within a non-main thread causes 7400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # an exception rather than crashing the interpreter on platforms 7410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # like Mac OS X or FreeBSD which have small default stack sizes 7420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao # for threads 7430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao script = """if True: 7440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao import threading 7450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def recurse(): 7470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao return recurse() 7480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao def outer(): 7500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao try: 7510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao recurse() 7520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao except RuntimeError: 7530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao pass 7540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w = threading.Thread(target=outer) 7560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w.start() 7570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao w.join() 7580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao print('end of main thread') 7590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao """ 7600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao expected_output = "end of main thread\n" 7610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao p = subprocess.Popen([sys.executable, "-c", script], 7620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stdout=subprocess.PIPE) 7630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao stdout, stderr = p.communicate() 7640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao data = stdout.decode().replace('\r', '') 7650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(p.returncode, 0, "Unexpected error") 7660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao self.assertEqual(data, expected_output) 7670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7680a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef test_main(): 7690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test.test_support.run_unittest(LockTests, RLockTests, EventTests, 7700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ConditionAsRLockTests, ConditionTests, 7710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao SemaphoreTests, BoundedSemaphoreTests, 7720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ThreadTests, 7730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ThreadJoinOnShutdown, 7740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ThreadingExceptionTests, 7750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao ) 7760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao 7770a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoif __name__ == "__main__": 7780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao test_main() 779