summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2010-08-14 00:10:07 -0700
committerZac Medico <zmedico@gentoo.org>2010-08-14 00:10:07 -0700
commitde2cbf6e28da9ebbcef7946186df042f28c09808 (patch)
treeab7bfc95a2a024723e73b131d7d50788cd8b9c26
parent1e69471d3eac6d0e2a01878ed3f0031783f57671 (diff)
downloadportage-de2cbf6e28da9ebbcef7946186df042f28c09808.tar.gz
portage-de2cbf6e28da9ebbcef7946186df042f28c09808.tar.bz2
portage-de2cbf6e28da9ebbcef7946186df042f28c09808.zip
Add a PollScheduler._schedule_waitpid() method for SubProcess._wait()
to use as an alternative to hanging up the scheduler in a blocking waitpid call.
-rw-r--r--pym/_emerge/PollScheduler.py33
-rw-r--r--pym/_emerge/QueueScheduler.py3
-rw-r--r--pym/_emerge/Scheduler.py2
-rw-r--r--pym/_emerge/SubProcess.py15
4 files changed, 49 insertions, 4 deletions
diff --git a/pym/_emerge/PollScheduler.py b/pym/_emerge/PollScheduler.py
index ea8ebaacf..7f972e972 100644
--- a/pym/_emerge/PollScheduler.py
+++ b/pym/_emerge/PollScheduler.py
@@ -5,6 +5,7 @@ import logging
import select
import time
+from portage import os
from portage.util import writemsg_level
from _emerge.SlotObject import SlotObject
@@ -15,7 +16,7 @@ from _emerge.PollSelectAdapter import PollSelectAdapter
class PollScheduler(object):
class _sched_iface_class(SlotObject):
- __slots__ = ("register", "schedule", "unregister")
+ __slots__ = ("register", "schedule", "schedule_waitpid", "unregister")
def __init__(self):
self._max_jobs = 1
@@ -229,6 +230,36 @@ class PollScheduler(object):
return event_handled
+ def _schedule_waitpid(self, pid):
+ """
+ Schedule until waitpid returns process status
+ for the given pid, and return the result from waitpid.
+ This is meant to be called as a last resort, since
+ it won't return until the process exits. This can raise
+ OSError from the waitpid call (typically errno.ECHILD).
+ @type pid: int
+ @param pid: the pid of the child process to wait for
+ """
+ event_handlers = self._poll_event_handlers
+
+ try:
+ while event_handlers:
+ f, event = self._next_poll_event()
+ try:
+ handler, reg_id = event_handlers[f]
+ except KeyError:
+ pass
+ else:
+ handler(f, event)
+ wait_retval = os.waitpid(pid, os.WNOHANG)
+ if wait_retval != (0, 0):
+ return wait_retval
+ self.schedule()
+ except StopIteration:
+ pass
+
+ # Once scheduling is exhaused, do a blocking waitpid.
+ return os.waitpid(pid, 0)
_can_poll_device = None
diff --git a/pym/_emerge/QueueScheduler.py b/pym/_emerge/QueueScheduler.py
index 8e1837c03..a65a90f06 100644
--- a/pym/_emerge/QueueScheduler.py
+++ b/pym/_emerge/QueueScheduler.py
@@ -21,7 +21,8 @@ class QueueScheduler(PollScheduler):
self.sched_iface = self._sched_iface_class(
register=self._register,
schedule=self._schedule_wait,
- unregister=self._unregister)
+ unregister=self._unregister,
+ schedule_waitpid=self._schedule_waitpid)
self._queues = []
self._schedule_listeners = []
diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py
index ae9cbcaa8..8d00a6f92 100644
--- a/pym/_emerge/Scheduler.py
+++ b/pym/_emerge/Scheduler.py
@@ -78,6 +78,7 @@ class Scheduler(PollScheduler):
class _iface_class(SlotObject):
__slots__ = ("dblinkEbuildPhase", "dblinkDisplayMerge",
"dblinkElog", "dblinkEmergeLog", "fetch", "register", "schedule",
+ "schedule_waitpid",
"scheduleSetup", "scheduleUnpack", "scheduleYield",
"unregister")
@@ -210,6 +211,7 @@ class Scheduler(PollScheduler):
dblinkEmergeLog=self._dblink_emerge_log,
fetch=fetch_iface, register=self._register,
schedule=self._schedule_wait,
+ schedule_waitpid=self._schedule_waitpid,
scheduleSetup=self._schedule_setup,
scheduleUnpack=self._schedule_unpack,
scheduleYield=self._schedule_yield,
diff --git a/pym/_emerge/SubProcess.py b/pym/_emerge/SubProcess.py
index 9d75f0ea1..177ae3f92 100644
--- a/pym/_emerge/SubProcess.py
+++ b/pym/_emerge/SubProcess.py
@@ -81,14 +81,25 @@ class SubProcess(AbstractPollTask):
return self.returncode
try:
- wait_retval = os.waitpid(self.pid, 0)
+ 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))
else:
- self._set_returncode(wait_retval)
+ if wait_retval != (0, 0):
+ self._set_returncode(wait_retval)
+ else:
+ try:
+ wait_retval = self.scheduler.schedule_waitpid(self.pid)
+ except OSError as e:
+ if e.errno != errno.ECHILD:
+ raise
+ del e
+ self._set_returncode((self.pid, 1))
+ else:
+ self._set_returncode(wait_retval)
return self.returncode