Bug 1309060 - Ignore "No such process" when trying to find pgid in mozprocess, r?gps draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Thu, 03 Nov 2016 10:24:11 -0400
changeset 439814 0e7e361d30975886318d1969f5182f31ec58372f
parent 439707 2598a93e2e1a27f363af9fdd290cf4184cc51d48
child 439815 6942dbd53955faf7c3ffa5cb8b25028ec8733ef1
push id36108
push userahalberstadt@mozilla.com
push dateWed, 16 Nov 2016 17:56:38 +0000
reviewersgps
bugs1309060
milestone53.0a1
Bug 1309060 - Ignore "No such process" when trying to find pgid in mozprocess, r?gps For some reason calling os.getpgid(proc.pid) in this bug results in an OSError "No such process" on OSX. This bug is starting the ProcessHandler from a concurrent.futures Thread, that must be somehow related. I tried debugging this, but couldn't figure out why this is happening. However, the pgid is not needed for this use case, and simply ignoring the error works. We also ignore this very same exception when calling os.getpgid elsewhere in mozprocess, so there must be some weird OSXism happening. MozReview-Commit-ID: 2YXhBaORC5s
testing/mozbase/mozprocess/mozprocess/processhandler.py
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -1,14 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import
 
+import errno
 import os
 import signal
 import subprocess
 import sys
 import threading
 import time
 import traceback
 from Queue import Queue, Empty
@@ -152,20 +153,20 @@ class ProcessHandlerMixin(object):
                         self._cleanup()
             else:
                 def send_sig(sig):
                     pid = self.detached_pid or self.pid
                     if not self._ignore_children:
                         try:
                             os.killpg(pid, sig)
                         except BaseException as e:
-                            # Error 3 is a "no such process" failure, which is fine because the
+                            # 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) != 3:
+                            if getattr(e, "errno", None) != errno.ESRCH:
                                 print >> sys.stderr, "Could not terminate process: %s" % self.pid
                                 raise
                     else:
                         os.kill(pid, sig)
 
                 if sig is None and isPosix:
                     # ask the process for termination and wait a bit
                     send_sig(signal.SIGTERM)
@@ -734,17 +735,17 @@ falling back to not using job objects fo
         # build process arguments
         args.update(self.keywordargs)
 
         # launch the process
         self.proc = self.Process([self.cmd] + self.args, **args)
 
         if isPosix:
             # Keep track of the initial process group in case the process detaches itself
-            self.proc.pgid = os.getpgid(self.proc.pid)
+            self.proc.pgid = self._getpgid(self.proc.pid)
             self.proc.detached_pid = None
 
         self.processOutput(timeout=timeout, outputTimeout=outputTimeout)
 
     def kill(self, sig=None):
         """
         Kills the managed process.
 
@@ -845,37 +846,40 @@ falling back to not using job objects fo
         print >> sys.stderr, "MOZPROCESS WARNING: ProcessHandler.waitForFinish() is deprecated, " \
                              "use ProcessHandler.wait() instead"
         return self.wait(timeout=timeout)
 
     @property
     def pid(self):
         return self.proc.pid
 
+    @classmethod
+    def _getpgid(cls, pid):
+        try:
+            return os.getpgid(pid)
+        except OSError as e:
+            # Do not raise for "No such process"
+            if e.errno != errno.ESRCH:
+                raise
+
     def check_for_detached(self, new_pid):
         """Check if the current process has been detached and mark it appropriately.
 
         In case of application restarts the process can spawn itself into a new process group.
         From now on the process can no longer be tracked by mozprocess anymore and has to be
         marked as detached. If the consumer of mozprocess still knows the new process id it could
         check for the detached state.
 
         new_pid is the new process id of the child process.
         """
         if not self.proc:
             return
 
         if isPosix:
-            new_pgid = None
-            try:
-                new_pgid = os.getpgid(new_pid)
-            except OSError as e:
-                # Do not consume errors except "No such process"
-                if e.errno != 3:
-                    raise
+            new_pgid = self._getpgid(new_pid)
 
             if new_pgid and new_pgid != self.proc.pgid:
                 self.proc.detached_pid = new_pid
                 print >> sys.stdout, \
                     'Child process with id "%s" has been marked as detached because it is no ' \
                     'longer in the managed process group. Keeping reference to the process id ' \
                     '"%s" which is the new child process.' % (self.pid, new_pid)