Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

eventio.py 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. """
  2. kombu.utils.eventio
  3. ===================
  4. Evented IO support for multiple platforms.
  5. """
  6. from __future__ import absolute_import
  7. import errno
  8. import select as __select__
  9. import socket
  10. from numbers import Integral
  11. from kombu.syn import detect_environment
  12. from . import fileno
  13. from .compat import get_errno
  14. __all__ = ['poll']
  15. READ = POLL_READ = 0x001
  16. WRITE = POLL_WRITE = 0x004
  17. ERR = POLL_ERR = 0x008 | 0x010
  18. _selectf = __select__.select
  19. _selecterr = __select__.error
  20. epoll = getattr(__select__, 'epoll', None)
  21. kqueue = getattr(__select__, 'kqueue', None)
  22. kevent = getattr(__select__, 'kevent', None)
  23. KQ_EV_ADD = getattr(__select__, 'KQ_EV_ADD', 1)
  24. KQ_EV_DELETE = getattr(__select__, 'KQ_EV_DELETE', 2)
  25. KQ_EV_ENABLE = getattr(__select__, 'KQ_EV_ENABLE', 4)
  26. KQ_EV_CLEAR = getattr(__select__, 'KQ_EV_CLEAR', 32)
  27. KQ_EV_ERROR = getattr(__select__, 'KQ_EV_ERROR', 16384)
  28. KQ_EV_EOF = getattr(__select__, 'KQ_EV_EOF', 32768)
  29. KQ_FILTER_READ = getattr(__select__, 'KQ_FILTER_READ', -1)
  30. KQ_FILTER_WRITE = getattr(__select__, 'KQ_FILTER_WRITE', -2)
  31. KQ_FILTER_AIO = getattr(__select__, 'KQ_FILTER_AIO', -3)
  32. KQ_FILTER_VNODE = getattr(__select__, 'KQ_FILTER_VNODE', -4)
  33. KQ_FILTER_PROC = getattr(__select__, 'KQ_FILTER_PROC', -5)
  34. KQ_FILTER_SIGNAL = getattr(__select__, 'KQ_FILTER_SIGNAL', -6)
  35. KQ_FILTER_TIMER = getattr(__select__, 'KQ_FILTER_TIMER', -7)
  36. KQ_NOTE_LOWAT = getattr(__select__, 'KQ_NOTE_LOWAT', 1)
  37. KQ_NOTE_DELETE = getattr(__select__, 'KQ_NOTE_DELETE', 1)
  38. KQ_NOTE_WRITE = getattr(__select__, 'KQ_NOTE_WRITE', 2)
  39. KQ_NOTE_EXTEND = getattr(__select__, 'KQ_NOTE_EXTEND', 4)
  40. KQ_NOTE_ATTRIB = getattr(__select__, 'KQ_NOTE_ATTRIB', 8)
  41. KQ_NOTE_LINK = getattr(__select__, 'KQ_NOTE_LINK', 16)
  42. KQ_NOTE_RENAME = getattr(__select__, 'KQ_NOTE_RENAME', 32)
  43. KQ_NOTE_REVOKE = getattr(__select__, 'kQ_NOTE_REVOKE', 64)
  44. try:
  45. SELECT_BAD_FD = set((errno.EBADF, errno.WSAENOTSOCK))
  46. except AttributeError:
  47. SELECT_BAD_FD = set((errno.EBADF,))
  48. class Poller(object):
  49. def poll(self, timeout):
  50. try:
  51. return self._poll(timeout)
  52. except Exception as exc:
  53. if get_errno(exc) != errno.EINTR:
  54. raise
  55. class _epoll(Poller):
  56. def __init__(self):
  57. self._epoll = epoll()
  58. def register(self, fd, events):
  59. try:
  60. self._epoll.register(fd, events)
  61. except Exception as exc:
  62. if get_errno(exc) != errno.EEXIST:
  63. raise
  64. def unregister(self, fd):
  65. try:
  66. self._epoll.unregister(fd)
  67. except (socket.error, ValueError, KeyError, TypeError):
  68. pass
  69. except (IOError, OSError) as exc:
  70. if get_errno(exc) not in (errno.ENOENT, errno.EPERM):
  71. raise
  72. def _poll(self, timeout):
  73. return self._epoll.poll(timeout if timeout is not None else -1)
  74. def close(self):
  75. self._epoll.close()
  76. class _kqueue(Poller):
  77. w_fflags = (KQ_NOTE_WRITE | KQ_NOTE_EXTEND |
  78. KQ_NOTE_ATTRIB | KQ_NOTE_DELETE)
  79. def __init__(self):
  80. self._kqueue = kqueue()
  81. self._active = {}
  82. self.on_file_change = None
  83. self._kcontrol = self._kqueue.control
  84. def register(self, fd, events):
  85. self._control(fd, events, KQ_EV_ADD)
  86. self._active[fd] = events
  87. def unregister(self, fd):
  88. events = self._active.pop(fd, None)
  89. if events:
  90. try:
  91. self._control(fd, events, KQ_EV_DELETE)
  92. except socket.error:
  93. pass
  94. def watch_file(self, fd):
  95. ev = kevent(fd,
  96. filter=KQ_FILTER_VNODE,
  97. flags=KQ_EV_ADD | KQ_EV_ENABLE | KQ_EV_CLEAR,
  98. fflags=self.w_fflags)
  99. self._kcontrol([ev], 0)
  100. def unwatch_file(self, fd):
  101. ev = kevent(fd,
  102. filter=KQ_FILTER_VNODE,
  103. flags=KQ_EV_DELETE,
  104. fflags=self.w_fflags)
  105. self._kcontrol([ev], 0)
  106. def _control(self, fd, events, flags):
  107. if not events:
  108. return
  109. kevents = []
  110. if events & WRITE:
  111. kevents.append(kevent(fd,
  112. filter=KQ_FILTER_WRITE,
  113. flags=flags))
  114. if not kevents or events & READ:
  115. kevents.append(
  116. kevent(fd, filter=KQ_FILTER_READ, flags=flags),
  117. )
  118. control = self._kcontrol
  119. for e in kevents:
  120. try:
  121. control([e], 0)
  122. except ValueError:
  123. pass
  124. def _poll(self, timeout):
  125. kevents = self._kcontrol(None, 1000, timeout)
  126. events, file_changes = {}, []
  127. for k in kevents:
  128. fd = k.ident
  129. if k.filter == KQ_FILTER_READ:
  130. events[fd] = events.get(fd, 0) | READ
  131. elif k.filter == KQ_FILTER_WRITE:
  132. if k.flags & KQ_EV_EOF:
  133. events[fd] = ERR
  134. else:
  135. events[fd] = events.get(fd, 0) | WRITE
  136. elif k.filter == KQ_EV_ERROR:
  137. events[fd] = events.get(fd, 0) | ERR
  138. elif k.filter == KQ_FILTER_VNODE:
  139. if k.fflags & KQ_NOTE_DELETE:
  140. self.unregister(fd)
  141. file_changes.append(k)
  142. if file_changes:
  143. self.on_file_change(file_changes)
  144. return list(events.items())
  145. def close(self):
  146. self._kqueue.close()
  147. class _select(Poller):
  148. def __init__(self):
  149. self._all = (self._rfd,
  150. self._wfd,
  151. self._efd) = set(), set(), set()
  152. def register(self, fd, events):
  153. fd = fileno(fd)
  154. if events & ERR:
  155. self._efd.add(fd)
  156. if events & WRITE:
  157. self._wfd.add(fd)
  158. if events & READ:
  159. self._rfd.add(fd)
  160. def _remove_bad(self):
  161. for fd in self._rfd | self._wfd | self._efd:
  162. try:
  163. _selectf([fd], [], [], 0)
  164. except (_selecterr, socket.error) as exc:
  165. if get_errno(exc) in SELECT_BAD_FD:
  166. self.unregister(fd)
  167. def unregister(self, fd):
  168. try:
  169. fd = fileno(fd)
  170. except socket.error as exc:
  171. # we don't know the previous fd of this object
  172. # but it will be removed by the next poll iteration.
  173. if get_errno(exc) in SELECT_BAD_FD:
  174. return
  175. raise
  176. self._rfd.discard(fd)
  177. self._wfd.discard(fd)
  178. self._efd.discard(fd)
  179. def _poll(self, timeout):
  180. try:
  181. read, write, error = _selectf(
  182. self._rfd, self._wfd, self._efd, timeout,
  183. )
  184. except (_selecterr, socket.error) as exc:
  185. if get_errno(exc) == errno.EINTR:
  186. return
  187. elif get_errno(exc) in SELECT_BAD_FD:
  188. return self._remove_bad()
  189. raise
  190. events = {}
  191. for fd in read:
  192. if not isinstance(fd, Integral):
  193. fd = fd.fileno()
  194. events[fd] = events.get(fd, 0) | READ
  195. for fd in write:
  196. if not isinstance(fd, Integral):
  197. fd = fd.fileno()
  198. events[fd] = events.get(fd, 0) | WRITE
  199. for fd in error:
  200. if not isinstance(fd, Integral):
  201. fd = fd.fileno()
  202. events[fd] = events.get(fd, 0) | ERR
  203. return list(events.items())
  204. def close(self):
  205. self._rfd.clear()
  206. self._wfd.clear()
  207. self._efd.clear()
  208. def _get_poller():
  209. if detect_environment() != 'default':
  210. # greenlet
  211. return _select
  212. elif epoll:
  213. # Py2.6+ Linux
  214. return _epoll
  215. elif kqueue:
  216. # Py2.6+ on BSD / Darwin
  217. return _select # was: _kqueue
  218. else:
  219. return _select
  220. def poll(*args, **kwargs):
  221. return _get_poller()(*args, **kwargs)