diff options
Diffstat (limited to 'pym/_emerge')
-rw-r--r-- | pym/_emerge/AbstractPollTask.py | 49 | ||||
-rw-r--r-- | pym/_emerge/PipeReader.py | 29 |
2 files changed, 76 insertions, 2 deletions
diff --git a/pym/_emerge/AbstractPollTask.py b/pym/_emerge/AbstractPollTask.py index b3c0b2d16..83e6c7b9c 100644 --- a/pym/_emerge/AbstractPollTask.py +++ b/pym/_emerge/AbstractPollTask.py @@ -1,6 +1,7 @@ # Copyright 1999-2011 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 +import array import errno import logging import os @@ -21,6 +22,54 @@ class AbstractPollTask(AsynchronousTask): def isAlive(self): return bool(self._registered) + 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). + + | POLLIN | RETURN + | BIT | VALUE + | --------------------------------------------------- + | 1 | Read self._bufsize into an instance of + | | array.array('B') and return it, ignoring + | | EOFError and IOError. An empty array + | | indicates EOF. + | --------------------------------------------------- + | 0 | None + """ + buf = None + if event & PollConstants.POLLIN: + buf = array.array('B') + try: + buf.fromfile(f, self._bufsize) + 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 diff --git a/pym/_emerge/PipeReader.py b/pym/_emerge/PipeReader.py index 9fedbff6f..b162fe5cc 100644 --- a/pym/_emerge/PipeReader.py +++ b/pym/_emerge/PipeReader.py @@ -15,16 +15,22 @@ class PipeReader(AbstractPollTask): """ __slots__ = ("input_files",) + \ - ("_read_data", "_reg_ids") + ("_read_data", "_reg_ids", "_use_array") def _start(self): self._reg_ids = set() self._read_data = [] + + if self._use_array: + output_handler = self._array_output_handler + else: + output_handler = self._output_handler + for k, f in self.input_files.items(): fcntl.fcntl(f.fileno(), fcntl.F_SETFL, fcntl.fcntl(f.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK) self._reg_ids.add(self.scheduler.register(f.fileno(), - self._registered_events, self._output_handler)) + self._registered_events, output_handler)) self._registered = True def isAlive(self): @@ -68,6 +74,25 @@ class PipeReader(AbstractPollTask): self._unregister_if_appropriate(event) + def _array_output_handler(self, fd, event): + + for f in self.input_files.values(): + if f.fileno() == fd: + break + + while True: + data = self._read_array(f, event) + if data is None: + break + if data: + self._read_data.append(data) + else: + self._unregister() + self.wait() + break + + self._unregister_if_appropriate(event) + def _unregister(self): """ Unregister from the scheduler and close open files. |