1
# -*- test-case-name: twisted.test.test_internet -*-
2
# $Id: default.py,v 1.90 2004/01/06 22:35:22 warner Exp $
4
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
5
# See LICENSE for details.
12
Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>}
15
from time import sleep
18
from zope.interface import implements
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
28
from errno import EINTR, EBADF
30
# global state for selector
35
def win32select(r, w, e, timeout=None):
36
"""Win32 select wrapper."""
38
# windows select() exits immediately when no sockets
42
timeout = min(timeout, 0.001)
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:
49
r, w, e = select.select(r, w, w, timeout)
52
if platformType == "win32":
55
_select = select.select
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')
61
class SelectReactor(posixbase.PosixReactorBase):
62
"""A select() based reactor - runs on all POSIX platforms and on Win32.
64
implements(IReactorFDSet)
66
def _preenDescriptors(self):
67
log.msg("Malformed file descriptor found. Preening lists.")
68
readers = reads.keys()
69
writers = writes.keys()
72
for selDict, selList in ((reads, readers), (writes, writers)):
73
for selectable in selList:
75
select.select([selectable], [selectable], [selectable], 0)
77
log.msg("bad descriptor %s" % selectable)
79
selDict[selectable] = 1
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.
88
"""Run one iteration of the I/O monitor loop.
90
This will run all selectables who had input or output readiness
95
r, w, ignored = _select(reads.keys(),
99
except ValueError, ve:
100
# Possibly a file descriptor has gone negative?
102
self._preenDescriptors()
103
except TypeError, te:
104
# Something *totally* invalid (object w/o fileno, non-integral
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):
116
elif se.args[0] == EINTR:
118
elif se.args[0] == EBADF:
119
self._preenDescriptors()
121
# OK, I really don't know what's going on. Blow up.
123
_drdw = self._doReadOrWrite
124
_logrun = log.callWithLogger
125
for selectables, method, dict in ((r, "doRead", reads),
126
(w,"doWrite", writes)):
128
for selectable in selectables:
129
# if this was disconnected in another thread, kill it.
130
if not hkm(selectable):
132
# This for pausing input when we're not ready for more.
133
_logrun(selectable, _drdw, selectable, method, dict)
135
doIteration = doSelect
137
def _doReadOrWrite(self, selectable, method, dict):
139
why = getattr(selectable, method)()
140
handfn = getattr(selectable, 'fileno', None)
146
why = sys.exc_info()[1]
149
self._disconnectSelectable(selectable, why, method=="doRead")
151
def addReader(self, reader):
152
"""Add a FileDescriptor for notification of data available to read.
156
def addWriter(self, writer):
157
"""Add a FileDescriptor for notification of data available to write.
161
def removeReader(self, reader):
162
"""Remove a Selectable for notification of data available to read.
164
if reads.has_key(reader):
167
def removeWriter(self, writer):
168
"""Remove a Selectable for notification of data available to write.
170
if writes.has_key(writer):
174
return self._removeAll(reads, writes)
178
"""Configure the twisted mainloop to be run using the select() reactor.
180
reactor = SelectReactor()
181
from twisted.internet.main import installReactor
182
installReactor(reactor)
184
__all__ = ['install']