worker: make sure killworkers() never be interrupted by another SIGCHLD
killworkers() iterates over pids, which can be updated by SIGCHLD handler.
So we should either copy pids or prevent killworkers() from being interrupted
by SIGCHLD. I chose the latter as it is simpler and can make pids handling
more consistent.
This fixes a possible "set changed size during iteration" error at
killworkers() before cleanup().
--- a/mercurial/worker.py Thu Nov 17 21:43:01 2016 +0900
+++ b/mercurial/worker.py Thu Nov 17 20:44:05 2016 +0900
@@ -89,6 +89,10 @@
signal.signal(signal.SIGINT, signal.SIG_IGN)
pids, problem = set(), [0]
def killworkers():
+ # unregister SIGCHLD handler as all children will be killed. This
+ # function shouldn't be interrupted by another SIGCHLD; otherwise pids
+ # could be updated while iterating, which would cause inconsistency.
+ signal.signal(signal.SIGCHLD, oldchldhandler)
# if one worker bails, there's no good reason to wait for the rest
for p in pids:
try:
@@ -115,8 +119,6 @@
st = _exitstatus(st)
if st and not problem[0]:
problem[0] = st
- # unregister SIGCHLD handler as all children will be killed
- signal.signal(signal.SIGCHLD, oldchldhandler)
killworkers()
def sigchldhandler(signum, frame):
waitforworkers(blocking=False)