~vishvananda/nova/network-refactor

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/internet/selectreactor.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
# -*- test-case-name: twisted.test.test_internet -*-
 
2
# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
 
 
6
"""
 
7
Select reactor
 
8
 
 
9
Maintainer: Itamar Shtull-Trauring
 
10
"""
 
11
 
 
12
from time import sleep
 
13
import sys
 
14
import select
 
15
from errno import EINTR, EBADF
 
16
 
 
17
from zope.interface import implements
 
18
 
 
19
from twisted.internet.interfaces import IReactorFDSet
 
20
from twisted.internet import error
 
21
from twisted.internet import posixbase
 
22
from twisted.python import log
 
23
from twisted.python.runtime import platformType
 
24
 
 
25
 
 
26
def win32select(r, w, e, timeout=None):
 
27
    """Win32 select wrapper."""
 
28
    if not (r or w):
 
29
        # windows select() exits immediately when no sockets
 
30
        if timeout is None:
 
31
            timeout = 0.01
 
32
        else:
 
33
            timeout = min(timeout, 0.001)
 
34
        sleep(timeout)
 
35
        return [], [], []
 
36
    # windows doesn't process 'signals' inside select(), so we set a max
 
37
    # time or ctrl-c will never be recognized
 
38
    if timeout is None or timeout > 0.5:
 
39
        timeout = 0.5
 
40
    r, w, e = select.select(r, w, w, timeout)
 
41
    return r, w + e, []
 
42
 
 
43
if platformType == "win32":
 
44
    _select = win32select
 
45
else:
 
46
    _select = select.select
 
47
 
 
48
# Exceptions that doSelect might return frequently
 
49
_NO_FILENO = error.ConnectionFdescWentAway('Handler has no fileno method')
 
50
_NO_FILEDESC = error.ConnectionFdescWentAway('Filedescriptor went away')
 
51
 
 
52
class SelectReactor(posixbase.PosixReactorBase):
 
53
    """
 
54
    A select() based reactor - runs on all POSIX platforms and on Win32.
 
55
 
 
56
    @ivar _reads: A dictionary mapping L{FileDescriptor} instances to arbitrary
 
57
        values (this is essentially a set).  Keys in this dictionary will be
 
58
        checked for read events.
 
59
 
 
60
    @ivar _writes: A dictionary mapping L{FileDescriptor} instances to
 
61
        arbitrary values (this is essentially a set).  Keys in this dictionary
 
62
        will be checked for writability.
 
63
    """
 
64
    implements(IReactorFDSet)
 
65
 
 
66
    def __init__(self):
 
67
        """
 
68
        Initialize file descriptor tracking dictionaries and the base class.
 
69
        """
 
70
        self._reads = {}
 
71
        self._writes = {}
 
72
        posixbase.PosixReactorBase.__init__(self)
 
73
 
 
74
 
 
75
    def _preenDescriptors(self):
 
76
        log.msg("Malformed file descriptor found.  Preening lists.")
 
77
        readers = self._reads.keys()
 
78
        writers = self._writes.keys()
 
79
        self._reads.clear()
 
80
        self._writes.clear()
 
81
        for selDict, selList in ((self._reads, readers),
 
82
                                 (self._writes, writers)):
 
83
            for selectable in selList:
 
84
                try:
 
85
                    select.select([selectable], [selectable], [selectable], 0)
 
86
                except Exception, e:
 
87
                    log.msg("bad descriptor %s" % selectable)
 
88
                    self._disconnectSelectable(selectable, e, False)
 
89
                else:
 
90
                    selDict[selectable] = 1
 
91
 
 
92
 
 
93
    def doSelect(self, timeout):
 
94
        """
 
95
        Run one iteration of the I/O monitor loop.
 
96
 
 
97
        This will run all selectables who had input or output readiness
 
98
        waiting for them.
 
99
        """
 
100
        while 1:
 
101
            try:
 
102
                r, w, ignored = _select(self._reads.keys(),
 
103
                                        self._writes.keys(),
 
104
                                        [], timeout)
 
105
                break
 
106
            except ValueError, ve:
 
107
                # Possibly a file descriptor has gone negative?
 
108
                log.err()
 
109
                self._preenDescriptors()
 
110
            except TypeError, te:
 
111
                # Something *totally* invalid (object w/o fileno, non-integral
 
112
                # result) was passed
 
113
                log.err()
 
114
                self._preenDescriptors()
 
115
            except (select.error, IOError), se:
 
116
                # select(2) encountered an error
 
117
                if se.args[0] in (0, 2):
 
118
                    # windows does this if it got an empty list
 
119
                    if (not self._reads) and (not self._writes):
 
120
                        return
 
121
                    else:
 
122
                        raise
 
123
                elif se.args[0] == EINTR:
 
124
                    return
 
125
                elif se.args[0] == EBADF:
 
126
                    self._preenDescriptors()
 
127
                else:
 
128
                    # OK, I really don't know what's going on.  Blow up.
 
129
                    raise
 
130
        _drdw = self._doReadOrWrite
 
131
        _logrun = log.callWithLogger
 
132
        for selectables, method, fdset in ((r, "doRead", self._reads),
 
133
                                           (w,"doWrite", self._writes)):
 
134
            for selectable in selectables:
 
135
                # if this was disconnected in another thread, kill it.
 
136
                # ^^^^ --- what the !@#*?  serious!  -exarkun
 
137
                if selectable not in fdset:
 
138
                    continue
 
139
                # This for pausing input when we're not ready for more.
 
140
                _logrun(selectable, _drdw, selectable, method, dict)
 
141
 
 
142
    doIteration = doSelect
 
143
 
 
144
    def _doReadOrWrite(self, selectable, method, dict):
 
145
        try:
 
146
            why = getattr(selectable, method)()
 
147
            handfn = getattr(selectable, 'fileno', None)
 
148
            if not handfn:
 
149
                why = _NO_FILENO
 
150
            elif handfn() == -1:
 
151
                why = _NO_FILEDESC
 
152
        except:
 
153
            why = sys.exc_info()[1]
 
154
            log.err()
 
155
        if why:
 
156
            self._disconnectSelectable(selectable, why, method=="doRead")
 
157
 
 
158
    def addReader(self, reader):
 
159
        """
 
160
        Add a FileDescriptor for notification of data available to read.
 
161
        """
 
162
        self._reads[reader] = 1
 
163
 
 
164
    def addWriter(self, writer):
 
165
        """
 
166
        Add a FileDescriptor for notification of data available to write.
 
167
        """
 
168
        self._writes[writer] = 1
 
169
 
 
170
    def removeReader(self, reader):
 
171
        """
 
172
        Remove a Selectable for notification of data available to read.
 
173
        """
 
174
        if reader in self._reads:
 
175
            del self._reads[reader]
 
176
 
 
177
    def removeWriter(self, writer):
 
178
        """
 
179
        Remove a Selectable for notification of data available to write.
 
180
        """
 
181
        if writer in self._writes:
 
182
            del self._writes[writer]
 
183
 
 
184
    def removeAll(self):
 
185
        return self._removeAll(self._reads, self._writes)
 
186
 
 
187
 
 
188
    def getReaders(self):
 
189
        return self._reads.keys()
 
190
 
 
191
 
 
192
    def getWriters(self):
 
193
        return self._writes.keys()
 
194
 
 
195
 
 
196
 
 
197
def install():
 
198
    """Configure the twisted mainloop to be run using the select() reactor.
 
199
    """
 
200
    reactor = SelectReactor()
 
201
    from twisted.internet.main import installReactor
 
202
    installReactor(reactor)
 
203
 
 
204
__all__ = ['install']