From de2cbf6e28da9ebbcef7946186df042f28c09808 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Sat, 14 Aug 2010 00:10:07 -0700 Subject: [PATCH] Add a PollScheduler._schedule_waitpid() method for SubProcess._wait() to use as an alternative to hanging up the scheduler in a blocking waitpid call. --- pym/_emerge/PollScheduler.py | 33 ++++++++++++++++++++++++++++++++- pym/_emerge/QueueScheduler.py | 3 ++- pym/_emerge/Scheduler.py | 2 ++ pym/_emerge/SubProcess.py | 15 +++++++++++++-- 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 -- 2.26.2