cleanup grayout handling in servicelist.. so no more grayout in timeout channelselect...
[enigma2.git] / e2reactor.py
1 # enigma2 reactor: based on pollreactor, which is
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5
6 """
7 Maintainer: U{Felix Domke<mailto:tmbinc@elitedvb.net>}
8 """
9
10 # System imports
11 import select, errno, sys
12
13 # Twisted imports
14 from twisted.python import log, failure
15 from twisted.internet import main, posixbase, error
16 #from twisted.internet.pollreactor import PollReactor, poller
17
18 from enigma import getApplication
19
20 # globals
21 reads = {}
22 writes = {}
23 selectables = {}
24
25 POLL_DISCONNECTED = (select.POLLHUP | select.POLLERR | select.POLLNVAL)
26
27 class E2SharedPoll:
28         def __init__(self):
29                 self.dict = { }
30                 self.eApp = getApplication()
31
32         def register(self, fd, eventmask = select.POLLIN | select.POLLERR | select.POLLOUT):
33                 self.dict[fd] = eventmask
34         
35         def unregister(self, fd):
36                 del self.dict[fd]
37         
38         def poll(self, timeout = None):
39                 try:
40                         r = self.eApp.poll(timeout, self.dict)
41                 except KeyboardInterrupt:
42                         return None
43                 return r
44
45 poller = E2SharedPoll()
46
47 class PollReactor(posixbase.PosixReactorBase):
48         """A reactor that uses poll(2)."""
49
50         def _updateRegistration(self, fd):
51                 """Register/unregister an fd with the poller."""
52                 try:
53                         poller.unregister(fd)
54                 except KeyError:
55                         pass
56
57                 mask = 0
58                 if reads.has_key(fd): mask = mask | select.POLLIN
59                 if writes.has_key(fd): mask = mask | select.POLLOUT
60                 if mask != 0:
61                         poller.register(fd, mask)
62                 else:
63                         if selectables.has_key(fd): del selectables[fd]
64                 
65                 
66                 poller.eApp.interruptPoll()
67
68         def _dictRemove(self, selectable, mdict):
69                 try:
70                         # the easy way
71                         fd = selectable.fileno()
72                         # make sure the fd is actually real.  In some situations we can get
73                         # -1 here.
74                         mdict[fd]
75                 except:
76                         # the hard way: necessary because fileno() may disappear at any
77                         # moment, thanks to python's underlying sockets impl
78                         for fd, fdes in selectables.items():
79                                 if selectable is fdes:
80                                         break
81                         else:
82                                 # Hmm, maybe not the right course of action?  This method can't
83                                 # fail, because it happens inside error detection...
84                                 return
85                 if mdict.has_key(fd):
86                         del mdict[fd]
87                         self._updateRegistration(fd)
88
89         def addReader(self, reader):
90                 """Add a FileDescriptor for notification of data available to read.
91                 """
92                 fd = reader.fileno()
93                 if not reads.has_key(fd):
94                         selectables[fd] = reader
95                         reads[fd] =  1
96                         self._updateRegistration(fd)
97
98         def addWriter(self, writer, writes=writes, selectables=selectables):
99                 """Add a FileDescriptor for notification of data available to write.
100                 """
101                 fd = writer.fileno()
102                 if not writes.has_key(fd):
103                         selectables[fd] = writer
104                         writes[fd] =  1
105                         self._updateRegistration(fd)
106
107         def removeReader(self, reader, reads=reads):
108                 """Remove a Selectable for notification of data available to read.
109                 """
110                 return self._dictRemove(reader, reads)
111
112         def removeWriter(self, writer, writes=writes):
113                 """Remove a Selectable for notification of data available to write.
114                 """
115                 return self._dictRemove(writer, writes)
116
117         def removeAll(self, reads=reads, writes=writes, selectables=selectables):
118                 """Remove all selectables, and return a list of them."""
119                 if self.waker is not None:
120                         self.removeReader(self.waker)
121                 result = selectables.values()
122                 fds = selectables.keys()
123                 reads.clear()
124                 writes.clear()
125                 selectables.clear()
126                 for fd in fds:
127                         poller.unregister(fd)
128                         
129                 if self.waker is not None:
130                         self.addReader(self.waker)
131                 return result
132
133         def doPoll(self, timeout,
134                            reads=reads,
135                            writes=writes,
136                            selectables=selectables,
137                            select=select,
138                            log=log,
139                            POLLIN=select.POLLIN,
140                            POLLOUT=select.POLLOUT):
141                 """Poll the poller for new events."""
142                 
143                 if timeout is not None:
144                         timeout = int(timeout * 1000) # convert seconds to milliseconds
145
146                 try:
147                         l = poller.poll(timeout)
148                         if l is None:
149                                 if self.running:
150                                         self.stop()
151                                 l = [ ]
152                 except select.error, e:
153                         if e[0] == errno.EINTR:
154                                 return
155                         else:
156                                 raise
157                 _drdw = self._doReadOrWrite
158                 for fd, event in l:
159                         try:
160                                 selectable = selectables[fd]
161                         except KeyError:
162                                 # Handles the infrequent case where one selectable's
163                                 # handler disconnects another.
164                                 continue
165                         log.callWithLogger(selectable, _drdw, selectable, fd, event, POLLIN, POLLOUT, log)
166
167         doIteration = doPoll
168
169         def _doReadOrWrite(self, selectable, fd, event, POLLIN, POLLOUT, log, 
170                 faildict={
171                         error.ConnectionDone: failure.Failure(error.ConnectionDone()),
172                         error.ConnectionLost: failure.Failure(error.ConnectionLost())
173                 }):
174                 why = None
175                 inRead = False
176                 if event & POLL_DISCONNECTED and not (event & POLLIN):
177                         why = main.CONNECTION_LOST
178                 else:
179                         try:
180                                 if event & POLLIN:
181                                         why = selectable.doRead()
182                                         inRead = True
183                                 if not why and event & POLLOUT:
184                                         why = selectable.doWrite()
185                                         inRead = False
186                                 if not selectable.fileno() == fd:
187                                         why = error.ConnectionFdescWentAway('Filedescriptor went away')
188                                         inRead = False
189                         except:
190                                 log.deferr()
191                                 why = sys.exc_info()[1]
192                 if why:
193                         self._disconnectSelectable(selectable, why, inRead)
194
195         def callLater(self, *args, **kwargs):
196                 poller.eApp.interruptPoll()
197                 return posixbase.PosixReactorBase.callLater(self, *args, **kwargs)
198
199 def install():
200         """Install the poll() reactor."""
201         
202         p = PollReactor()
203         main.installReactor(p)
204
205 __all__ = ["PollReactor", "install"]