switch to 4.2.x (initial add 4.2.0)
[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/macros.h>
14 #include <lib/base/sigc.h>
15 #endif
16
17 #include <lib/base/esignal.h>
18
19 class eMainloop;
20 class MainloopList;
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, const timespec &now )
134 {
135         const timespec tv = orig - now;
136         return (int64_t)tv.tv_sec * 1000 + tv.tv_nsec / 1000000;
137 }
138
139 static inline int64_t timeout_msec ( const timespec & orig )
140 {
141         timespec now;
142         clock_gettime(CLOCK_MONOTONIC, &now);
143         return timeout_msec(orig, now);
144 }
145
146 #endif
147
148 class MainloopList;
149 class eSocketNotifier;
150 class eTimer;
151
152 class eMainloop
153 {
154         friend class eTimer;
155         friend class eSocketNotifier;
156         friend class ePythonConfigQuery;
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         ePtr<MainloopList> m_ml_list;
166 protected:
167         int m_is_idle;
168         int m_idle_count;
169
170         int m_zero;
171         int &m_argc;
172         char **m_argv;
173
174         virtual void enterIdle() { m_is_idle=1; ++m_idle_count; }
175         virtual void leaveIdle() { m_is_idle=0; }
176
177         virtual ~eMainloop();
178 public:
179         eMainloop();
180         eMainloop(int &argc, char **argv);
181 #ifndef SWIG
182         virtual void quit(int ret=0) = 0; // leave all pending loops (recursive leave())
183 #endif
184                 /* run will iterate endlessly until the app is quit, and return
185                    the exit code */
186         virtual int runLoop() = 0;
187
188                 /* m_is_idle needs to be atomic, but it doesn't really matter much, as it's read-only from outside */
189         int isIdle() { return m_is_idle; }
190         int idleCount() { return m_idle_count; }
191
192         int &argc() { return m_argc; }
193         char **argv() { return m_argv; }
194 };
195
196
197                         // die beiden signalquellen: SocketNotifier...
198 /**
199  * \brief Gives a callback when data on a file descriptor is ready.
200  *
201  * This class emits the signal \c eSocketNotifier::activate whenever the
202  * event specified by \c req is available.
203  */
204 class eSocketNotifier: public iObject
205 {
206         friend class eMainloop_native;
207         DECLARE_REF(eSocketNotifier);
208 public:
209         enum { Read=POLLIN, Write=POLLOUT, Priority=POLLPRI, Error=POLLERR, Hungup=POLLHUP };
210 protected:
211         eMainloop *context;
212         eSocketNotifier(eMainloop *context, int fd, int req, bool startnow);
213 private:
214         int fd;
215         int state;
216         int requested;          // requested events (POLLIN, ...)
217         ePtr<MainloopList> m_ml_list;
218 public:
219         /**
220          * \brief Constructs a eSocketNotifier.
221          * \param context The thread where to bind the socketnotifier to. The signal is emitted from that thread.
222          * \param fd The filedescriptor to monitor. Can be a device or a socket.
223          * \param req The events to watch to, normally either \c Read or \c Write. You can specify any events that \c poll supports.
224          * \param startnow Specifies if the socketnotifier should start immediately.
225          */
226 #ifndef SWIG
227         static eSocketNotifier* create(eMainloop *context, int fd, int req, bool startnow=true) { return context->createSocketNotifier(fd, req, startnow); }
228 #endif
229         virtual ~eSocketNotifier();
230
231         eSignal1<void, int> activated;
232
233         void start();
234         void stop();
235         bool isRunning() { return state; }
236
237         int getFD() { return fd; }
238         int getRequested() { return requested; }
239         virtual void setRequested(int req) { requested = req; }
240         int getState() { return state; }
241         void activate(int what);
242
243 #ifndef SWIG
244         eSmartPtrList<iObject> m_clients;
245 #endif
246 };
247
248                                 // ... und Timer
249 /**
250  * \brief Gives a callback after a specified timeout.
251  *
252  * This class emits the signal \c eTimer::timeout after the specified timeout.
253  */
254 class eTimer: public iObject
255 {
256         friend class eMainloop_native;
257         DECLARE_REF(eTimer);
258         timespec nextActivation;
259         int interval;
260         bool bSingleShot;
261         bool bActive;
262         ePtr<MainloopList> m_ml_list;
263 protected:
264         eMainloop *context;
265         eTimer(eMainloop *context);
266 public:
267         /**
268          * \brief Constructs a timer.
269          *
270          * The timer is not yet active, it has to be started with \c start.
271          * \param context The thread from which the signal should be emitted.
272          */
273 #ifndef SWIG
274         static eTimer *create(eMainloop *context=eApp) { return context->createTimer(); }
275 #endif
276         virtual ~eTimer();
277
278         eSignal0<void> timeout;
279
280         bool isActive() { return bActive; }
281
282         timespec &getNextActivation() { return nextActivation; }
283         int getInterval() const { return interval; }
284
285         void activate();
286         void start(int msec, bool b=false);
287         void stop();
288         void changeInterval(int msek);
289         void startLongTimer(int seconds);
290
291 #ifndef SWIG
292         bool operator<(const eTimer& t) const { return nextActivation < t.nextActivation; }
293         eSmartPtrList<iObject> m_clients;
294 #endif
295 };
296
297 #ifndef SWIG
298                         // werden in einer mainloop verarbeitet
299 class eMainloop_native: public eMainloop
300 {
301 protected:
302         std::multimap<int, eSocketNotifier*> m_notifiers;
303         std::multimap<int, eSocketNotifier*> m_notifiers_new;
304
305         ePtrList<eTimer> m_timers;
306         ePtrList<eTimer> m_timers_new;
307
308         pid_t m_tid;
309         volatile bool m_abort_loop;
310         int m_loop_count;
311         bool m_app_quit_now;
312         int m_retval;
313
314         void processOneEvent(int do_wait=1);
315
316         eSocketNotifier *createSocketNotifier(int fd, int req, bool startnow) { return new eSocketNotifier(this, fd, req, startnow); }
317         eTimer *createTimer() { return new eTimer(this); }
318
319         void addSocketNotifier(eSocketNotifier *sn);
320         void removeSocketNotifier(eSocketNotifier *sn);
321         void addTimer(eTimer* e);
322         void removeTimer(eTimer* e);
323 public:
324         eMainloop_native();
325         eMainloop_native(int &argc, char **argv);
326         ~eMainloop_native();
327
328         void quit(int ret=0); // leave all pending loops (recursive leave())
329                 /* run will iterate endlessly until the app is quit, and return
330                    the exit code */
331         int runLoop();
332
333         void reset() { m_app_quit_now = false; }
334 };
335 #endif  // SWIG
336
337 #endif