<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># enigma2 reactor: based on pollreactor, which is
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
# See LICENSE for details.


"""
Maintainer: U{Felix Domke&lt;mailto:tmbinc@elitedvb.net&gt;}
"""

# System imports
import select, errno, sys

# Twisted imports
from twisted.python import log, 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 = { }
		self.eApp = getApplication()

	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):
		try:
			r = self.eApp.poll(timeout, self.dict)
		except KeyboardInterrupt:
			return None
		return r

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]
		
		
		poller.eApp.interruptPoll()

	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 &amp; POLL_DISCONNECTED and not (event &amp; POLLIN):
			why = main.CONNECTION_LOST
		else:
			try:
				if event &amp; POLLIN:
					why = selectable.doRead()
					inRead = True
				if not why and event &amp; 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 callLater(self, *args, **kwargs):
		poller.eApp.interruptPoll()
		return posixbase.PosixReactorBase.callLater(self, *args, **kwargs)

def install():
	"""Install the poll() reactor."""
	
	p = PollReactor()
	main.installReactor(p)

__all__ = ["PollReactor", "install"]
</pre></body></html>