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