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:
parent
6db3588c93
commit
e1af2db4ae
|
@ -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,17 +132,18 @@ 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
|
||||||
mitogen.core.ExternalContext().main(**kwargs)
|
try:
|
||||||
|
mitogen.core.ExternalContext().main(**kwargs)
|
||||||
# Don't trigger atexit handlers, they were copied from the parent.
|
finally:
|
||||||
os._exit(0)
|
# Don't trigger atexit handlers, they were copied from the parent.
|
||||||
|
os._exit(0)
|
||||||
|
|
||||||
def _connect_bootstrap(self):
|
def _connect_bootstrap(self):
|
||||||
# None required.
|
# None required.
|
||||||
|
|
Loading…
Reference in New Issue