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