select.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. # Copyright (c) 2009-2011 Denis Bilenko. See LICENSE for details.
  2. """
  3. Waiting for I/O completion.
  4. """
  5. from __future__ import absolute_import
  6. import sys
  7. from gevent.event import Event
  8. from gevent.hub import get_hub
  9. from gevent.hub import sleep as _g_sleep
  10. from gevent._compat import integer_types
  11. from gevent._compat import iteritems
  12. from gevent._compat import itervalues
  13. from gevent._util import copy_globals
  14. from gevent._util import _NONE
  15. from errno import EINTR
  16. if sys.platform.startswith('win32'):
  17. def _original_select(_r, _w, _x, _t):
  18. # windows cant handle three empty lists, but we've always
  19. # accepted that, so don't try the compliance check on windows
  20. return ((), (), ())
  21. else:
  22. from select import select as _original_select
  23. try:
  24. from select import poll as original_poll
  25. from select import POLLIN, POLLOUT, POLLNVAL
  26. __implements__ = ['select', 'poll']
  27. except ImportError:
  28. original_poll = None
  29. __implements__ = ['select']
  30. __all__ = ['error'] + __implements__
  31. import select as __select__
  32. error = __select__.error
  33. __imports__ = copy_globals(__select__, globals(),
  34. names_to_ignore=__all__,
  35. dunder_names_to_keep=())
  36. _EV_READ = 1
  37. _EV_WRITE = 2
  38. def get_fileno(obj):
  39. try:
  40. fileno_f = obj.fileno
  41. except AttributeError:
  42. if not isinstance(obj, integer_types):
  43. raise TypeError('argument must be an int, or have a fileno() method: %r' % (obj,))
  44. return obj
  45. else:
  46. return fileno_f()
  47. class SelectResult(object):
  48. __slots__ = ('read', 'write', 'event')
  49. def __init__(self):
  50. self.read = []
  51. self.write = []
  52. self.event = Event()
  53. def add_read(self, socket):
  54. self.read.append(socket)
  55. self.event.set()
  56. add_read.event = _EV_READ
  57. def add_write(self, socket):
  58. self.write.append(socket)
  59. self.event.set()
  60. add_write.event = _EV_WRITE
  61. def __add_watchers(self, watchers, fdlist, callback, io, pri):
  62. for fd in fdlist:
  63. watcher = io(get_fileno(fd), callback.event)
  64. watcher.priority = pri
  65. watchers.append(watcher)
  66. watcher.start(callback, fd)
  67. def _make_watchers(self, watchers, rlist, wlist):
  68. loop = get_hub().loop
  69. io = loop.io
  70. MAXPRI = loop.MAXPRI
  71. try:
  72. self.__add_watchers(watchers, rlist, self.add_read, io, MAXPRI)
  73. self.__add_watchers(watchers, wlist, self.add_write, io, MAXPRI)
  74. except IOError as ex:
  75. raise error(*ex.args)
  76. def _closeall(self, watchers):
  77. for watcher in watchers:
  78. watcher.stop()
  79. del watchers[:]
  80. def select(self, rlist, wlist, timeout):
  81. watchers = []
  82. try:
  83. self._make_watchers(watchers, rlist, wlist)
  84. self.event.wait(timeout=timeout)
  85. return self.read, self.write, []
  86. finally:
  87. self._closeall(watchers)
  88. def select(rlist, wlist, xlist, timeout=None): # pylint:disable=unused-argument
  89. """An implementation of :meth:`select.select` that blocks only the current greenlet.
  90. .. caution:: *xlist* is ignored.
  91. .. versionchanged:: 1.2a1
  92. Raise a :exc:`ValueError` if timeout is negative. This matches Python 3's
  93. behaviour (Python 2 would raise a ``select.error``). Previously gevent had
  94. undefined behaviour.
  95. .. versionchanged:: 1.2a1
  96. Raise an exception if any of the file descriptors are invalid.
  97. """
  98. if timeout is not None and timeout < 0:
  99. # Raise an error like the real implementation; which error
  100. # depends on the version. Python 3, where select.error is OSError,
  101. # raises a ValueError (which makes sense). Older pythons raise
  102. # the error from the select syscall...but we don't actually get there.
  103. # We choose to just raise the ValueError as it makes more sense and is
  104. # forward compatible
  105. raise ValueError("timeout must be non-negative")
  106. # First, do a poll with the original select system call. This
  107. # is the most efficient way to check to see if any of the file descriptors
  108. # have previously been closed and raise the correct corresponding exception.
  109. # (Because libev tends to just return them as ready...)
  110. # We accept the *xlist* here even though we can't below because this is all about
  111. # error handling.
  112. sel_results = ((), (), ())
  113. try:
  114. sel_results = _original_select(rlist, wlist, xlist, 0)
  115. except error as e:
  116. enumber = getattr(e, 'errno', None) or e.args[0]
  117. if enumber != EINTR:
  118. # Ignore interrupted syscalls
  119. raise
  120. if sel_results[0] or sel_results[1] or sel_results[2]:
  121. # If we actually had stuff ready, go ahead and return it. No need
  122. # to go through the trouble of doing our own stuff.
  123. # However, because this is typically a place where scheduling switches
  124. # can occur, we need to make sure that's still the case; otherwise a single
  125. # consumer could monopolize the thread. (shows up in test_ftplib.)
  126. _g_sleep()
  127. return sel_results
  128. result = SelectResult()
  129. return result.select(rlist, wlist, timeout)
  130. if original_poll is not None:
  131. class PollResult(object):
  132. __slots__ = ('events', 'event')
  133. def __init__(self):
  134. self.events = set()
  135. self.event = Event()
  136. def add_event(self, events, fd):
  137. if events < 0:
  138. result_flags = POLLNVAL
  139. else:
  140. result_flags = 0
  141. if events & _EV_READ:
  142. result_flags = POLLIN
  143. if events & _EV_WRITE:
  144. result_flags |= POLLOUT
  145. self.events.add((fd, result_flags))
  146. self.event.set()
  147. class poll(object):
  148. """
  149. An implementation of :class:`select.poll` that blocks only the current greenlet.
  150. .. caution:: ``POLLPRI`` data is not supported.
  151. .. versionadded:: 1.1b1
  152. """
  153. def __init__(self):
  154. self.fds = {} # {int -> watcher}
  155. self.loop = get_hub().loop
  156. def register(self, fd, eventmask=_NONE):
  157. if eventmask is _NONE:
  158. flags = _EV_READ | _EV_WRITE
  159. else:
  160. flags = 0
  161. if eventmask & POLLIN:
  162. flags = _EV_READ
  163. if eventmask & POLLOUT:
  164. flags |= _EV_WRITE
  165. # If they ask for POLLPRI, we can't support
  166. # that. Should we raise an error?
  167. fileno = get_fileno(fd)
  168. watcher = self.loop.io(fileno, flags)
  169. watcher.priority = self.loop.MAXPRI
  170. self.fds[fileno] = watcher
  171. def modify(self, fd, eventmask):
  172. self.register(fd, eventmask)
  173. def poll(self, timeout=None):
  174. """
  175. poll the registered fds.
  176. .. versionchanged:: 1.2a1
  177. File descriptors that are closed are reported with POLLNVAL.
  178. """
  179. result = PollResult()
  180. try:
  181. for fd, watcher in iteritems(self.fds):
  182. watcher.start(result.add_event, fd, pass_events=True)
  183. if timeout is not None and timeout > -1:
  184. timeout /= 1000.0
  185. result.event.wait(timeout=timeout)
  186. return list(result.events)
  187. finally:
  188. for awatcher in itervalues(self.fds):
  189. awatcher.stop()
  190. def unregister(self, fd):
  191. """
  192. Unregister the *fd*.
  193. .. versionchanged:: 1.2a1
  194. Raise a `KeyError` if *fd* was not registered, like the standard
  195. library. Previously gevent did nothing.
  196. """
  197. fileno = get_fileno(fd)
  198. del self.fds[fileno]
  199. del original_poll