From 2c10049e10195f88b1eefec26f70f5019d316cc8 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Sun, 19 Feb 2006 22:35:02 +0000 Subject: [PATCH] add e2reactor --- e2reactor.py | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mytest.py | 3 +- 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 e2reactor.py diff --git a/e2reactor.py b/e2reactor.py new file mode 100644 index 0000000..1ecd40e --- /dev/null +++ b/e2reactor.py @@ -0,0 +1,193 @@ +# enigma2 reactor: based on pollreactor, which is +# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# See LICENSE for details. + + +""" +Maintainer: U{Felix Domke} +""" + +# System imports +import select, errno, sys + +# Twisted imports +from twisted.python import log, threadable, failure +from twisted.internet import main, posixbase, error +#from twisted.internet.pollreactor import PollReactor, poller + +from enigma import getApplication + +# globals +reads = {} +writes = {} +selectables = {} + +POLL_DISCONNECTED = (select.POLLHUP | select.POLLERR | select.POLLNVAL) + +class E2SharedPoll: + def __init__(self): + self.dict = { } + + def register(self, fd, eventmask = select.POLLIN | select.POLLERR | select.POLLOUT): + self.dict[fd] = eventmask + + def unregister(self, fd): + del self.dict[fd] + + def poll(self, timeout = None): + return getApplication().poll(timeout, self.dict) + +poller = E2SharedPoll() + +class PollReactor(posixbase.PosixReactorBase): + """A reactor that uses poll(2).""" + + def _updateRegistration(self, fd): + """Register/unregister an fd with the poller.""" + try: + poller.unregister(fd) + except KeyError: + pass + + mask = 0 + if reads.has_key(fd): mask = mask | select.POLLIN + if writes.has_key(fd): mask = mask | select.POLLOUT + if mask != 0: + poller.register(fd, mask) + else: + if selectables.has_key(fd): del selectables[fd] + + def _dictRemove(self, selectable, mdict): + try: + # the easy way + fd = selectable.fileno() + # make sure the fd is actually real. In some situations we can get + # -1 here. + mdict[fd] + except: + # the hard way: necessary because fileno() may disappear at any + # moment, thanks to python's underlying sockets impl + for fd, fdes in selectables.items(): + if selectable is fdes: + break + else: + # Hmm, maybe not the right course of action? This method can't + # fail, because it happens inside error detection... + return + if mdict.has_key(fd): + del mdict[fd] + self._updateRegistration(fd) + + def addReader(self, reader): + """Add a FileDescriptor for notification of data available to read. + """ + fd = reader.fileno() + if not reads.has_key(fd): + selectables[fd] = reader + reads[fd] = 1 + self._updateRegistration(fd) + + def addWriter(self, writer, writes=writes, selectables=selectables): + """Add a FileDescriptor for notification of data available to write. + """ + fd = writer.fileno() + if not writes.has_key(fd): + selectables[fd] = writer + writes[fd] = 1 + self._updateRegistration(fd) + + def removeReader(self, reader, reads=reads): + """Remove a Selectable for notification of data available to read. + """ + return self._dictRemove(reader, reads) + + def removeWriter(self, writer, writes=writes): + """Remove a Selectable for notification of data available to write. + """ + return self._dictRemove(writer, writes) + + def removeAll(self, reads=reads, writes=writes, selectables=selectables): + """Remove all selectables, and return a list of them.""" + if self.waker is not None: + self.removeReader(self.waker) + result = selectables.values() + fds = selectables.keys() + reads.clear() + writes.clear() + selectables.clear() + for fd in fds: + poller.unregister(fd) + + if self.waker is not None: + self.addReader(self.waker) + return result + + def doPoll(self, timeout, + reads=reads, + writes=writes, + selectables=selectables, + select=select, + log=log, + POLLIN=select.POLLIN, + POLLOUT=select.POLLOUT): + """Poll the poller for new events.""" + if timeout is not None: + timeout = int(timeout * 1000) # convert seconds to milliseconds + + try: + l = poller.poll(timeout) + if l is None: + if self.running: + self.stop() + l = [ ] + except select.error, e: + if e[0] == errno.EINTR: + return + else: + raise + _drdw = self._doReadOrWrite + for fd, event in l: + try: + selectable = selectables[fd] + except KeyError: + # Handles the infrequent case where one selectable's + # handler disconnects another. + continue + log.callWithLogger(selectable, _drdw, selectable, fd, event, POLLIN, POLLOUT, log) + + doIteration = doPoll + + def _doReadOrWrite(self, selectable, fd, event, POLLIN, POLLOUT, log, + faildict={ + error.ConnectionDone: failure.Failure(error.ConnectionDone()), + error.ConnectionLost: failure.Failure(error.ConnectionLost()) + }): + why = None + inRead = False + if event & POLL_DISCONNECTED and not (event & POLLIN): + why = main.CONNECTION_LOST + else: + try: + if event & POLLIN: + why = selectable.doRead() + inRead = True + if not why and event & POLLOUT: + why = selectable.doWrite() + inRead = False + if not selectable.fileno() == fd: + why = error.ConnectionFdescWentAway('Filedescriptor went away') + inRead = False + except: + log.deferr() + why = sys.exc_info()[1] + if why: + self._disconnectSelectable(selectable, why, inRead) + + +def install(): + """Install the poll() reactor.""" + + p = PollReactor() + main.installReactor(p) + +__all__ = ["PollReactor", "install"] diff --git a/mytest.py b/mytest.py index 91cb9f9..8ae28ab 100644 --- a/mytest.py +++ b/mytest.py @@ -22,7 +22,7 @@ InitFallbackFiles() eDVBDB.getInstance().reloadBouquets() try: - from twisted.internet import e2reactor + import e2reactor e2reactor.install() from twisted.internet import reactor @@ -30,6 +30,7 @@ try: def runReactor(): reactor.run() except: + print "twisted not available" def runReactor(): runMainloop() -- 2.7.4