1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 A poll() based implementation of the twisted main loop.
7 To install the event loop (and you should do this before any connections,
8 listeners or connectors are added)::
10 from twisted.internet import pollreactor
16 from select import error as SelectError, poll
17 from select import POLLIN, POLLOUT, POLLHUP, POLLERR, POLLNVAL
19 from zope.interface import implements
22 from twisted.python import log
23 from twisted.internet import posixbase
24 from twisted.internet.interfaces import IReactorFDSet
28 class PollReactor(posixbase.PosixReactorBase, posixbase._PollLikeMixin):
30 A reactor that uses poll(2).
32 @ivar _poller: A L{poll} which will be used to check for I/O
35 @ivar _selectables: A dictionary mapping integer file descriptors to
36 instances of L{FileDescriptor} which have been registered with the
37 reactor. All L{FileDescriptors} which are currently receiving read or
38 write readiness notifications will be present as values in this
41 @ivar _reads: A dictionary mapping integer file descriptors to arbitrary
42 values (this is essentially a set). Keys in this dictionary will be
43 registered with C{_poller} for read readiness notifications which will
44 be dispatched to the corresponding L{FileDescriptor} instances in
47 @ivar _writes: A dictionary mapping integer file descriptors to arbitrary
48 values (this is essentially a set). Keys in this dictionary will be
49 registered with C{_poller} for write readiness notifications which will
50 be dispatched to the corresponding L{FileDescriptor} instances in
53 implements(IReactorFDSet)
55 _POLL_DISCONNECTED = (POLLHUP | POLLERR | POLLNVAL)
61 Initialize polling object, file descriptor tracking dictionaries, and
65 self._selectables = {}
68 posixbase.PosixReactorBase.__init__(self)
71 def _updateRegistration(self, fd):
72 """Register/unregister an fd with the poller."""
74 self._poller.unregister(fd)
81 if fd in self._writes:
84 self._poller.register(fd, mask)
86 if fd in self._selectables:
87 del self._selectables[fd]
89 def _dictRemove(self, selectable, mdict):
92 fd = selectable.fileno()
93 # make sure the fd is actually real. In some situations we can get
97 # the hard way: necessary because fileno() may disappear at any
98 # moment, thanks to python's underlying sockets impl
99 for fd, fdes in self._selectables.items():
100 if selectable is fdes:
103 # Hmm, maybe not the right course of action? This method can't
104 # fail, because it happens inside error detection...
108 self._updateRegistration(fd)
110 def addReader(self, reader):
111 """Add a FileDescriptor for notification of data available to read.
114 if fd not in self._reads:
115 self._selectables[fd] = reader
117 self._updateRegistration(fd)
119 def addWriter(self, writer):
120 """Add a FileDescriptor for notification of data available to write.
123 if fd not in self._writes:
124 self._selectables[fd] = writer
126 self._updateRegistration(fd)
128 def removeReader(self, reader):
129 """Remove a Selectable for notification of data available to read.
131 return self._dictRemove(reader, self._reads)
133 def removeWriter(self, writer):
134 """Remove a Selectable for notification of data available to write.
136 return self._dictRemove(writer, self._writes)
140 Remove all selectables, and return a list of them.
142 return self._removeAll(
143 [self._selectables[fd] for fd in self._reads],
144 [self._selectables[fd] for fd in self._writes])
147 def doPoll(self, timeout):
148 """Poll the poller for new events."""
149 if timeout is not None:
150 timeout = int(timeout * 1000) # convert seconds to milliseconds
153 l = self._poller.poll(timeout)
154 except SelectError, e:
155 if e.args[0] == errno.EINTR:
159 _drdw = self._doReadOrWrite
162 selectable = self._selectables[fd]
164 # Handles the infrequent case where one selectable's
165 # handler disconnects another.
167 log.callWithLogger(selectable, _drdw, selectable, fd, event)
171 def getReaders(self):
172 return [self._selectables[fd] for fd in self._reads]
175 def getWriters(self):
176 return [self._selectables[fd] for fd in self._writes]
181 """Install the poll() reactor."""
183 from twisted.internet.main import installReactor
187 __all__ = ["PollReactor", "install"]