Home | History | Annotate | Download | only in test
      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