poll.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """0MQ polling related functions and classes."""
  2. # Copyright (C) PyZMQ Developers
  3. # Distributed under the terms of the Modified BSD License.
  4. import zmq
  5. from zmq.backend import zmq_poll
  6. from .constants import POLLIN, POLLOUT, POLLERR
  7. #-----------------------------------------------------------------------------
  8. # Polling related methods
  9. #-----------------------------------------------------------------------------
  10. class Poller(object):
  11. """A stateful poll interface that mirrors Python's built-in poll."""
  12. sockets = None
  13. _map = {}
  14. def __init__(self):
  15. self.sockets = []
  16. self._map = {}
  17. def __contains__(self, socket):
  18. return socket in self._map
  19. def register(self, socket, flags=POLLIN|POLLOUT):
  20. """p.register(socket, flags=POLLIN|POLLOUT)
  21. Register a 0MQ socket or native fd for I/O monitoring.
  22. register(s,0) is equivalent to unregister(s).
  23. Parameters
  24. ----------
  25. socket : zmq.Socket or native socket
  26. A zmq.Socket or any Python object having a ``fileno()``
  27. method that returns a valid file descriptor.
  28. flags : int
  29. The events to watch for. Can be POLLIN, POLLOUT or POLLIN|POLLOUT.
  30. If `flags=0`, socket will be unregistered.
  31. """
  32. if flags:
  33. if socket in self._map:
  34. idx = self._map[socket]
  35. self.sockets[idx] = (socket, flags)
  36. else:
  37. idx = len(self.sockets)
  38. self.sockets.append((socket, flags))
  39. self._map[socket] = idx
  40. elif socket in self._map:
  41. # uregister sockets registered with no events
  42. self.unregister(socket)
  43. else:
  44. # ignore new sockets with no events
  45. pass
  46. def modify(self, socket, flags=POLLIN|POLLOUT):
  47. """Modify the flags for an already registered 0MQ socket or native fd."""
  48. self.register(socket, flags)
  49. def unregister(self, socket):
  50. """Remove a 0MQ socket or native fd for I/O monitoring.
  51. Parameters
  52. ----------
  53. socket : Socket
  54. The socket instance to stop polling.
  55. """
  56. idx = self._map.pop(socket)
  57. self.sockets.pop(idx)
  58. # shift indices after deletion
  59. for socket, flags in self.sockets[idx:]:
  60. self._map[socket] -= 1
  61. def poll(self, timeout=None):
  62. """Poll the registered 0MQ or native fds for I/O.
  63. If there are currently events ready to be processed, this function will return immediately.
  64. Otherwise, this function will return as soon the first event is available or after timeout
  65. milliseconds have elapsed.
  66. Parameters
  67. ----------
  68. timeout : float, int
  69. The timeout in milliseconds. If None, no `timeout` (infinite). This
  70. is in milliseconds to be compatible with ``select.poll()``.
  71. Returns
  72. -------
  73. events : list of tuples
  74. The list of events that are ready to be processed.
  75. This is a list of tuples of the form ``(socket, event_mask)``, where the 0MQ Socket
  76. or integer fd is the first element, and the poll event mask (POLLIN, POLLOUT) is the second.
  77. It is common to call ``events = dict(poller.poll())``,
  78. which turns the list of tuples into a mapping of ``socket : event_mask``.
  79. """
  80. if timeout is None or timeout < 0:
  81. timeout = -1
  82. elif isinstance(timeout, float):
  83. timeout = int(timeout)
  84. return zmq_poll(self.sockets, timeout=timeout)
  85. def select(rlist, wlist, xlist, timeout=None):
  86. """select(rlist, wlist, xlist, timeout=None) -> (rlist, wlist, xlist)
  87. Return the result of poll as a lists of sockets ready for r/w/exception.
  88. This has the same interface as Python's built-in ``select.select()`` function.
  89. Parameters
  90. ----------
  91. timeout : float, int, optional
  92. The timeout in seconds. If None, no timeout (infinite). This is in seconds to be
  93. compatible with ``select.select()``.
  94. rlist : list of sockets/FDs
  95. sockets/FDs to be polled for read events
  96. wlist : list of sockets/FDs
  97. sockets/FDs to be polled for write events
  98. xlist : list of sockets/FDs
  99. sockets/FDs to be polled for error events
  100. Returns
  101. -------
  102. (rlist, wlist, xlist) : tuple of lists of sockets (length 3)
  103. Lists correspond to sockets available for read/write/error events respectively.
  104. """
  105. if timeout is None:
  106. timeout = -1
  107. # Convert from sec -> us for zmq_poll.
  108. # zmq_poll accepts 3.x style timeout in ms
  109. timeout = int(timeout*1000.0)
  110. if timeout < 0:
  111. timeout = -1
  112. sockets = []
  113. for s in set(rlist + wlist + xlist):
  114. flags = 0
  115. if s in rlist:
  116. flags |= POLLIN
  117. if s in wlist:
  118. flags |= POLLOUT
  119. if s in xlist:
  120. flags |= POLLERR
  121. sockets.append((s, flags))
  122. return_sockets = zmq_poll(sockets, timeout)
  123. rlist, wlist, xlist = [], [], []
  124. for s, flags in return_sockets:
  125. if flags & POLLIN:
  126. rlist.append(s)
  127. if flags & POLLOUT:
  128. wlist.append(s)
  129. if flags & POLLERR:
  130. xlist.append(s)
  131. return rlist, wlist, xlist
  132. #-----------------------------------------------------------------------------
  133. # Symbols to export
  134. #-----------------------------------------------------------------------------
  135. __all__ = [ 'Poller', 'select' ]