1 """This test case provides support for checking forking and wait behavior. 2 3 To test different wait behavior, override the wait_impl method. 4 5 We want fork1() semantics -- only the forking thread survives in the 6 child after a fork(). 7 8 On some systems (e.g. Solaris without posix threads) we find that all 9 active threads survive in the child after a fork(); this is an error. 10 """ 11 12 import os, sys, time, unittest 13 import threading 14 import test.support as support 15 16 17 LONGSLEEP = 2 18 SHORTSLEEP = 0.5 19 NUM_THREADS = 4 20 21 class 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): 47 for i in range(10): 48 # waitpid() shouldn't hang, but some of the buildbots seem to hang 49 # in the forking tests. This is an attempt to fix the problem. 50 spid, status = os.waitpid(cpid, os.WNOHANG) 51 if spid == cpid: 52 break 53 time.sleep(2 * SHORTSLEEP) 54 55 self.assertEqual(spid, cpid) 56 self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8)) 57 58 def test_wait(self): 59 for i in range(NUM_THREADS): 60 thread = threading.Thread(target=self.f, args=(i,)) 61 thread.start() 62 self.threads.append(thread) 63 64 # busy-loop to wait for threads 65 deadline = time.monotonic() + 10.0 66 while len(self.alive) < NUM_THREADS: 67 time.sleep(0.1) 68 if deadline < time.monotonic(): 69 break 70 71 a = sorted(self.alive.keys()) 72 self.assertEqual(a, list(range(NUM_THREADS))) 73 74 prefork_lives = self.alive.copy() 75 76 if sys.platform in ['unixware7']: 77 cpid = os.fork1() 78 else: 79 cpid = os.fork() 80 81 if cpid == 0: 82 # Child 83 time.sleep(LONGSLEEP) 84 n = 0 85 for key in self.alive: 86 if self.alive[key] != prefork_lives[key]: 87 n += 1 88 os._exit(n) 89 else: 90 # Parent 91 self.wait_impl(cpid) 92