Show More
@@ -134,37 +134,43 b' def _posixworker(ui, func, staticargs, a' | |||||
134 | killworkers() |
|
134 | killworkers() | |
135 | oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler) |
|
135 | oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler) | |
136 | ui.flush() |
|
136 | ui.flush() | |
|
137 | parentpid = os.getpid() | |||
137 | for pargs in partition(args, workers): |
|
138 | for pargs in partition(args, workers): | |
138 | pid = os.fork() |
|
139 | # make sure we use os._exit in all worker code paths. otherwise the | |
139 | if pid == 0: |
|
140 | # worker may do some clean-ups which could cause surprises like | |
140 | signal.signal(signal.SIGINT, oldhandler) |
|
141 | # deadlock. see sshpeer.cleanup for example. | |
141 | signal.signal(signal.SIGCHLD, oldchldhandler) |
|
142 | # override error handling *before* fork. this is necessary because | |
142 |
|
143 | # exception (signal) may arrive after fork, before "pid =" assignment | ||
143 | def workerfunc(): |
|
144 | # completes, and other exception handler (dispatch.py) can lead to | |
144 | os.close(rfd) |
|
145 | # unexpected code path without os._exit. | |
145 | for i, item in func(*(staticargs + (pargs,))): |
|
146 | ret = -1 | |
146 | os.write(wfd, '%d %s\n' % (i, item)) |
|
147 | try: | |
147 | return 0 |
|
148 | pid = os.fork() | |
|
149 | if pid == 0: | |||
|
150 | signal.signal(signal.SIGINT, oldhandler) | |||
|
151 | signal.signal(signal.SIGCHLD, oldchldhandler) | |||
148 |
|
152 | |||
149 | # make sure we use os._exit in all code paths. otherwise the worker |
|
153 | def workerfunc(): | |
150 | # may do some clean-ups which could cause surprises like deadlock. |
|
154 | os.close(rfd) | |
151 | # see sshpeer.cleanup for example. |
|
155 | for i, item in func(*(staticargs + (pargs,))): | |
152 | ret = 0 |
|
156 | os.write(wfd, '%d %s\n' % (i, item)) | |
153 |
|
|
157 | return 0 | |
|
158 | ||||
|
159 | ret = scmutil.callcatch(ui, workerfunc) | |||
|
160 | except: # parent re-raises, child never returns | |||
|
161 | if os.getpid() == parentpid: | |||
|
162 | raise | |||
|
163 | exctype = sys.exc_info()[0] | |||
|
164 | force = not issubclass(exctype, KeyboardInterrupt) | |||
|
165 | ui.traceback(force=force) | |||
|
166 | finally: | |||
|
167 | if os.getpid() != parentpid: | |||
154 | try: |
|
168 | try: | |
155 | ret = scmutil.callcatch(ui, workerfunc) |
|
|||
156 | finally: |
|
|||
157 | ui.flush() |
|
169 | ui.flush() | |
158 | except KeyboardInterrupt: |
|
170 | except: # never returns, no re-raises | |
159 |
|
|
171 | pass | |
160 | except: # never return, therefore no re-raises |
|
|||
161 | try: |
|
|||
162 | ui.traceback(force=True) |
|
|||
163 | ui.flush() |
|
|||
164 | finally: |
|
172 | finally: | |
165 | os._exit(255) |
|
173 | os._exit(ret & 255) | |
166 | else: |
|
|||
167 | os._exit(ret & 255) |
|
|||
168 | pids.add(pid) |
|
174 | pids.add(pid) | |
169 | os.close(wfd) |
|
175 | os.close(wfd) | |
170 | fp = os.fdopen(rfd, pycompat.sysstr('rb'), 0) |
|
176 | fp = os.fdopen(rfd, pycompat.sysstr('rb'), 0) |
@@ -91,4 +91,36 b' Traceback must be printed for unknown ex' | |||||
91 | > test 100000.0 exc 2>&1 | grep '^Traceback' |
|
91 | > test 100000.0 exc 2>&1 | grep '^Traceback' | |
92 | Traceback (most recent call last): |
|
92 | Traceback (most recent call last): | |
93 |
|
93 | |||
|
94 | Workers should not do cleanups in all cases | |||
|
95 | ||||
|
96 | $ cat > $TESTTMP/detectcleanup.py <<EOF | |||
|
97 | > from __future__ import absolute_import | |||
|
98 | > import atexit | |||
|
99 | > import os | |||
|
100 | > import time | |||
|
101 | > oldfork = os.fork | |||
|
102 | > count = 0 | |||
|
103 | > parentpid = os.getpid() | |||
|
104 | > def delayedfork(): | |||
|
105 | > global count | |||
|
106 | > count += 1 | |||
|
107 | > pid = oldfork() | |||
|
108 | > # make it easier to test SIGTERM hitting other workers when they have | |||
|
109 | > # not set up error handling yet. | |||
|
110 | > if count > 1 and pid == 0: | |||
|
111 | > time.sleep(0.1) | |||
|
112 | > return pid | |||
|
113 | > os.fork = delayedfork | |||
|
114 | > def cleanup(): | |||
|
115 | > if os.getpid() != parentpid: | |||
|
116 | > os.write(1, 'should never happen\n') | |||
|
117 | > atexit.register(cleanup) | |||
|
118 | > EOF | |||
|
119 | ||||
|
120 | $ hg --config "extensions.t=$abspath" --config worker.numcpus=8 --config \ | |||
|
121 | > "extensions.d=$TESTTMP/detectcleanup.py" test 100000 abort | |||
|
122 | start | |||
|
123 | abort: known exception | |||
|
124 | [255] | |||
|
125 | ||||
94 | #endif |
|
126 | #endif |
General Comments 0
You need to be logged in to leave comments.
Login now