Mercurial > public > mercurial-scm > hg
comparison mercurial/worker.py @ 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 |
comparison
equal
deleted
inserted
replaced
30422:0e6ce6313e47 | 30423:237b2883cbd8 |
---|---|
87 workers = _numworkers(ui) | 87 workers = _numworkers(ui) |
88 oldhandler = signal.getsignal(signal.SIGINT) | 88 oldhandler = signal.getsignal(signal.SIGINT) |
89 signal.signal(signal.SIGINT, signal.SIG_IGN) | 89 signal.signal(signal.SIGINT, signal.SIG_IGN) |
90 pids, problem = set(), [0] | 90 pids, problem = set(), [0] |
91 def killworkers(): | 91 def killworkers(): |
92 # unregister SIGCHLD handler as all children will be killed. This | |
93 # function shouldn't be interrupted by another SIGCHLD; otherwise pids | |
94 # could be updated while iterating, which would cause inconsistency. | |
95 signal.signal(signal.SIGCHLD, oldchldhandler) | |
92 # if one worker bails, there's no good reason to wait for the rest | 96 # if one worker bails, there's no good reason to wait for the rest |
93 for p in pids: | 97 for p in pids: |
94 try: | 98 try: |
95 os.kill(p, signal.SIGTERM) | 99 os.kill(p, signal.SIGTERM) |
96 except OSError as err: | 100 except OSError as err: |
113 if p: | 117 if p: |
114 pids.remove(p) | 118 pids.remove(p) |
115 st = _exitstatus(st) | 119 st = _exitstatus(st) |
116 if st and not problem[0]: | 120 if st and not problem[0]: |
117 problem[0] = st | 121 problem[0] = st |
118 # unregister SIGCHLD handler as all children will be killed | |
119 signal.signal(signal.SIGCHLD, oldchldhandler) | |
120 killworkers() | 122 killworkers() |
121 def sigchldhandler(signum, frame): | 123 def sigchldhandler(signum, frame): |
122 waitforworkers(blocking=False) | 124 waitforworkers(blocking=False) |
123 oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler) | 125 oldchldhandler = signal.signal(signal.SIGCHLD, sigchldhandler) |
124 for pargs in partition(args, workers): | 126 for pargs in partition(args, workers): |