Bug 1329528 - Reap zombie processes on Mac OS if killing the process group initially fails with EPERM; r?ahal draft
authorSam Giles <sam.e.giles@gmail.com>
Thu, 16 Feb 2017 06:18:17 +0000
changeset 485129 e31c3a9ea490f33fef88be22d21ecdecbf9baeba
parent 485098 a9ec72f82299250e6023988e238931bbca0ef7fa
child 545933 7b490744ddd9bf83d3955288b66a3c5463cfe724
push id45640
push userbmo:sgiles@mozilla.com
push dateThu, 16 Feb 2017 06:18:57 +0000
reviewersahal
bugs1329528
milestone54.0a1
Bug 1329528 - Reap zombie processes on Mac OS if killing the process group initially fails with EPERM; r?ahal MozReview-Commit-ID: IKqXKIN0mXx
testing/mozbase/mozprocess/mozprocess/processhandler.py
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -147,22 +147,34 @@ class ProcessHandlerMixin(object):
                         winprocess.TerminateProcess(self._handle, winprocess.ERROR_CONTROL_C_EXIT)
                     except:
                         traceback.print_exc()
                         raise OSError("Could not terminate process")
                     finally:
                         winprocess.GetExitCodeProcess(self._handle)
                         self._cleanup()
             else:
-                def send_sig(sig):
+                def send_sig(sig, retries=0):
                     pid = self.detached_pid or self.pid
                     if not self._ignore_children:
                         try:
                             os.killpg(pid, sig)
                         except BaseException as e:
+                            # On Mac OSX if the process group contains zombie
+                            # processes, killpg results in an EPERM.
+                            # In this case, zombie processes need to be reaped
+                            # before continuing
+                            # Note: A negative pid refers to the entire process
+                            # group
+                            if retries < 1 and getattr(e, "errno", None) == errno.EPERM:
+                                try:
+                                    os.waitpid(-pid, 0)
+                                finally:
+                                    return send_sig(sig, retries + 1)
+
                             # ESRCH is a "no such process" failure, which is fine because the
                             # application might already have been terminated itself. Any other
                             # error would indicate a problem in killing the process.
                             if getattr(e, "errno", None) != errno.ESRCH:
                                 print >> sys.stderr, "Could not terminate process: %s" % self.pid
                                 raise
                     else:
                         os.kill(pid, sig)