changeset 30423:237b2883cbd8

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().
author Yuya Nishihara <yuya@tcha.org>
date Thu, 17 Nov 2016 20:44:05 +0900
parents 0e6ce6313e47
children f2d13eb85198
files mercurial/worker.py
diffstat 1 files changed, 4 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- 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)