1 # enigma2 reactor: based on pollreactor, which is
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
7 Maintainer: U{Felix Domke<mailto:tmbinc@elitedvb.net>}
11 import select, errno, sys
14 from twisted.python import log, threadable, failure
15 from twisted.internet import main, posixbase, error
16 #from twisted.internet.pollreactor import PollReactor, poller
18 from enigma import getApplication
25 POLL_DISCONNECTED = (select.POLLHUP | select.POLLERR | select.POLLNVAL)
31 def register(self, fd, eventmask = select.POLLIN | select.POLLERR | select.POLLOUT):
32 self.dict[fd] = eventmask
34 def unregister(self, fd):
37 def poll(self, timeout = None):
38 return getApplication().poll(timeout, self.dict)
40 poller = E2SharedPoll()
42 class PollReactor(posixbase.PosixReactorBase):
43 """A reactor that uses poll(2)."""
45 def _updateRegistration(self, fd):
46 """Register/unregister an fd with the poller."""
53 if reads.has_key(fd): mask = mask | select.POLLIN
54 if writes.has_key(fd): mask = mask | select.POLLOUT
56 poller.register(fd, mask)
58 if selectables.has_key(fd): del selectables[fd]
60 def _dictRemove(self, selectable, mdict):
63 fd = selectable.fileno()
64 # make sure the fd is actually real. In some situations we can get
68 # the hard way: necessary because fileno() may disappear at any
69 # moment, thanks to python's underlying sockets impl
70 for fd, fdes in selectables.items():
71 if selectable is fdes:
74 # Hmm, maybe not the right course of action? This method can't
75 # fail, because it happens inside error detection...
79 self._updateRegistration(fd)
81 def addReader(self, reader):
82 """Add a FileDescriptor for notification of data available to read.
85 if not reads.has_key(fd):
86 selectables[fd] = reader
88 self._updateRegistration(fd)
90 def addWriter(self, writer, writes=writes, selectables=selectables):
91 """Add a FileDescriptor for notification of data available to write.
94 if not writes.has_key(fd):
95 selectables[fd] = writer
97 self._updateRegistration(fd)
99 def removeReader(self, reader, reads=reads):
100 """Remove a Selectable for notification of data available to read.
102 return self._dictRemove(reader, reads)
104 def removeWriter(self, writer, writes=writes):
105 """Remove a Selectable for notification of data available to write.
107 return self._dictRemove(writer, writes)
109 def removeAll(self, reads=reads, writes=writes, selectables=selectables):
110 """Remove all selectables, and return a list of them."""
111 if self.waker is not None:
112 self.removeReader(self.waker)
113 result = selectables.values()
114 fds = selectables.keys()
119 poller.unregister(fd)
121 if self.waker is not None:
122 self.addReader(self.waker)
125 def doPoll(self, timeout,
128 selectables=selectables,
131 POLLIN=select.POLLIN,
132 POLLOUT=select.POLLOUT):
133 """Poll the poller for new events."""
134 if timeout is not None:
135 timeout = int(timeout * 1000) # convert seconds to milliseconds
138 l = poller.poll(timeout)
143 except select.error, e:
144 if e[0] == errno.EINTR:
148 _drdw = self._doReadOrWrite
151 selectable = selectables[fd]
153 # Handles the infrequent case where one selectable's
154 # handler disconnects another.
156 log.callWithLogger(selectable, _drdw, selectable, fd, event, POLLIN, POLLOUT, log)
160 def _doReadOrWrite(self, selectable, fd, event, POLLIN, POLLOUT, log,
162 error.ConnectionDone: failure.Failure(error.ConnectionDone()),
163 error.ConnectionLost: failure.Failure(error.ConnectionLost())
167 if event & POLL_DISCONNECTED and not (event & POLLIN):
168 why = main.CONNECTION_LOST
172 why = selectable.doRead()
174 if not why and event & POLLOUT:
175 why = selectable.doWrite()
177 if not selectable.fileno() == fd:
178 why = error.ConnectionFdescWentAway('Filedescriptor went away')
182 why = sys.exc_info()[1]
184 self._disconnectSelectable(selectable, why, inRead)
188 """Install the poll() reactor."""
191 main.installReactor(p)
193 __all__ = ["PollReactor", "install"]