Package _emerge :: Module AbstractPollTask
[hide private]

Source Code for Module _emerge.AbstractPollTask

  1  # Copyright 1999-2015 Gentoo Foundation 
  2  # Distributed under the terms of the GNU General Public License v2 
  3   
  4  import array 
  5  import errno 
  6  import logging 
  7  import os 
  8   
  9  from portage.util import writemsg_level 
 10  from _emerge.AsynchronousTask import AsynchronousTask 
11 12 -class AbstractPollTask(AsynchronousTask):
13 14 __slots__ = ("scheduler",) + \ 15 ("_registered",) 16 17 _bufsize = 4096 18 19 @property
20 - def _exceptional_events(self):
21 return self.scheduler.IO_ERR | self.scheduler.IO_NVAL
22 23 @property
24 - def _registered_events(self):
25 return self.scheduler.IO_IN | self.scheduler.IO_HUP | \ 26 self._exceptional_events
27
28 - def isAlive(self):
29 return bool(self._registered)
30
31 - def _read_array(self, f, event):
32 """ 33 NOTE: array.fromfile() is used here only for testing purposes, 34 because it has bugs in all known versions of Python (including 35 Python 2.7 and Python 3.2). See PipeReaderArrayTestCase. 36 37 | POLLIN | RETURN 38 | BIT | VALUE 39 | --------------------------------------------------- 40 | 1 | Read self._bufsize into an instance of 41 | | array.array('B') and return it, handling 42 | | EOFError and IOError. An empty array 43 | | indicates EOF. 44 | --------------------------------------------------- 45 | 0 | None 46 """ 47 buf = None 48 if event & self.scheduler.IO_IN: 49 buf = array.array('B') 50 try: 51 buf.fromfile(f, self._bufsize) 52 except EOFError: 53 pass 54 except TypeError: 55 # Python 3.2: 56 # TypeError: read() didn't return bytes 57 pass 58 except IOError as e: 59 # EIO happens with pty on Linux after the 60 # slave end of the pty has been closed. 61 if e.errno == errno.EIO: 62 # EOF: return empty string of bytes 63 pass 64 elif e.errno == errno.EAGAIN: 65 # EAGAIN: return None 66 buf = None 67 else: 68 raise 69 70 if buf is not None: 71 try: 72 # Python >=3.2 73 buf = buf.tobytes() 74 except AttributeError: 75 buf = buf.tostring() 76 77 return buf
78
79 - def _read_buf(self, fd, event):
80 """ 81 Read self._bufsize into a string of bytes, handling EAGAIN and 82 EIO. This will only call os.read() once, so the caller should 83 call this method in a loop until either None or an empty string 84 of bytes is returned. An empty string of bytes indicates EOF. 85 None indicates EAGAIN. 86 87 NOTE: os.read() will be called regardless of the event flags, 88 since otherwise data may be lost (see bug #531724). 89 90 @param fd: file descriptor (non-blocking mode required) 91 @type fd: int 92 @param event: poll event flags 93 @type event: int 94 @rtype: bytes or None 95 @return: A string of bytes, or None 96 """ 97 # NOTE: array.fromfile() is no longer used here because it has 98 # bugs in all known versions of Python (including Python 2.7 99 # and Python 3.2). 100 buf = None 101 try: 102 buf = os.read(fd, self._bufsize) 103 except OSError as e: 104 # EIO happens with pty on Linux after the 105 # slave end of the pty has been closed. 106 if e.errno == errno.EIO: 107 # EOF: return empty string of bytes 108 buf = b'' 109 elif e.errno == errno.EAGAIN: 110 # EAGAIN: return None 111 buf = None 112 else: 113 raise 114 115 return buf
116
117 - def _unregister(self):
118 raise NotImplementedError(self)
119
120 - def _log_poll_exception(self, event):
121 writemsg_level( 122 "!!! %s received strange poll event: %s\n" % \ 123 (self.__class__.__name__, event,), 124 level=logging.ERROR, noiselevel=-1)
125
126 - def _unregister_if_appropriate(self, event):
127 if self._registered: 128 if event & self._exceptional_events: 129 self._log_poll_exception(event) 130 self._unregister() 131 self.cancel() 132 self.wait() 133 elif event & self.scheduler.IO_HUP: 134 self._unregister() 135 self.wait()
136
137 - def _wait(self):
138 if self.returncode is not None: 139 return self.returncode 140 self._wait_loop() 141 return self.returncode
142
143 - def _wait_loop(self, timeout=None):
144 145 if timeout is None: 146 while self._registered: 147 self.scheduler.iteration() 148 return 149 150 def timeout_cb(): 151 timeout_cb.timed_out = True 152 return False
153 timeout_cb.timed_out = False 154 timeout_cb.timeout_id = self.scheduler.timeout_add(timeout, timeout_cb) 155 156 try: 157 while self._registered and not timeout_cb.timed_out: 158 self.scheduler.iteration() 159 finally: 160 self.scheduler.source_remove(timeout_cb.timeout_id)
161