~vishvananda/nova/network-refactor

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/internet/pollreactor.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
 
 
5
"""
 
6
A poll() based implementation of the twisted main loop.
 
7
 
 
8
To install the event loop (and you should do this before any connections,
 
9
listeners or connectors are added)::
 
10
 
 
11
    from twisted.internet import pollreactor
 
12
    pollreactor.install()
 
13
"""
 
14
 
 
15
# System imports
 
16
import errno, sys
 
17
from select import error as SelectError, poll
 
18
from select import POLLIN, POLLOUT, POLLHUP, POLLERR, POLLNVAL
 
19
 
 
20
from zope.interface import implements
 
21
 
 
22
# Twisted imports
 
23
from twisted.python import log
 
24
from twisted.internet import main, posixbase, error
 
25
from twisted.internet.interfaces import IReactorFDSet
 
26
 
 
27
POLL_DISCONNECTED = (POLLHUP | POLLERR | POLLNVAL)
 
28
 
 
29
 
 
30
class PollReactor(posixbase.PosixReactorBase):
 
31
    """
 
32
    A reactor that uses poll(2).
 
33
 
 
34
    @ivar _poller: A L{poll} which will be used to check for I/O
 
35
        readiness.
 
36
 
 
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
 
41
        dictionary.
 
42
 
 
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
 
47
        C{_selectables}.
 
48
 
 
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
 
53
        C{_selectables}.
 
54
    """
 
55
    implements(IReactorFDSet)
 
56
 
 
57
    def __init__(self):
 
58
        """
 
59
        Initialize polling object, file descriptor tracking dictionaries, and
 
60
        the base class.
 
61
        """
 
62
        self._poller = poll()
 
63
        self._selectables = {}
 
64
        self._reads = {}
 
65
        self._writes = {}
 
66
        posixbase.PosixReactorBase.__init__(self)
 
67
 
 
68
 
 
69
    def _updateRegistration(self, fd):
 
70
        """Register/unregister an fd with the poller."""
 
71
        try:
 
72
            self._poller.unregister(fd)
 
73
        except KeyError:
 
74
            pass
 
75
 
 
76
        mask = 0
 
77
        if fd in self._reads:
 
78
            mask = mask | POLLIN
 
79
        if fd in self._writes:
 
80
            mask = mask | POLLOUT
 
81
        if mask != 0:
 
82
            self._poller.register(fd, mask)
 
83
        else:
 
84
            if fd in self._selectables:
 
85
                del self._selectables[fd]
 
86
 
 
87
    def _dictRemove(self, selectable, mdict):
 
88
        try:
 
89
            # the easy way
 
90
            fd = selectable.fileno()
 
91
            # make sure the fd is actually real.  In some situations we can get
 
92
            # -1 here.
 
93
            mdict[fd]
 
94
        except:
 
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:
 
99
                    break
 
100
            else:
 
101
                # Hmm, maybe not the right course of action?  This method can't
 
102
                # fail, because it happens inside error detection...
 
103
                return
 
104
        if fd in mdict:
 
105
            del mdict[fd]
 
106
            self._updateRegistration(fd)
 
107
 
 
108
    def addReader(self, reader):
 
109
        """Add a FileDescriptor for notification of data available to read.
 
110
        """
 
111
        fd = reader.fileno()
 
112
        if fd not in self._reads:
 
113
            self._selectables[fd] = reader
 
114
            self._reads[fd] =  1
 
115
            self._updateRegistration(fd)
 
116
 
 
117
    def addWriter(self, writer):
 
118
        """Add a FileDescriptor for notification of data available to write.
 
119
        """
 
120
        fd = writer.fileno()
 
121
        if fd not in self._writes:
 
122
            self._selectables[fd] = writer
 
123
            self._writes[fd] =  1
 
124
            self._updateRegistration(fd)
 
125
 
 
126
    def removeReader(self, reader):
 
127
        """Remove a Selectable for notification of data available to read.
 
128
        """
 
129
        return self._dictRemove(reader, self._reads)
 
130
 
 
131
    def removeWriter(self, writer):
 
132
        """Remove a Selectable for notification of data available to write.
 
133
        """
 
134
        return self._dictRemove(writer, self._writes)
 
135
 
 
136
    def removeAll(self):
 
137
        """
 
138
        Remove all selectables, and return a list of them.
 
139
        """
 
140
        return self._removeAll(
 
141
            [self._selectables[fd] for fd in self._reads],
 
142
            [self._selectables[fd] for fd in self._writes])
 
143
 
 
144
 
 
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
 
149
 
 
150
        try:
 
151
            l = self._poller.poll(timeout)
 
152
        except SelectError, e:
 
153
            if e[0] == errno.EINTR:
 
154
                return
 
155
            else:
 
156
                raise
 
157
        _drdw = self._doReadOrWrite
 
158
        for fd, event in l:
 
159
            try:
 
160
                selectable = self._selectables[fd]
 
161
            except KeyError:
 
162
                # Handles the infrequent case where one selectable's
 
163
                # handler disconnects another.
 
164
                continue
 
165
            log.callWithLogger(selectable, _drdw, selectable, fd, event)
 
166
 
 
167
    doIteration = doPoll
 
168
 
 
169
    def _doReadOrWrite(self, selectable, fd, event):
 
170
        why = None
 
171
        inRead = False
 
172
        if event & POLL_DISCONNECTED and not (event & POLLIN):
 
173
            why = main.CONNECTION_LOST
 
174
        else:
 
175
            try:
 
176
                if event & POLLIN:
 
177
                    why = selectable.doRead()
 
178
                    inRead = True
 
179
                if not why and event & POLLOUT:
 
180
                    why = selectable.doWrite()
 
181
                    inRead = False
 
182
                if not selectable.fileno() == fd:
 
183
                    why = error.ConnectionFdescWentAway('Filedescriptor went away')
 
184
                    inRead = False
 
185
            except:
 
186
                log.deferr()
 
187
                why = sys.exc_info()[1]
 
188
        if why:
 
189
            self._disconnectSelectable(selectable, why, inRead)
 
190
 
 
191
 
 
192
    def getReaders(self):
 
193
        return [self._selectables[fd] for fd in self._reads]
 
194
 
 
195
 
 
196
    def getWriters(self):
 
197
        return [self._selectables[fd] for fd in self._writes]
 
198
 
 
199
 
 
200
 
 
201
def install():
 
202
    """Install the poll() reactor."""
 
203
    p = PollReactor()
 
204
    from twisted.internet.main import installReactor
 
205
    installReactor(p)
 
206
 
 
207
 
 
208
__all__ = ["PollReactor", "install"]