PageRenderTime 76ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/resources/lib/twisted/twisted/internet/selectreactor.py

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