1
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
2
# See LICENSE for details.
6
A poll() based implementation of the twisted main loop.
8
To install the event loop (and you should do this before any connections,
9
listeners or connectors are added)::
11
from twisted.internet import pollreactor
17
from select import error as SelectError, poll
18
from select import POLLIN, POLLOUT, POLLHUP, POLLERR, POLLNVAL
20
from zope.interface import implements
23
from twisted.python import log
24
from twisted.internet import main, posixbase, error
25
from twisted.internet.interfaces import IReactorFDSet
27
POLL_DISCONNECTED = (POLLHUP | POLLERR | POLLNVAL)
30
class PollReactor(posixbase.PosixReactorBase):
32
A reactor that uses poll(2).
34
@ivar _poller: A L{poll} which will be used to check for I/O
37
@ivar _selectables: A dictionary mapping integer file descriptors to
38
instances of L{FileDescriptor} which have been registered with the
39
reactor. All L{FileDescriptors} which are currently receiving read or
40
write readiness notifications will be present as values in this
43
@ivar _reads: A dictionary mapping integer file descriptors to arbitrary
44
values (this is essentially a set). Keys in this dictionary will be
45
registered with C{_poller} for read readiness notifications which will
46
be dispatched to the corresponding L{FileDescriptor} instances in
49
@ivar _writes: A dictionary mapping integer file descriptors to arbitrary
50
values (this is essentially a set). Keys in this dictionary will be
51
registered with C{_poller} for write readiness notifications which will
52
be dispatched to the corresponding L{FileDescriptor} instances in
55
implements(IReactorFDSet)
59
Initialize polling object, file descriptor tracking dictionaries, and
63
self._selectables = {}
66
posixbase.PosixReactorBase.__init__(self)
69
def _updateRegistration(self, fd):
70
"""Register/unregister an fd with the poller."""
72
self._poller.unregister(fd)
79
if fd in self._writes:
82
self._poller.register(fd, mask)
84
if fd in self._selectables:
85
del self._selectables[fd]
87
def _dictRemove(self, selectable, mdict):
90
fd = selectable.fileno()
91
# make sure the fd is actually real. In some situations we can get
95
# the hard way: necessary because fileno() may disappear at any
96
# moment, thanks to python's underlying sockets impl
97
for fd, fdes in self._selectables.items():
98
if selectable is fdes:
101
# Hmm, maybe not the right course of action? This method can't
102
# fail, because it happens inside error detection...
106
self._updateRegistration(fd)
108
def addReader(self, reader):
109
"""Add a FileDescriptor for notification of data available to read.
112
if fd not in self._reads:
113
self._selectables[fd] = reader
115
self._updateRegistration(fd)
117
def addWriter(self, writer):
118
"""Add a FileDescriptor for notification of data available to write.
121
if fd not in self._writes:
122
self._selectables[fd] = writer
124
self._updateRegistration(fd)
126
def removeReader(self, reader):
127
"""Remove a Selectable for notification of data available to read.
129
return self._dictRemove(reader, self._reads)
131
def removeWriter(self, writer):
132
"""Remove a Selectable for notification of data available to write.
134
return self._dictRemove(writer, self._writes)
138
Remove all selectables, and return a list of them.
140
return self._removeAll(
141
[self._selectables[fd] for fd in self._reads],
142
[self._selectables[fd] for fd in self._writes])
145
def doPoll(self, timeout):
146
"""Poll the poller for new events."""
147
if timeout is not None:
148
timeout = int(timeout * 1000) # convert seconds to milliseconds
151
l = self._poller.poll(timeout)
152
except SelectError, e:
153
if e[0] == errno.EINTR:
157
_drdw = self._doReadOrWrite
160
selectable = self._selectables[fd]
162
# Handles the infrequent case where one selectable's
163
# handler disconnects another.
165
log.callWithLogger(selectable, _drdw, selectable, fd, event)
169
def _doReadOrWrite(self, selectable, fd, event):
172
if event & POLL_DISCONNECTED and not (event & POLLIN):
173
why = main.CONNECTION_LOST
177
why = selectable.doRead()
179
if not why and event & POLLOUT:
180
why = selectable.doWrite()
182
if not selectable.fileno() == fd:
183
why = error.ConnectionFdescWentAway('Filedescriptor went away')
187
why = sys.exc_info()[1]
189
self._disconnectSelectable(selectable, why, inRead)
192
def getReaders(self):
193
return [self._selectables[fd] for fd in self._reads]
196
def getWriters(self):
197
return [self._selectables[fd] for fd in self._writes]
202
"""Install the poll() reactor."""
204
from twisted.internet.main import installReactor
208
__all__ = ["PollReactor", "install"]