issue #155: handle crash in the forking child better.

This code path is probably only necessary during development, but it
prevents tracebacks (etc.) getting written over the Stream socket, which
naturally causes corruption.

Instead keep whatever the parent has for stderr, manually write a
traceback there and hard exit.
This commit is contained in:
David Wilson 2018-03-29 17:59:23 +05:45
parent 6db3588c93
commit e1af2db4ae
1 changed files with 25 additions and 5 deletions

View File

@ -31,6 +31,7 @@ import os
import random import random
import sys import sys
import threading import threading
import traceback
import mitogen.core import mitogen.core
import mitogen.parent import mitogen.parent
@ -65,6 +66,18 @@ def break_logging_locks():
handler.createLock() handler.createLock()
def handle_child_crash():
"""
Respond to _child_main() crashing by ensuring the relevant exception is
logged to /dev/tty.
"""
sys.stderr.write('\n\nFORKED CHILD PID %d CRASHED\n%s\n\n' % (
os.getpid(),
traceback.format_exc(),
))
os._exit(1)
class Stream(mitogen.parent.Stream): class Stream(mitogen.parent.Stream):
#: Reference to the importer, if any, recovered from the parent. #: Reference to the importer, if any, recovered from the parent.
importer = None importer = None
@ -94,7 +107,13 @@ class Stream(mitogen.parent.Stream):
return self.pid, fd return self.pid, fd
else: else:
parentfp.close() parentfp.close()
self._wrap_child_main(childfp)
def _wrap_child_main(self, childfp):
try:
self._child_main(childfp) self._child_main(childfp)
except BaseException, e:
handle_child_crash()
def _child_main(self, childfp): def _child_main(self, childfp):
mitogen.core.Latch._on_fork() mitogen.core.Latch._on_fork()
@ -113,15 +132,16 @@ 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(childfp.fileno(), 2) os.dup2(sys.stderr.fileno(), 2)
childfp.close() childfp.close()
kwargs = self.get_main_kwargs() kwargs = self.get_main_kwargs()
kwargs['core_src_fd'] = None kwargs['core_src_fd'] = None
kwargs['importer'] = self.importer kwargs['importer'] = self.importer
kwargs['setup_package'] = False kwargs['setup_package'] = False
try:
mitogen.core.ExternalContext().main(**kwargs) mitogen.core.ExternalContext().main(**kwargs)
finally:
# Don't trigger atexit handlers, they were copied from the parent. # Don't trigger atexit handlers, they were copied from the parent.
os._exit(0) os._exit(0)