1"""This test case provides support for checking forking and wait behavior. 2 3To test different wait behavior, override the wait_impl method. 4 5We want fork1() semantics -- only the forking thread survives in the 6child after a fork(). 7 8On some systems (e.g. Solaris without posix threads) we find that all 9active threads survive in the child after a fork(); this is an error. 10""" 11 12import os, sys, time, unittest 13import threading 14from test import support 15 16 17LONGSLEEP = 2 18SHORTSLEEP = 0.5 19NUM_THREADS = 4 20 21class ForkWait(unittest.TestCase): 22 23 def setUp(self): 24 self._threading_key = support.threading_setup() 25 self.alive = {} 26 self.stop = 0 27 self.threads = [] 28 29 def tearDown(self): 30 # Stop threads 31 self.stop = 1 32 for thread in self.threads: 33 thread.join() 34 thread = None 35 self.threads.clear() 36 support.threading_cleanup(*self._threading_key) 37 38 def f(self, id): 39 while not self.stop: 40 self.alive[id] = os.getpid() 41 try: 42 time.sleep(SHORTSLEEP) 43 except OSError: 44 pass 45 46 def wait_impl(self, cpid, *, exitcode): 47 support.wait_process(cpid, exitcode=exitcode) 48 49 def test_wait(self): 50 for i in range(NUM_THREADS): 51 thread = threading.Thread(target=self.f, args=(i,)) 52 thread.start() 53 self.threads.append(thread) 54 55 # busy-loop to wait for threads 56 deadline = time.monotonic() + support.SHORT_TIMEOUT 57 while len(self.alive) < NUM_THREADS: 58 time.sleep(0.1) 59 if deadline < time.monotonic(): 60 break 61 62 a = sorted(self.alive.keys()) 63 self.assertEqual(a, list(range(NUM_THREADS))) 64 65 prefork_lives = self.alive.copy() 66 67 if sys.platform in ['unixware7']: 68 cpid = os.fork1() 69 else: 70 cpid = os.fork() 71 72 if cpid == 0: 73 # Child 74 time.sleep(LONGSLEEP) 75 n = 0 76 for key in self.alive: 77 if self.alive[key] != prefork_lives[key]: 78 n += 1 79 os._exit(n) 80 else: 81 # Parent 82 self.wait_impl(cpid, exitcode=0) 83