From b05ee3d224c5fbbfb8655d93fb7a1e99e6d7eac4 Mon Sep 17 00:00:00 2001
From: Jason Madden <jamadden@gmail.com>
Date: Tue, 1 Sep 2015 09:07:59 -0500
Subject: [PATCH] Make waitpid(-1) work properly with exited children.

---
 gevent/os.py                      | 14 ++++++++++++--
 greentest/test__monkey_sigchld.py | 10 ++++++++++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/gevent/os.py b/gevent/os.py
index 7314689f..befac1e7 100644
--- a/gevent/os.py
+++ b/gevent/os.py
@@ -238,8 +238,18 @@ if hasattr(os, 'fork'):
             """
             # XXX Does not handle tracing children
             if pid <= 0:
-                # magic functions for multiple children. Pass.
-                return _waitpid(pid, options)
+                # magic functions for multiple children.
+                if pid == -1:
+                    # Any child. If we have one that we're watching and that finished,
+                    # we need to use that one. Otherwise, let the OS take care of it.
+                    for k, v in _watched_children.items():
+                        if isinstance(v, tuple):
+                            pid = k
+                            break
+                if pid <= 0:
+                    # If we didn't find anything, go to the OS. Otherwise,
+                    # handle waiting
+                    return _waitpid(pid, options)
 
             if pid in _watched_children:
                 # yes, we're watching it
diff --git a/greentest/test__monkey_sigchld.py b/greentest/test__monkey_sigchld.py
index c74b1e53..5d22e473 100644
--- a/greentest/test__monkey_sigchld.py
+++ b/greentest/test__monkey_sigchld.py
@@ -1,3 +1,4 @@
+import errno
 import os
 import sys
 #os.environ['GEVENT_NOWAITPID'] = 'True'
@@ -34,6 +35,15 @@ if hasattr(signal, 'SIGCHLD'):
         with gevent.Timeout(1):
             while awaiting_child:
                 gevent.sleep(0.01)
+            # We should now be able to waitpid() for an arbitrary child
+            wpid, status = os.waitpid(-1, os.WNOHANG)
+            assert wpid == pid
+            # And a second call should raise ECHILD
+            try:
+                wpid, status = os.waitpid(-1, os.WNOHANG)
+                raise AssertionError("Should not be able to wait again")
+            except OSError as e:
+                assert e.errno == errno.ECHILD
             sys.exit(0)
 else:
     print("No SIGCHLD, not testing")
-- 
2.30.9