Submitter | Jun Wu |
---|---|
Date | Nov. 12, 2016, 3:11 a.m. |
Message ID | <596cee9d5c12dcfa2d27.1478920297@x1c> |
Download | mbox | patch |
Permalink | /patch/17512/ |
State | Changes Requested |
Headers | show |
Comments
On Sat, 12 Nov 2016 03:11:37 +0000, Jun Wu wrote: > # HG changeset patch > # User Jun Wu <quark@fb.com> > # Date 1478919468 0 > # Sat Nov 12 02:57:48 2016 +0000 > # Node ID 596cee9d5c12dcfa2d272b5441d5060a26a6440c > # Parent ca128e326027530210f6509e3ec8b28b97bdce12 > # Available At https://bitbucket.org/quark-zju/hg-draft > # hg pull https://bitbucket.org/quark-zju/hg-draft -r 596cee9d5c12 > worker: make killworkers safe to be called multiple times [...] > --- a/mercurial/worker.py > +++ b/mercurial/worker.py > @@ -89,5 +89,14 @@ def _posixworker(ui, func, staticargs, a > def killworkers(): > # if one worker bails, there's no good reason to wait for the rest > - for p in pids: > + # note: use "while pids" instead of "for p in pids" as other code may > + # get run by a signal handler and change "pids" in the mean time. > + while pids: > + try: > + # note: set.pop() cannot be interrupted by a Python signal > + # handler - this is true for both cpython and pypy. we use this > + # property to make sure a child receive the signal once. > + p = pids.pop() > + except KeyError: > + break # pids is empty > try: > os.kill(p, signal.SIGTERM) The process "p" is about to be killed but removed from the pids set, which would mean we can't wait killed processes at cleanup(). > @@ -109,5 +118,8 @@ def _posixworker(ui, func, staticargs, a > raise > if p: > - pids.remove(p) > + try: > + pids.remove(p) > + except KeyError: # in case p was poped by "killworkers" > + pass
Patch
diff --git a/mercurial/worker.py b/mercurial/worker.py --- a/mercurial/worker.py +++ b/mercurial/worker.py @@ -89,5 +89,14 @@ def _posixworker(ui, func, staticargs, a def killworkers(): # if one worker bails, there's no good reason to wait for the rest - for p in pids: + # note: use "while pids" instead of "for p in pids" as other code may + # get run by a signal handler and change "pids" in the mean time. + while pids: + try: + # note: set.pop() cannot be interrupted by a Python signal + # handler - this is true for both cpython and pypy. we use this + # property to make sure a child receive the signal once. + p = pids.pop() + except KeyError: + break # pids is empty try: os.kill(p, signal.SIGTERM) @@ -109,5 +118,8 @@ def _posixworker(ui, func, staticargs, a raise if p: - pids.remove(p) + try: + pids.remove(p) + except KeyError: # in case p was poped by "killworkers" + pass st = _exitstatus(st) if st and not problem[0]: