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
--- 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)