[PATCH STABLE] worker: ignore meaningless exit status indication returned by os.waitpid()

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Thu Feb 23 21:05:29 UTC 2017


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1487883654 -32400
#      Fri Feb 24 06:00:54 2017 +0900
# Branch stable
# Node ID d879917b416a305a42ab92a6d3ac2121d6830560
# Parent  aa25989b0658dcefbd4c1bce7c389f006f22af30
worker: ignore meaningless exit status indication returned by os.waitpid()

Before this patch, worker implementation assumes that os.waitpid()
with os.WNOHANG returns '(0, 0)' for still running child process. This
is explicitly specified as below in Python API document.

    os.WNOHANG
        The option for waitpid() to return immediately if no child
        process status is available immediately. The function returns
        (0, 0) in this case.

On the other hand, POSIX specification doesn't define the "stat_loc"
value returned by waitpid() with WNOHANG for such child process.

    http://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html

CPython implementation for os.waitpid() on POSIX doesn't take any care
of this gap, and this may cause unexpected "exit status indication"
even on POSIX conformance platform.

For example, os.waitpid() with os.WNOHANG returns non-zero "exit
status indication" on FreeBSD. This implies os.kill() with own pid or
sys.exit() with non-zero exit code, even if no child process fails.

To ignore meaningless exit status indication returned by os.waitpid()
with os.WNOHANG, this patch skips assignment to problem[0], if
non-blocking os.waitpid() returns 0 as pid.

This patch also adds "assert not st", to detect this kind of breakage
immediately. In this unexpected case, blocking os.waitpid() with
explicit pid returns '(0, non-zero)' without any exception.

diff --git a/mercurial/worker.py b/mercurial/worker.py
--- a/mercurial/worker.py
+++ b/mercurial/worker.py
@@ -123,6 +123,15 @@ def _posixworker(ui, func, staticargs, a
             if p:
                 pids.discard(p)
                 st = _exitstatus(st)
+            elif not blocking:
+                # ignore st in this case, because it might be non-zero
+                # on some platforms, even though it should be zero
+                # according to Python document
+                #
+                # See also https://bugs.python.org/issue27808
+                continue
+            else:
+                assert not st
             if st and not problem[0]:
                 problem[0] = st
     def sigchldhandler(signum, frame):


More information about the Mercurial-devel mailing list