• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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