Add a PollScheduler._schedule_waitpid() method for SubProcess._wait()
authorZac Medico <zmedico@gentoo.org>
Sat, 14 Aug 2010 07:10:07 +0000 (00:10 -0700)
committerZac Medico <zmedico@gentoo.org>
Sat, 14 Aug 2010 07:10:07 +0000 (00:10 -0700)
 to use as an alternative to hanging up the scheduler in a blocking
waitpid call.

pym/_emerge/PollScheduler.py
pym/_emerge/QueueScheduler.py
pym/_emerge/Scheduler.py
pym/_emerge/SubProcess.py

index ea8ebaacf041ece9aeb2c0644cf08fb0f4f57ba8..7f972e9728351d6d53fe2d147a26f1dacfdc5b38 100644 (file)
@@ -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
 
index 8e1837c03245a9bb5b4c4e08acc2445a4b055fb7..a65a90f060e86ef27e4508062777590ec4cd5045 100644 (file)
@@ -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 = []
index ae9cbcaa87ccc5e534d6196d4185deb91960508b..8d00a6f9251a898c2b25e2744fadc4c38cd2232e 100644 (file)
@@ -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,
index 9d75f0ea1213737351ca7737fb3f1c16f89890de..177ae3f927291002ef8bde50f31e6bb7aa850fc3 100644 (file)
@@ -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