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 15from test.support import threading_helper 16 17 18LONGSLEEP = 2 19SHORTSLEEP = 0.5 20NUM_THREADS = 4 21 22class ForkWait(unittest.TestCase): 23 24 def setUp(self): 25 self._threading_key = threading_helper.threading_setup() 26 self.alive = {} 27 self.stop = 0 28 self.threads = [] 29 30 def tearDown(self): 31 # Stop threads 32 self.stop = 1 33 for thread in self.threads: 34 thread.join() 35 thread = None 36 self.threads.clear() 37 threading_helper.threading_cleanup(*self._threading_key) 38 39 def f(self, id): 40 while not self.stop: 41 self.alive[id] = os.getpid() 42 try: 43 time.sleep(SHORTSLEEP) 44 except OSError: 45 pass 46 47 def wait_impl(self, cpid, *, exitcode): 48 support.wait_process(cpid, exitcode=exitcode) 49 50 def test_wait(self): 51 for i in range(NUM_THREADS): 52 thread = threading.Thread(target=self.f, args=(i,)) 53 thread.start() 54 self.threads.append(thread) 55 56 # busy-loop to wait for threads 57 deadline = time.monotonic() + support.SHORT_TIMEOUT 58 while len(self.alive) < NUM_THREADS: 59 time.sleep(0.1) 60 if deadline < time.monotonic(): 61 break 62 63 a = sorted(self.alive.keys()) 64 self.assertEqual(a, list(range(NUM_THREADS))) 65 66 prefork_lives = self.alive.copy() 67 68 if sys.platform in ['unixware7']: 69 cpid = os.fork1() 70 else: 71 cpid = os.fork() 72 73 if cpid == 0: 74 # Child 75 time.sleep(LONGSLEEP) 76 n = 0 77 for key in self.alive: 78 if self.alive[key] != prefork_lives[key]: 79 n += 1 80 os._exit(n) 81 else: 82 # Parent 83 self.wait_impl(cpid, exitcode=0) 84