1
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
An epoll() 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 epollreactor
11
epollreactor.install()
16
from zope.interface import implements
18
from twisted.internet.interfaces import IReactorFDSet
20
from twisted.python import _epoll
21
from twisted.python import log
22
from twisted.internet import posixbase, error
23
from twisted.internet.main import CONNECTION_LOST
26
_POLL_DISCONNECTED = (_epoll.HUP | _epoll.ERR)
28
class EPollReactor(posixbase.PosixReactorBase):
30
A reactor that uses epoll(4).
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)
57
Initialize epoll object, file descriptor tracking dictionaries, and the
60
# Create the poller we're going to use. The 1024 here is just a hint
61
# to the kernel, it is not a hard maximum.
62
self._poller = _epoll.epoll(1024)
65
self._selectables = {}
66
posixbase.PosixReactorBase.__init__(self)
69
def _add(self, xer, primary, other, selectables, event, antievent):
71
Private method for adding a descriptor from the event loop.
73
It takes care of adding it if new or modifying it if already added
74
for another state (read -> read/write for example).
85
# epoll_ctl can raise all kinds of IOErrors, and every one
86
# indicates a bug either in the reactor or application-code.
87
# Let them all through so someone sees a traceback and fixes
88
# something. We'll do the same thing for every other call to
89
# this method in this file.
90
self._poller._control(cmd, fd, flags)
93
def addReader(self, reader):
95
Add a FileDescriptor for notification of data available to read.
97
self._add(reader, self._reads, self._writes, self._selectables, _epoll.IN, _epoll.OUT)
100
def addWriter(self, writer):
102
Add a FileDescriptor for notification of data available to write.
104
self._add(writer, self._writes, self._reads, self._selectables, _epoll.OUT, _epoll.IN)
107
def _remove(self, xer, primary, other, selectables, event, antievent):
109
Private method for removing a descriptor from the event loop.
111
It does the inverse job of _add, and also add a check in case of the fd
116
for fd, fdes in selectables.items():
130
# See comment above _control call in _add.
131
self._poller._control(cmd, fd, flags)
134
def removeReader(self, reader):
136
Remove a Selectable for notification of data available to read.
138
self._remove(reader, self._reads, self._writes, self._selectables, _epoll.IN, _epoll.OUT)
141
def removeWriter(self, writer):
143
Remove a Selectable for notification of data available to write.
145
self._remove(writer, self._writes, self._reads, self._selectables, _epoll.OUT, _epoll.IN)
149
Remove all selectables, and return a list of them.
151
return self._removeAll(
152
[self._selectables[fd] for fd in self._reads],
153
[self._selectables[fd] for fd in self._writes])
156
def getReaders(self):
157
return [self._selectables[fd] for fd in self._reads]
160
def getWriters(self):
161
return [self._selectables[fd] for fd in self._writes]
164
def doPoll(self, timeout):
166
Poll the poller for new events.
170
timeout = int(timeout * 1000) # convert seconds to milliseconds
173
# Limit the number of events to the number of io objects we're
174
# currently tracking (because that's maybe a good heuristic) and
175
# the amount of time we block to the value specified by our
177
l = self._poller.wait(len(self._selectables), timeout)
179
if err.errno == errno.EINTR:
181
# See epoll_wait(2) for documentation on the other conditions
182
# under which this can fail. They can only be due to a serious
183
# programming error on our part, so let's just announce them
187
_drdw = self._doReadOrWrite
190
selectable = self._selectables[fd]
194
log.callWithLogger(selectable, _drdw, selectable, fd, event)
198
def _doReadOrWrite(self, selectable, fd, event):
200
fd is available for read or write, make the work and raise errors
205
if event & _POLL_DISCONNECTED and not (event & _epoll.IN):
206
why = CONNECTION_LOST
209
if event & _epoll.IN:
210
why = selectable.doRead()
212
if not why and event & _epoll.OUT:
213
why = selectable.doWrite()
215
if selectable.fileno() != fd:
216
why = error.ConnectionFdescWentAway(
217
'Filedescriptor went away')
221
why = sys.exc_info()[1]
223
self._disconnectSelectable(selectable, why, inRead)
227
Install the epoll() reactor.
230
from twisted.internet.main import installReactor
234
__all__ = ["EPollReactor", "install"]