enigma2 20120526 master -> 20120602 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
157         virtual eSocketNotifier *createSocketNotifier(int fd, int req, bool startnow) = 0;
158         virtual eTimer *createTimer() = 0;
159         virtual void addSocketNotifier(eSocketNotifier *sn) = 0;
160         virtual void removeSocketNotifier(eSocketNotifier *sn) = 0;
161         virtual void addTimer(eTimer* e) = 0;
162         virtual void removeTimer(eTimer* e) = 0;
163
164 protected:
165         int m_is_idle;
166         int m_idle_count;
167
168         virtual void enterIdle() { m_is_idle=1; ++m_idle_count; }
169         virtual void leaveIdle() { m_is_idle=0; }
170
171         virtual ~eMainloop();
172 public:
173         eMainloop();
174 #ifndef SWIG
175         virtual void quit(int ret=0) = 0; // leave all pending loops (recursive leave())
176 #endif
177                 /* run will iterate endlessly until the app is quit, and return
178                    the exit code */
179         virtual int runLoop() = 0;
180
181                 /* m_is_idle needs to be atomic, but it doesn't really matter much, as it's read-only from outside */
182         int isIdle() { return m_is_idle; }
183         int idleCount() { return m_idle_count; }
184 };
185
186 #ifndef SWIG
187                         // die beiden signalquellen: SocketNotifier...
188 /**
189  * \brief Gives a callback when data on a file descriptor is ready.
190  *
191  * This class emits the signal \c eSocketNotifier::activate whenever the
192  * event specified by \c req is available.
193  */
194 class eSocketNotifier: public iObject
195 {
196         friend class eMainloop_native;
197         DECLARE_REF(eSocketNotifier);
198 public:
199         enum { Read=POLLIN, Write=POLLOUT, Priority=POLLPRI, Error=POLLERR, Hungup=POLLHUP };
200 protected:
201         eMainloop *context;
202         eSocketNotifier(eMainloop *context, int fd, int req, bool startnow);
203 private:
204         int fd;
205         int state;
206         int requested;          // requested events (POLLIN, ...)
207 public:
208         /**
209          * \brief Constructs a eSocketNotifier.
210          * \param context The thread where to bind the socketnotifier to. The signal is emitted from that thread.
211          * \param fd The filedescriptor to monitor. Can be a device or a socket.
212          * \param req The events to watch to, normally either \c Read or \c Write. You can specify any events that \c poll supports.
213          * \param startnow Specifies if the socketnotifier should start immediately.
214          */
215         static eSocketNotifier* create(eMainloop *context, int fd, int req, bool startnow=true) { return context->createSocketNotifier(fd, req, startnow); }
216         virtual ~eSocketNotifier();
217
218         PSignal1<void, int> activated;
219
220         void start();
221         void stop();
222         bool isRunning() { return state; }
223
224         int getFD() { return fd; }
225         int getRequested() { return requested; }
226         virtual void setRequested(int req) { requested = req; }
227         int getState() { return state; }
228         void activate(int what);
229
230         eSmartPtrList<iObject> m_clients;
231 };
232
233                                 // ... und Timer
234 /**
235  * \brief Gives a callback after a specified timeout.
236  *
237  * This class emits the signal \c eTimer::timeout after the specified timeout.
238  */
239 class eTimer: public iObject
240 {
241         friend class eMainloop_native;
242         DECLARE_REF(eTimer);
243         timespec nextActivation;
244         int interval;
245         bool bSingleShot;
246         bool bActive;
247 protected:
248         eMainloop *context;
249         eTimer(eMainloop *context);
250 public:
251         /**
252          * \brief Constructs a timer.
253          *
254          * The timer is not yet active, it has to be started with \c start.
255          * \param context The thread from which the signal should be emitted.
256          */
257         static eTimer *create(eMainloop *context=eApp) { return context->createTimer(); }
258         virtual ~eTimer();
259
260         PSignal0<void> timeout;
261
262         bool isActive() { return bActive; }
263
264         timespec &getNextActivation() { return nextActivation; }
265         int getInterval() const { return interval; }
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 protected:
280         std::multimap<int, eSocketNotifier*> m_notifiers;
281         std::multimap<int, eSocketNotifier*> m_notifiers_new;
282
283         ePtrList<eTimer> m_timer_list;
284
285         volatile bool m_abort_loop;
286         int m_loop_count;
287         bool m_app_quit_now;
288         int m_retval;
289
290         void processOneEvent(int do_wait=1);
291
292         eSocketNotifier *createSocketNotifier(int fd, int req, bool startnow) { return new eSocketNotifier(this, fd, req, startnow); }
293         eTimer *createTimer() { return new eTimer(this); }
294
295         void addSocketNotifier(eSocketNotifier *sn);
296         void removeSocketNotifier(eSocketNotifier *sn);
297         void addTimer(eTimer* e) { m_timer_list.insert_in_order(e); }
298         void removeTimer(eTimer* e) { m_timer_list.remove(e); }
299 public:
300         eMainloop_native();
301         ~eMainloop_native();
302
303         void quit(int ret=0); // leave all pending loops (recursive leave())
304                 /* run will iterate endlessly until the app is quit, and return
305                    the exit code */
306         int runLoop();
307
308         void reset() { m_app_quit_now = false; }
309 };
310 #endif  // SWIG
311
312 #endif