blob: 8192c38a4491d4d11a045425f946ba8d83c744e0 [file] [log] [blame]
Guido van Rossumf7221c32000-02-25 19:25:05 +00001"""This test checks for correct fork() behavior.
Guido van Rossumf7221c32000-02-25 19:25:05 +00002"""
3
Benjamin Peterson0df35a92009-10-04 20:32:25 +00004import imp
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005import os
Benjamin Peterson0df35a92009-10-04 20:32:25 +00006import signal
7import sys
Thomas Wouters0e3f5912006-08-11 14:57:12 +00008import time
Benjamin Peterson0df35a92009-10-04 20:32:25 +00009
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000010from test.fork_wait import ForkWait
Nick Coghlanb2ddf792010-12-02 04:11:46 +000011from test.support import (run_unittest, reap_children, get_attribute,
12 import_module, verbose)
13
Victor Stinner45df8202010-04-28 22:31:17 +000014threading = import_module('threading')
Guido van Rossumf7221c32000-02-25 19:25:05 +000015
R. David Murraya21e4ca2009-03-31 23:16:50 +000016# Skip test if fork does not exist.
17get_attribute(os, 'fork')
18
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000019class ForkTest(ForkWait):
20 def wait_impl(self, cpid):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021 for i in range(10):
22 # waitpid() shouldn't hang, but some of the buildbots seem to hang
23 # in the forking tests. This is an attempt to fix the problem.
24 spid, status = os.waitpid(cpid, os.WNOHANG)
25 if spid == cpid:
26 break
27 time.sleep(1.0)
28
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000029 self.assertEqual(spid, cpid)
30 self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8))
Guido van Rossumf7221c32000-02-25 19:25:05 +000031
Nick Coghlanb2ddf792010-12-02 04:11:46 +000032 def test_threaded_import_lock_fork(self):
33 """Check fork() in main thread works while a subthread is doing an import"""
Benjamin Peterson0df35a92009-10-04 20:32:25 +000034 import_started = threading.Event()
35 fake_module_name = "fake test module"
36 partial_module = "partial"
37 complete_module = "complete"
38 def importer():
39 imp.acquire_lock()
40 sys.modules[fake_module_name] = partial_module
41 import_started.set()
42 time.sleep(0.01) # Give the other thread time to try and acquire.
43 sys.modules[fake_module_name] = complete_module
44 imp.release_lock()
45 t = threading.Thread(target=importer)
46 t.start()
47 import_started.wait()
48 pid = os.fork()
49 try:
Nick Coghlanb2ddf792010-12-02 04:11:46 +000050 # PyOS_BeforeFork should have waited for the import to complete
51 # before forking, so the child can recreate the import lock
52 # correctly, but also won't see a partially initialised module
Benjamin Peterson0df35a92009-10-04 20:32:25 +000053 if not pid:
54 m = __import__(fake_module_name)
55 if m == complete_module:
56 os._exit(0)
57 else:
Nick Coghlanb2ddf792010-12-02 04:11:46 +000058 if verbose > 1:
59 print("Child encountered partial module")
Benjamin Peterson0df35a92009-10-04 20:32:25 +000060 os._exit(1)
61 else:
62 t.join()
63 # Exitcode 1 means the child got a partial module (bad.) No
64 # exitcode (but a hang, which manifests as 'got pid 0')
65 # means the child deadlocked (also bad.)
66 self.wait_impl(pid)
67 finally:
68 try:
69 os.kill(pid, signal.SIGKILL)
70 except OSError:
71 pass
72
Nick Coghlanb2ddf792010-12-02 04:11:46 +000073
74 def test_nested_import_lock_fork(self):
75 """Check fork() in main thread works while the main thread is doing an import"""
76 # Issue 9573: this used to trigger RuntimeError in the child process
77 def fork_with_import_lock(level):
78 release = 0
79 in_child = False
80 try:
81 try:
82 for i in range(level):
83 imp.acquire_lock()
84 release += 1
85 pid = os.fork()
86 in_child = not pid
87 finally:
88 for i in range(release):
89 imp.release_lock()
90 except RuntimeError:
91 if in_child:
92 if verbose > 1:
93 print("RuntimeError in child")
94 os._exit(1)
95 raise
96 if in_child:
97 os._exit(0)
98 self.wait_impl(pid)
99
100 # Check this works with various levels of nested
101 # import in the main thread
102 for level in range(5):
103 fork_with_import_lock(level)
104
105
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000106def test_main():
107 run_unittest(ForkTest)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000108 reap_children()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000109
110if __name__ == "__main__":
111 test_main()