[PATCH 6 of 8 V5] worker: make sure killworkers runs at most once

Jun Wu quark at fb.com
Mon Nov 14 21:39:09 EST 2016


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1479176697 0
#      Tue Nov 15 02:24:57 2016 +0000
# Node ID 8402c91c250a9dd369296dcdf00f7b50110ff6ae
# Parent  9dbb3532b173a980f341e41d9e96338a386364e5
# Available At https://bitbucket.org/quark-zju/hg-draft
#              hg pull https://bitbucket.org/quark-zju/hg-draft -r 8402c91c250a
worker: make sure killworkers runs at most once

With the next patch adding SIGCHILD handler calling
waitforworkers(blocking=False), the current code could call "killworkers"
multiple times:

    if st and not problem[0]:
        # at this time, another SIGCHILD happens, killworkers may run twice
        problem[0] = st
        killworkers()

This patch uses the property that "next(itertools.count())" is an "atomic
test and update" operation at the Python code level (cannot be interrupted
by a Python signal handler). That property is true for both CPython
(confirmed from source code) and PyPy (confirmed by PyPy dev arigato on
freenode #pypy channel).

diff --git a/mercurial/worker.py b/mercurial/worker.py
--- a/mercurial/worker.py
+++ b/mercurial/worker.py
@@ -9,4 +9,5 @@ from __future__ import absolute_import
 
 import errno
+import itertools
 import os
 import signal
@@ -90,4 +91,5 @@ def _posixworker(ui, func, staticargs, a
     signal.signal(signal.SIGINT, signal.SIG_IGN)
     pids, problem = set(), [0]
+    problemcount = itertools.count()
     def killworkers():
         # if one worker bails, there's no good reason to wait for the rest
@@ -114,5 +116,8 @@ def _posixworker(ui, func, staticargs, a
                 pids.remove(p)
                 st = _exitstatus(st)
-            if st and not problem[0]:
+            # next(itertools.count()) cannot be interrupted by a Python signal
+            # handler - true for both CPython and PyPy. So killworkers() runs
+            # at most once.
+            if st and next(problemcount) == 0:
                 problem[0] = st
                 killworkers()


More information about the Mercurial-devel mailing list