aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'portage_with_autodep/pym/_emerge/SubProcess.py')
-rw-r--r--portage_with_autodep/pym/_emerge/SubProcess.py141
1 files changed, 141 insertions, 0 deletions
diff --git a/portage_with_autodep/pym/_emerge/SubProcess.py b/portage_with_autodep/pym/_emerge/SubProcess.py
new file mode 100644
index 0000000..b99cf0b
--- /dev/null
+++ b/portage_with_autodep/pym/_emerge/SubProcess.py
@@ -0,0 +1,141 @@
+# Copyright 1999-2011 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage import os
+from _emerge.AbstractPollTask import AbstractPollTask
+import signal
+import errno
+
+class SubProcess(AbstractPollTask):
+
+ __slots__ = ("pid",) + \
+ ("_files", "_reg_id")
+
+ # A file descriptor is required for the scheduler to monitor changes from
+ # inside a poll() loop. When logging is not enabled, create a pipe just to
+ # serve this purpose alone.
+ _dummy_pipe_fd = 9
+
+ def _poll(self):
+ if self.returncode is not None:
+ return self.returncode
+ if self.pid is None:
+ return self.returncode
+ if self._registered:
+ return self.returncode
+
+ try:
+ # With waitpid and WNOHANG, only check the
+ # first element of the tuple since the second
+ # element may vary (bug #337465).
+ retval = os.waitpid(self.pid, os.WNOHANG)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ del e
+ retval = (self.pid, 1)
+
+ if retval[0] == 0:
+ return None
+ self._set_returncode(retval)
+ self.wait()
+ return self.returncode
+
+ def _cancel(self):
+ if self.isAlive():
+ try:
+ os.kill(self.pid, signal.SIGTERM)
+ except OSError as e:
+ if e.errno != errno.ESRCH:
+ raise
+
+ def isAlive(self):
+ return self.pid is not None and \
+ self.returncode is None
+
+ def _wait(self):
+
+ if self.returncode is not None:
+ return self.returncode
+
+ if self._registered:
+ if self.cancelled:
+ timeout = 1000
+ self.scheduler.schedule(self._reg_id, timeout=timeout)
+ if self._registered:
+ try:
+ os.kill(self.pid, signal.SIGKILL)
+ except OSError as e:
+ if e.errno != errno.ESRCH:
+ raise
+ del e
+ self.scheduler.schedule(self._reg_id, timeout=timeout)
+ if self._registered:
+ self._orphan_process_warn()
+ else:
+ self.scheduler.schedule(self._reg_id)
+ self._unregister()
+ if self.returncode is not None:
+ return self.returncode
+
+ try:
+ # With waitpid and WNOHANG, only check the
+ # first element of the tuple since the second
+ # element may vary (bug #337465).
+ wait_retval = os.waitpid(self.pid, os.WNOHANG)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ del e
+ self._set_returncode((self.pid, 1 << 8))
+ else:
+ if wait_retval[0] != 0:
+ self._set_returncode(wait_retval)
+ else:
+ try:
+ wait_retval = os.waitpid(self.pid, 0)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ del e
+ self._set_returncode((self.pid, 1 << 8))
+ else:
+ self._set_returncode(wait_retval)
+
+ return self.returncode
+
+ def _orphan_process_warn(self):
+ pass
+
+ def _unregister(self):
+ """
+ Unregister from the scheduler and close open files.
+ """
+
+ self._registered = False
+
+ if self._reg_id is not None:
+ self.scheduler.unregister(self._reg_id)
+ self._reg_id = None
+
+ if self._files is not None:
+ for f in self._files.values():
+ f.close()
+ self._files = None
+
+ def _set_returncode(self, wait_retval):
+ """
+ Set the returncode in a manner compatible with
+ subprocess.Popen.returncode: A negative value -N indicates
+ that the child was terminated by signal N (Unix only).
+ """
+
+ pid, status = wait_retval
+
+ if os.WIFSIGNALED(status):
+ retval = - os.WTERMSIG(status)
+ else:
+ retval = os.WEXITSTATUS(status)
+
+ self.returncode = retval
+