~landscape/zope3/ztk-1.1.3

« back to all changes in this revision

Viewing changes to src/twisted/internet/selectreactor.py

  • Committer: Andreas Hasenack
  • Date: 2009-07-20 17:49:16 UTC
  • Revision ID: andreas@canonical.com-20090720174916-g2tn6qmietz2hn0u
Revert twisted removal, it breaks several dozen tests [trivial]

Show diffs side-by-side

added added

removed removed

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