diff options
Diffstat (limited to 'portage_with_autodep/pym/_emerge/AbstractPollTask.py')
-rw-r--r-- | portage_with_autodep/pym/_emerge/AbstractPollTask.py | 112 |
1 files changed, 102 insertions, 10 deletions
diff --git a/portage_with_autodep/pym/_emerge/AbstractPollTask.py b/portage_with_autodep/pym/_emerge/AbstractPollTask.py index f7f3a95..2c84709 100644 --- a/portage_with_autodep/pym/_emerge/AbstractPollTask.py +++ b/portage_with_autodep/pym/_emerge/AbstractPollTask.py @@ -1,44 +1,111 @@ -# Copyright 1999-2011 Gentoo Foundation +# Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import array +import errno import logging +import os from portage.util import writemsg_level from _emerge.AsynchronousTask import AsynchronousTask -from _emerge.PollConstants import PollConstants + class AbstractPollTask(AsynchronousTask): __slots__ = ("scheduler",) + \ ("_registered",) _bufsize = 4096 - _exceptional_events = PollConstants.POLLERR | PollConstants.POLLNVAL - _registered_events = PollConstants.POLLIN | PollConstants.POLLHUP | \ - _exceptional_events + + @property + def _exceptional_events(self): + return self.scheduler.IO_ERR | self.scheduler.IO_NVAL + + @property + def _registered_events(self): + return self.scheduler.IO_IN | self.scheduler.IO_HUP | \ + self._exceptional_events def isAlive(self): return bool(self._registered) - def _read_buf(self, f, event): + def _read_array(self, f, event): """ + NOTE: array.fromfile() is used here only for testing purposes, + because it has bugs in all known versions of Python (including + Python 2.7 and Python 3.2). See PipeReaderArrayTestCase. + | POLLIN | RETURN | BIT | VALUE | --------------------------------------------------- | 1 | Read self._bufsize into an instance of - | | array.array('B') and return it, ignoring + | | array.array('B') and return it, handling | | EOFError and IOError. An empty array | | indicates EOF. | --------------------------------------------------- | 0 | None """ buf = None - if event & PollConstants.POLLIN: + if event & self.scheduler.IO_IN: buf = array.array('B') try: buf.fromfile(f, self._bufsize) - except (EOFError, IOError): + except EOFError: pass + except TypeError: + # Python 3.2: + # TypeError: read() didn't return bytes + pass + except IOError as e: + # EIO happens with pty on Linux after the + # slave end of the pty has been closed. + if e.errno == errno.EIO: + # EOF: return empty string of bytes + pass + elif e.errno == errno.EAGAIN: + # EAGAIN: return None + buf = None + else: + raise + + if buf is not None: + try: + # Python >=3.2 + buf = buf.tobytes() + except AttributeError: + buf = buf.tostring() + + return buf + + def _read_buf(self, fd, event): + """ + | POLLIN | RETURN + | BIT | VALUE + | --------------------------------------------------- + | 1 | Read self._bufsize into a string of bytes, + | | handling EAGAIN and EIO. An empty string + | | of bytes indicates EOF. + | --------------------------------------------------- + | 0 | None + """ + # NOTE: array.fromfile() is no longer used here because it has + # bugs in all known versions of Python (including Python 2.7 + # and Python 3.2). + buf = None + if event & self.scheduler.IO_IN: + try: + buf = os.read(fd, self._bufsize) + except OSError as e: + # EIO happens with pty on Linux after the + # slave end of the pty has been closed. + if e.errno == errno.EIO: + # EOF: return empty string of bytes + buf = b'' + elif e.errno == errno.EAGAIN: + # EAGAIN: return None + buf = None + else: + raise + return buf def _unregister(self): @@ -56,7 +123,32 @@ class AbstractPollTask(AsynchronousTask): self._log_poll_exception(event) self._unregister() self.cancel() - elif event & PollConstants.POLLHUP: + self.wait() + elif event & self.scheduler.IO_HUP: self._unregister() self.wait() + def _wait(self): + if self.returncode is not None: + return self.returncode + self._wait_loop() + return self.returncode + + def _wait_loop(self, timeout=None): + + if timeout is None: + while self._registered: + self.scheduler.iteration() + return + + def timeout_cb(): + timeout_cb.timed_out = True + return False + timeout_cb.timed_out = False + timeout_cb.timeout_id = self.scheduler.timeout_add(timeout, timeout_cb) + + try: + while self._registered and not timeout_cb.timed_out: + self.scheduler.iteration() + finally: + self.scheduler.unregister(timeout_cb.timeout_id) |