enigma2 20130927 (master) -> 20131001 (master)
[enigma2.git] / usr / include / enigma2 / lib / base / ebase.h
1 #ifndef __ebase_h
2 #define __ebase_h
3
4 #ifndef SWIG
5 #include <vector>
6 #include <map>
7 #include <sys/poll.h>
8 #include <sys/time.h>
9 #include <asm/types.h>
10 #include <time.h>
11
12 #include <lib/base/eptrlist.h>
13 #include <lib/base/sigc.h>
14 #endif
15
16 #include <lib/python/connections.h>
17
18 #define E_UNUSED(x)     (void)x;
19
20 class eMainloop;
21 class MainloopList;
22
23 extern eMainloop* eApp;
24
25 #define DUMP_DESCRIPTOR(class, it) \
26         do { \
27                 eDebug(class"::%s line %d descriptor with tag %04x", __FUNCTION__, __LINE__, (*it)->getTag()); \
28         } while (0);
29
30 #ifndef SWIG
31         /* TODO: remove these inlines. */
32 static inline bool operator<( const timespec &t1, const timespec &t2 )
33 {
34         return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec);
35 }
36
37 static inline bool operator<=( const timespec &t1, const timespec &t2 )
38 {
39         return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec <= t2.tv_nsec);
40 }
41
42 static inline timespec &operator+=( timespec &t1, const timespec &t2 )
43 {
44         t1.tv_sec += t2.tv_sec;
45         if ( (t1.tv_nsec += t2.tv_nsec) >= 1000000000 )
46         {
47                 t1.tv_sec++;
48                 t1.tv_nsec -= 1000000000;
49         }
50         return t1;
51 }
52
53 static inline timespec operator+( const timespec &t1, const timespec &t2 )
54 {
55         timespec tmp;
56         tmp.tv_sec = t1.tv_sec + t2.tv_sec;
57         if ( (tmp.tv_nsec = t1.tv_nsec + t2.tv_nsec) >= 1000000000 )
58         {
59                 tmp.tv_sec++;
60                 tmp.tv_nsec -= 1000000000;
61         }
62         return tmp;
63 }
64
65 static inline timespec operator-( const timespec &t1, const timespec &t2 )
66 {
67         timespec tmp;
68         tmp.tv_sec = t1.tv_sec - t2.tv_sec;
69         if ( (tmp.tv_nsec = t1.tv_nsec - t2.tv_nsec) < 0 )
70         {
71                 tmp.tv_sec--;
72                 tmp.tv_nsec += 1000000000;
73         }
74         return tmp;
75 }
76
77 static inline timespec operator-=( timespec &t1, const timespec &t2 )
78 {
79         t1.tv_sec -= t2.tv_sec;
80         if ( (t1.tv_nsec -= t2.tv_nsec) < 0 )
81         {
82                 t1.tv_sec--;
83                 t1.tv_nsec += 1000000000;
84         }
85         return t1;
86 }
87
88 static inline timespec &operator+=( timespec &t1, const long msek )
89 {
90         t1.tv_sec += msek / 1000;
91         if ( (t1.tv_nsec += (msek % 1000) * 1000000) >= 1000000000 )
92         {
93                 t1.tv_sec++;
94                 t1.tv_nsec -= 1000000000;
95         }
96         return t1;
97 }
98
99 static inline timespec operator+( const timespec &t1, const long msek )
100 {
101         timespec tmp;
102         tmp.tv_sec = t1.tv_sec + msek / 1000;
103         if ( (tmp.tv_nsec = t1.tv_nsec + (msek % 1000) * 1000000) >= 1000000000 )
104         {
105                 tmp.tv_sec++;
106                 tmp.tv_nsec -= 1000000;
107         }
108         return tmp;
109 }
110
111 static inline timespec operator-( const timespec &t1, const long msek )
112 {
113         timespec tmp;
114         tmp.tv_sec = t1.tv_sec - msek / 1000;
115         if ( (tmp.tv_nsec = t1.tv_nsec - (msek % 1000)*1000000) < 0 )
116         {
117                 tmp.tv_sec--;
118                 tmp.tv_nsec += 1000000000;
119         }
120         return tmp;
121 }
122
123 static inline timespec operator-=( timespec &t1, const long msek )
124 {
125         t1.tv_sec -= msek / 1000;
126         if ( (t1.tv_nsec -= (msek % 1000) * 1000000) < 0 )
127         {
128                 t1.tv_sec--;
129                 t1.tv_nsec += 1000000000;
130         }
131         return t1;
132 }
133
134 static inline int64_t timeout_msec ( const timespec & orig )
135 {
136         timespec now;
137         clock_gettime(CLOCK_MONOTONIC, &now);
138         return (int64_t)((orig-now).tv_sec)*1000 + (orig-now).tv_nsec/1000000;
139 }
140
141 static inline int64_t timeout_msec ( const timespec & orig, const timespec &now )
142 {
143         return (int64_t)((orig-now).tv_sec)*1000 + (orig-now).tv_nsec/1000000;
144 }
145
146 #endif
147
148 class MainloopList;
149 class eSocketNotifier;
150 class eTimer;
151 class PSignal;
152
153 class eMainloop
154 {
155         friend class eTimer;
156         friend class eSocketNotifier;
157         friend class ePythonConfigQuery;
158
159         virtual eSocketNotifier *createSocketNotifier(int fd, int req, bool startnow) = 0;
160         virtual eTimer *createTimer() = 0;
161         virtual void addSocketNotifier(eSocketNotifier *sn) = 0;
162         virtual void removeSocketNotifier(eSocketNotifier *sn) = 0;
163         virtual void addTimer(eTimer* e) = 0;
164         virtual void removeTimer(eTimer* e) = 0;
165
166         ePtr<MainloopList> m_ml_list;
167 protected:
168         int m_is_idle;
169         int m_idle_count;
170
171         virtual void enterIdle() { m_is_idle=1; ++m_idle_count; }
172         virtual void leaveIdle() { m_is_idle=0; }
173
174         virtual ~eMainloop();
175 public:
176         eMainloop();
177 #ifndef SWIG
178         virtual void quit(int ret=0) = 0; // leave all pending loops (recursive leave())
179 #endif
180                 /* run will iterate endlessly until the app is quit, and return
181                    the exit code */
182         virtual int runLoop() = 0;
183
184                 /* m_is_idle needs to be atomic, but it doesn't really matter much, as it's read-only from outside */
185         int isIdle() { return m_is_idle; }
186         int idleCount() { return m_idle_count; }
187 };
188
189 #ifndef SWIG
190                         // die beiden signalquellen: SocketNotifier...
191 /**
192  * \brief Gives a callback when data on a file descriptor is ready.
193  *
194  * This class emits the signal \c eSocketNotifier::activate whenever the
195  * event specified by \c req is available.
196  */
197 class eSocketNotifier: public iObject
198 {
199         friend class eMainloop_native;
200         DECLARE_REF(eSocketNotifier);
201 public:
202         enum { Read=POLLIN, Write=POLLOUT, Priority=POLLPRI, Error=POLLERR, Hungup=POLLHUP };
203 protected:
204         eMainloop *context;
205         eSocketNotifier(eMainloop *context, int fd, int req, bool startnow);
206 private:
207         int fd;
208         int state;
209         int requested;          // requested events (POLLIN, ...)
210         ePtr<MainloopList> m_ml_list;
211 public:
212         /**
213          * \brief Constructs a eSocketNotifier.
214          * \param context The thread where to bind the socketnotifier to. The signal is emitted from that thread.
215          * \param fd The filedescriptor to monitor. Can be a device or a socket.
216          * \param req The events to watch to, normally either \c Read or \c Write. You can specify any events that \c poll supports.
217          * \param startnow Specifies if the socketnotifier should start immediately.
218          */
219         static eSocketNotifier* create(eMainloop *context, int fd, int req, bool startnow=true) { return context->createSocketNotifier(fd, req, startnow); }
220         virtual ~eSocketNotifier();
221
222         PSignal1<void, int> activated;
223
224         void start();
225         void stop();
226         bool isRunning() { return state; }
227
228         int getFD() { return fd; }
229         int getRequested() { return requested; }
230         virtual void setRequested(int req) { requested = req; }
231         int getState() { return state; }
232         void activate(int what);
233
234         eSmartPtrList<iObject> m_clients;
235 };
236
237                                 // ... und Timer
238 /**
239  * \brief Gives a callback after a specified timeout.
240  *
241  * This class emits the signal \c eTimer::timeout after the specified timeout.
242  */
243 class eTimer: public iObject
244 {
245         friend class eMainloop_native;
246         DECLARE_REF(eTimer);
247         timespec nextActivation;
248         int interval;
249         bool bSingleShot;
250         bool bActive;
251         ePtr<MainloopList> m_ml_list;
252 protected:
253         eMainloop *context;
254         eTimer(eMainloop *context);
255 public:
256         /**
257          * \brief Constructs a timer.
258          *
259          * The timer is not yet active, it has to be started with \c start.
260          * \param context The thread from which the signal should be emitted.
261          */
262         static eTimer *create(eMainloop *context=eApp) { return context->createTimer(); }
263         virtual ~eTimer();
264
265         PSignal0<void> timeout;
266
267         bool isActive() { return bActive; }
268
269         timespec &getNextActivation() { return nextActivation; }
270         int getInterval() const { return interval; }
271
272         void activate();
273         void start(int msec, bool b=false);
274         void stop();
275         void changeInterval(int msek);
276         void startLongTimer(int seconds);
277         bool operator<(const eTimer& t) const { return nextActivation < t.nextActivation; }
278
279         eSmartPtrList<iObject> m_clients;
280 };
281
282                         // werden in einer mainloop verarbeitet
283 class eMainloop_native: public eMainloop
284 {
285         bool m_timer_sn_thread_checks;
286 protected:
287         std::multimap<int, eSocketNotifier*> m_notifiers;
288         std::multimap<int, eSocketNotifier*> m_notifiers_new;
289
290         ePtrList<eTimer> m_timers;
291         ePtrList<eTimer> m_timers_new;
292
293         pid_t m_tid;
294         volatile bool m_abort_loop;
295         int m_loop_count;
296         bool m_app_quit_now;
297         int m_retval;
298
299         void processOneEvent(int do_wait=1);
300
301         eSocketNotifier *createSocketNotifier(int fd, int req, bool startnow) { return new eSocketNotifier(this, fd, req, startnow); }
302         eTimer *createTimer() { return new eTimer(this); }
303
304         void addSocketNotifier(eSocketNotifier *sn);
305         void removeSocketNotifier(eSocketNotifier *sn);
306         void addTimer(eTimer* e);
307         void removeTimer(eTimer* e);
308 public:
309         eMainloop_native();
310         ~eMainloop_native();
311
312         void quit(int ret=0); // leave all pending loops (recursive leave())
313                 /* run will iterate endlessly until the app is quit, and return
314                    the exit code */
315         int runLoop();
316
317         void reset() { m_app_quit_now = false; }
318 };
319 #endif  // SWIG
320
321 #endif