add eListboxEPGContent
[enigma2.git] / lib / base / ebase.cpp
1 #include <lib/base/ebase.h>
2
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <errno.h>
6
7 #include <lib/base/eerror.h>
8 #include <lib/base/elock.h>
9
10 eSocketNotifier::eSocketNotifier(eMainloop *context, int fd, int requested, bool startnow): context(*context), fd(fd), state(0), requested(requested)
11 {
12         if (startnow)   
13                 start();
14 }
15
16 eSocketNotifier::~eSocketNotifier()
17 {
18         stop();
19 }
20
21 void eSocketNotifier::start()
22 {
23         if (state)
24                 stop();
25
26         context.addSocketNotifier(this);
27         state=1;
28 }
29
30 void eSocketNotifier::stop()
31 {
32         if (state)
33                 context.removeSocketNotifier(this);
34
35         state=0;
36 }
37
38                                         // timer
39 void eTimer::start(long msek, bool singleShot)
40 {
41         if (bActive)
42                 stop();
43
44         bActive = true;
45         bSingleShot = singleShot;
46         interval = msek;
47         gettimeofday(&nextActivation, 0);
48         nextActivation += (msek<0 ? 0 : msek);
49 //      eDebug("this = %p\nnow sec = %d, usec = %d\nadd %d msec", this, nextActivation.tv_sec, nextActivation.tv_usec, msek);
50 //      eDebug("next Activation sec = %d, usec = %d", nextActivation.tv_sec, nextActivation.tv_usec );
51         context.addTimer(this);
52 }
53
54 void eTimer::startLongTimer( int seconds )
55 {
56         if (bActive)
57                 stop();
58
59         bActive = bSingleShot = true;
60         interval = 0;
61         gettimeofday(&nextActivation, 0);
62 //      eDebug("this = %p\nnow sec = %d, usec = %d\nadd %d msec", this, nextActivation.tv_sec, nextActivation.tv_usec, msek);
63         if ( seconds > 0 )
64                 nextActivation.tv_sec += seconds;
65 //      eDebug("next Activation sec = %d, usec = %d", nextActivation.tv_sec, nextActivation.tv_usec );
66         context.addTimer(this);
67 }
68
69 void eTimer::stop()
70 {
71         if (bActive)
72         {
73                 bActive=false;
74                 context.removeTimer(this);
75         }
76 }
77
78 void eTimer::changeInterval(long msek)
79 {
80         if (bActive)  // Timer is running?
81         {
82                 context.removeTimer(this);       // then stop
83                 nextActivation -= interval;  // sub old interval
84         }
85         else
86                 bActive=true; // then activate Timer
87
88         interval = msek;                                                // set new Interval
89         nextActivation += interval;             // calc nextActivation
90
91         context.addTimer(this);                         // add Timer to context TimerList
92 }
93
94 void eTimer::activate()   // Internal Funktion... called from eApplication
95 {
96         context.removeTimer(this);
97
98         if (!bSingleShot)
99         {
100                 nextActivation += interval;
101                 context.addTimer(this);
102         }
103         else
104                 bActive=false;
105
106         /*emit*/ timeout();
107 }
108
109 void eTimer::addTimeOffset( int offset )
110 {
111         nextActivation.tv_sec += offset;
112 }
113
114 // mainloop
115 ePtrList<eMainloop> eMainloop::existing_loops;
116
117 void eMainloop::addSocketNotifier(eSocketNotifier *sn)
118 {
119         notifiers.insert(std::pair<int,eSocketNotifier*> (sn->getFD(), sn));
120 }
121
122 void eMainloop::removeSocketNotifier(eSocketNotifier *sn)
123 {
124         notifiers.erase(sn->getFD());
125 }
126
127 void eMainloop::processOneEvent()
128 {
129                 /* notes:
130                   - we should use epoll(4)
131                   - timer are checked twice. there was a strong reason for it, but i can't remember. (FIXME)
132                   - for each time, we gettimeofday() and check wether the timer should fire.
133                     we should do this all better - we know how long the poll last, so we know which
134                     timers should fire. Problem is that a timer handler could have required so
135                     much time that another timer fired.
136
137                     A probably structure could look
138
139                     while (1)
140                     {
141                             time = gettimeofday()
142                             timeout = calculate_pending_timers(time);
143
144                       doPoll(timeout or infinite);
145
146                         if (poll_had_results)
147                                 handle_poll_handler();
148                         else
149                                     fire_timers(time + timeout)
150                           }
151
152                           the gettimeofday() call is required because fire_timers could last more
153                           than nothing.
154
155                           when poll did no timeout, we don't handle timers, as this will be done
156                           in the next iteration (without adding overhead - we had to get the new
157                           time anyway
158                 */
159
160                 /* get current time */
161         timeval now;
162         gettimeofday(&now, 0);
163         
164         int poll_timeout = -1; /* infinite in case of empty timer list */
165         
166         if (m_timer_list)
167         {
168                 poll_timeout = timeval_to_usec(m_timer_list.begin()->getNextActivation() - now);
169                         /* if current timer already passed, don't delay infinite. */
170                 if (poll_timeout < 0)
171                         poll_timeout = 0;
172                         
173                         /* convert us to ms */
174                 poll_timeout /= 1000;
175         }
176         
177         int ret = 0;
178
179         if (poll_timeout)
180         {
181                         // build the poll aray
182                 int fdcount = notifiers.size();
183                 pollfd* pfd = new pollfd[fdcount];  // make new pollfd array
184
185                 std::map<int,eSocketNotifier*>::iterator it(notifiers.begin());
186                 for (int i=0; i < fdcount; i++, it++)
187                 {
188                         pfd[i].fd = it->first;
189                         pfd[i].events = it->second->getRequested();
190                 }
191
192                 ret = poll(pfd, fdcount, poll_timeout);
193
194                         /* ret > 0 means that there are some active poll entries. */
195                 if (ret > 0)
196                 {
197                         for (int i=0; i < fdcount ; i++)
198                         {
199                                 if (notifiers.find(pfd[i].fd) == notifiers.end())
200                                         continue;
201                                 
202                                 int req = notifiers[pfd[i].fd]->getRequested();
203                                 
204                                 if (pfd[i].revents & req)
205                                 {
206                                         notifiers[pfd[i].fd]->activate(pfd[i].revents);
207                                 
208                                         if (!--ret)
209                                                 break;
210                                 } else if (pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL))
211                                         eFatal("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d) -> FIX YOUR CODE", pfd[i].fd,pfd[i].revents);
212                         }
213                 } else if (ret < 0)
214                 {
215                                 /* when we got a signal, we get EINTR. we do not care, 
216                                    because we check current time in timers anyway. */
217                         if (errno != EINTR)
218                                 eDebug("poll made error (%m)");
219                         else
220                                 ret = 0;
221                 }
222                 delete [] pfd;
223         }
224         
225                 /* when we not processed anything, check timers. */
226         if (!ret)
227         {
228                         /* process all timers which are ready. first remove them out of the list. */
229                 while ((!m_timer_list.empty()) && (m_timer_list.begin()->getNextActivation() < now))
230                         m_timer_list.begin()->activate();
231         }
232 }
233
234 void eMainloop::addTimer(eTimer* e)
235 {
236         m_timer_list.insert_in_order(e);
237 }
238
239 void eMainloop::removeTimer(eTimer* e)
240 {
241         m_timer_list.remove(e);
242 }
243
244 int eMainloop::exec()
245 {
246         if (!loop_level)
247         {
248                 app_quit_now = false;
249                 app_exit_loop = false;
250                 enter_loop();
251         }
252         return retval;
253 }
254
255 void eMainloop::enter_loop()
256 {
257         loop_level++;
258         // Status der vorhandenen Loop merken
259         bool old_exit_loop = app_exit_loop;
260
261         app_exit_loop = false;
262
263         while (!app_exit_loop && !app_quit_now)
264                 processOneEvent();
265
266         // wiederherstellen der vorherigen app_exit_loop
267         app_exit_loop = old_exit_loop;
268
269         --loop_level;
270
271         if (!loop_level)
272         {
273                 // do something here on exit the last loop
274         }
275 }
276
277 void eMainloop::exit_loop()  // call this to leave the current loop
278 {
279         app_exit_loop = true;
280 }
281
282 void eMainloop::quit( int ret )   // call this to leave all loops
283 {
284         retval=ret;
285         app_quit_now = true;
286 }
287
288 void eMainloop::addTimeOffset(int offset)
289 {
290         singleLock s(recalcLock);
291         for (ePtrList<eTimer>::iterator it(m_timer_list); it != m_timer_list.end(); ++it )
292                 it->addTimeOffset(offset);
293 }
294
295 eApplication* eApp = 0;