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() |
|