Commit 5a2dcd88 authored by Benjamin Peterson's avatar Benjamin Peterson

Issue #15881: Fixed atexit hook in multiprocessing.

parent 48daafe7
...@@ -247,6 +247,12 @@ def _run_finalizers(minpriority=None): ...@@ -247,6 +247,12 @@ def _run_finalizers(minpriority=None):
Finalizers with highest priority are called first; finalizers with Finalizers with highest priority are called first; finalizers with
the same priority will be called in reverse order of creation. the same priority will be called in reverse order of creation.
''' '''
if _finalizer_registry is None:
# This function may be called after this module's globals are
# destroyed. See the _exit_function function in this module for more
# notes.
return
if minpriority is None: if minpriority is None:
f = lambda p : p[0][0] is not None f = lambda p : p[0][0] is not None
else: else:
...@@ -278,21 +284,38 @@ def is_exiting(): ...@@ -278,21 +284,38 @@ def is_exiting():
_exiting = False _exiting = False
def _exit_function(): def _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers,
active_children=active_children,
current_process=current_process):
# NB: we hold on to references to functions in the arglist due to the
# situation described below, where this function is called after this
# module's globals are destroyed.
global _exiting global _exiting
info('process shutting down') info('process shutting down')
debug('running all "atexit" finalizers with priority >= 0') debug('running all "atexit" finalizers with priority >= 0')
_run_finalizers(0) _run_finalizers(0)
for p in active_children(): if current_process() is not None:
if p._daemonic: # NB: we check if the current process is None here because if
info('calling terminate() for daemon %s', p.name) # it's None, any call to ``active_children()`` will throw an
p._popen.terminate() # AttributeError (active_children winds up trying to get
# attributes from util._current_process). This happens in a
for p in active_children(): # variety of shutdown circumstances that are not well-understood
info('calling join() for process %s', p.name) # because module-scope variables are not apparently supposed to
p.join() # be destroyed until after this function is called. However,
# they are indeed destroyed before this function is called. See
# issues 9775 and 15881. Also related: 4106, 9205, and 9207.
for p in active_children():
if p._daemonic:
info('calling terminate() for daemon %s', p.name)
p._popen.terminate()
for p in active_children():
info('calling join() for process %s', p.name)
p.join()
debug('running the remaining "atexit" finalizers') debug('running the remaining "atexit" finalizers')
_run_finalizers() _run_finalizers()
......
...@@ -202,6 +202,8 @@ Core and Builtins ...@@ -202,6 +202,8 @@ Core and Builtins
Library Library
------- -------
- Issue #15881: Fixed atexit hook in multiprocessing.
- Issue #14340: Upgrade the embedded expat library to version 2.1.0. - Issue #14340: Upgrade the embedded expat library to version 2.1.0.
- Issue #11159: SAX parser now supports unicode file names. - Issue #11159: SAX parser now supports unicode file names.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment