issue #155: fix double-fork behaviour and test it this time.

pull/175/head
David Wilson 7 years ago
parent 4c433dbed1
commit bbb0f1bbd8

@ -262,7 +262,6 @@ Recovering Mitogen Object References In Children
... ...
Recursion Recursion
--------- ---------

@ -71,10 +71,12 @@ def handle_child_crash():
Respond to _child_main() crashing by ensuring the relevant exception is Respond to _child_main() crashing by ensuring the relevant exception is
logged to /dev/tty. logged to /dev/tty.
""" """
sys.stderr.write('\n\nFORKED CHILD PID %d CRASHED\n%s\n\n' % ( tty = open('/dev/tty', 'wb')
tty.write('\n\nFORKED CHILD PID %d CRASHED\n%s\n\n' % (
os.getpid(), os.getpid(),
traceback.format_exc(), traceback.format_exc(),
)) ))
tty.close()
os._exit(1) os._exit(1)
@ -134,7 +136,13 @@ class Stream(mitogen.parent.Stream):
# avoid ExternalContext.main() accidentally allocating new files over # avoid ExternalContext.main() accidentally allocating new files over
# the standard handles. # the standard handles.
os.dup2(childfp.fileno(), 0) os.dup2(childfp.fileno(), 0)
os.dup2(sys.stderr.fileno(), 2)
# Avoid corrupting the stream on fork crash by dupping /dev/null over
# stderr. Instead, handle_child_crash() uses /dev/tty to log errors.
devnull = os.open('/dev/null', os.O_WRONLY)
if devnull != 2:
os.dup2(devnull, 2)
os.close(devnull)
childfp.close() childfp.close()
kwargs = self.get_main_kwargs() kwargs = self.get_main_kwargs()

@ -26,6 +26,10 @@ c_ssl.RAND_pseudo_bytes.argtypes = [ctypes.c_char_p, ctypes.c_int]
c_ssl.RAND_pseudo_bytes.restype = ctypes.c_int c_ssl.RAND_pseudo_bytes.restype = ctypes.c_int
def ping():
return 123
def random_random(): def random_random():
return random.random() return random.random()
@ -54,5 +58,22 @@ class ForkTest(testlib.RouterMixin, unittest2.TestCase):
RAND_pseudo_bytes()) RAND_pseudo_bytes())
class DoubleChildTest(testlib.RouterMixin, unittest2.TestCase):
def test_okay(self):
# When forking from the master process, Mitogen had nothing to do with
# setting up stdio -- that was inherited wherever the Master is running
# (supervisor, iTerm, etc). When forking from a Mitogen child context
# however, Mitogen owns all of fd 0, 1, and 2, and during the fork
# procedure, it deletes all of these descriptors. That leaves the
# process in a weird state that must be handled by some combination of
# fork.py and ExternalContext.main().
# Below we simply test whether ExternalContext.main() managed to boot
# successfully. In future, we need lots more tests.
c1 = self.router.fork()
c2 = self.router.fork(via=c1)
self.assertEquals(123, c2.call(ping))
if __name__ == '__main__': if __name__ == '__main__':
unittest2.main() unittest2.main()

Loading…
Cancel
Save