issue #155: fork.py v2, now with full resource cleanup
This commit is contained in:
parent
872181bebd
commit
2ea65420d0
|
@ -56,18 +56,23 @@ 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
|
||||||
|
|
||||||
def construct(self, old_router, debug=False, profiling=False):
|
#: User-supplied function for cleaning up child process state.
|
||||||
|
on_fork = None
|
||||||
|
|
||||||
|
def construct(self, old_router, on_fork=None, debug=False, profiling=False):
|
||||||
# fork method only supports a tiny subset of options.
|
# fork method only supports a tiny subset of options.
|
||||||
super(Stream, self).construct(debug=debug, profiling=profiling)
|
super(Stream, self).construct(debug=debug, profiling=profiling)
|
||||||
|
self.on_fork = on_fork
|
||||||
|
|
||||||
responder = getattr(old_router, 'responder', None)
|
responder = getattr(old_router, 'responder', None)
|
||||||
if isinstance(responder, mitogen.parent.ModuleForwarder):
|
if isinstance(responder, mitogen.parent.ModuleForwarder):
|
||||||
self.importer = responder.importer
|
self.importer = responder.importer
|
||||||
|
|
||||||
|
name_prefix = 'fork'
|
||||||
|
|
||||||
def create_child(self, *_args):
|
def create_child(self, *_args):
|
||||||
parentfp, childfp = mitogen.parent.create_socketpair()
|
parentfp, childfp = mitogen.parent.create_socketpair()
|
||||||
self.pid = os.fork()
|
self.pid = os.fork()
|
||||||
self.name = 'fork.' + str(self.pid)
|
|
||||||
if self.pid:
|
if self.pid:
|
||||||
childfp.close()
|
childfp.close()
|
||||||
# Decouple the socket from the lifetime of the Python socket object.
|
# Decouple the socket from the lifetime of the Python socket object.
|
||||||
|
@ -79,18 +84,32 @@ class Stream(mitogen.parent.Stream):
|
||||||
self._child_main(childfp)
|
self._child_main(childfp)
|
||||||
|
|
||||||
def _child_main(self, childfp):
|
def _child_main(self, childfp):
|
||||||
# TODO: Latch descriptors inherited from the parent should be closed.
|
mitogen.core.Latch._on_fork()
|
||||||
vars(mitogen.core._tls).clear()
|
mitogen.core.Side._on_fork()
|
||||||
break_logging_locks()
|
break_logging_locks()
|
||||||
|
if self.on_fork:
|
||||||
|
self.on_fork()
|
||||||
mitogen.core.set_block(childfp.fileno())
|
mitogen.core.set_block(childfp.fileno())
|
||||||
|
|
||||||
|
# Expected by the ExternalContext.main().
|
||||||
os.dup2(childfp.fileno(), 1)
|
os.dup2(childfp.fileno(), 1)
|
||||||
os.dup2(childfp.fileno(), 100)
|
os.dup2(childfp.fileno(), 100)
|
||||||
|
# Overwritten by ExternalContext.main(); we must replace the
|
||||||
|
# parent-inherited descriptors that were closed by Side._on_fork() to
|
||||||
|
# avoid ExternalContext.main() accidentally allocating new files over
|
||||||
|
# the standard handles.
|
||||||
|
os.dup2(childfp.fileno(), 0)
|
||||||
|
os.dup2(childfp.fileno(), 2)
|
||||||
|
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)
|
mitogen.core.ExternalContext().main(**kwargs)
|
||||||
sys.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