components/python/python26/patches/Python26-37-multiproc-race.patch
changeset 4984 7145b15b7f0d
parent 4983 db2589571faa
child 4985 eed3576cafd0
equal deleted inserted replaced
4983:db2589571faa 4984:7145b15b7f0d
     1 This patch comes from upstream: http://bugs.python.org/issue15881
       
     2 
       
     3 It fixes a race condition in multiprocessing/util.py in which globals are
       
     4 deleted during exit but still used during the exit.
       
     5 
       
     6 diff -ur a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py
       
     7 --- a/Lib/multiprocessing/util.py	2014-11-12 08:02:39.431360950 -0800
       
     8 +++ b/Lib/multiprocessing/util.py	2014-11-12 08:03:56.970704872 -0800
       
     9 @@ -221,6 +221,12 @@
       
    10      Finalizers with highest priority are called first; finalizers with
       
    11      the same priority will be called in reverse order of creation.
       
    12      '''
       
    13 +    if _finalizer_registry is None:
       
    14 +        # This function may be called after this module's globals are
       
    15 +        # destroyed.  See the _exit_function function in this module for more
       
    16 +        # notes.
       
    17 +        return
       
    18 +    
       
    19      if minpriority is None:
       
    20          f = lambda p : p[0][0] is not None
       
    21      else:
       
    22 @@ -252,21 +258,38 @@
       
    23  
       
    24  _exiting = False
       
    25  
       
    26 -def _exit_function():
       
    27 +def _exit_function(info=info, debug=debug, _run_finalizers=_run_finalizers,
       
    28 +                   active_children=active_children,
       
    29 +                   current_process=current_process):
       
    30 +    # NB: we hold on to references to functions in the arglist due to the
       
    31 +    # situation described below, where this function is called after this
       
    32 +    # module's globals are destroyed.
       
    33 +
       
    34      global _exiting
       
    35  
       
    36      info('process shutting down')
       
    37      debug('running all "atexit" finalizers with priority >= 0')
       
    38      _run_finalizers(0)
       
    39  
       
    40 -    for p in active_children():
       
    41 -        if p._daemonic:
       
    42 -            info('calling terminate() for daemon %s', p.name)
       
    43 -            p._popen.terminate()
       
    44 -
       
    45 -    for p in active_children():
       
    46 -        info('calling join() for process %s', p.name)
       
    47 -        p.join()
       
    48 +    if current_process() is not None:
       
    49 +        # NB: we check if the current process is None here because if
       
    50 +        # it's None, any call to ``active_children()`` will throw an
       
    51 +        # AttributeError (active_children winds up trying to get
       
    52 +        # attributes from util._current_process).  This happens in a
       
    53 +        # variety of shutdown circumstances that are not well-understood
       
    54 +        # because module-scope variables are not apparently supposed to
       
    55 +        # be destroyed until after this function is called.  However,
       
    56 +        # they are indeed destroyed before this function is called.  See
       
    57 +        # issues 9775 and 15881.  Also related: 4106, 9205, and 9207.
       
    58 +
       
    59 +        for p in active_children():
       
    60 +            if p._daemonic:
       
    61 +                info('calling terminate() for daemon %s', p.name)
       
    62 +                p._popen.terminate()
       
    63 +
       
    64 +        for p in active_children():
       
    65 +            info('calling join() for process %s', p.name)
       
    66 +            p.join()
       
    67  
       
    68      debug('running the remaining "atexit" finalizers')
       
    69      _run_finalizers()