OSDN Git Service

ed99a124694a94cfdbd6a1342d4957f08df4a1eb
[android-x86/hardware-ril.git] / libril / ril_event.cpp
1 /* //device/libs/telephony/ril_event.cpp
2 **
3 ** Copyright 2008, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License"); 
6 ** you may not use this file except in compliance with the License. 
7 ** You may obtain a copy of the License at 
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0 
10 **
11 ** Unless required by applicable law or agreed to in writing, software 
12 ** distributed under the License is distributed on an "AS IS" BASIS, 
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14 ** See the License for the specific language governing permissions and 
15 ** limitations under the License.
16 */
17
18 #define LOG_TAG "RILC"
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <utils/Log.h>
25 #include <ril_event.h>
26 #include <string.h>
27 #include <sys/time.h>
28 #include <time.h>
29
30 #include <pthread.h>
31 static pthread_mutex_t listMutex;
32 #define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex)
33 #define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex)
34 #define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL)
35 #define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex)
36
37 #define timeradd(tvp, uvp, vvp)                                         \
38         do {                                                            \
39                 (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;          \
40                 (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
41                 if ((vvp)->tv_usec >= 1000000) {                        \
42                         (vvp)->tv_sec++;                                \
43                         (vvp)->tv_usec -= 1000000;                      \
44                 }                                                       \
45         } while (0)
46
47 #ifndef timercmp
48 #define timercmp(a, b, op)               \
49         ((a)->tv_sec == (b)->tv_sec      \
50         ? (a)->tv_usec op (b)->tv_usec   \
51         : (a)->tv_sec op (b)->tv_sec)
52 #endif
53
54 #ifndef timersub
55 #define timersub(a, b, res)                           \
56     do {                                              \
57         (res)->tv_sec = (a)->tv_sec - (b)->tv_sec;    \
58         (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
59         if ((res)->tv_usec < 0) {                     \
60             (res)->tv_usec += 1000000;                \
61             (res)->tv_sec -= 1;                       \
62         }                                             \
63     } while(0);
64 #endif
65
66 static fd_set readFds;
67 static int nfds = 0;
68
69 static struct ril_event * watch_table[MAX_FD_EVENTS];
70 static struct ril_event timer_list;
71 static struct ril_event pending_list;
72
73 #define DEBUG 0
74
75 #if DEBUG
76 #define dlog(x...) LOGD( x )
77 static void dump_event(struct ril_event * ev)
78 {
79     dlog("~~~~ Event %x ~~~~", (unsigned int)ev);
80     dlog("     next    = %x", (unsigned int)ev->next);
81     dlog("     prev    = %x", (unsigned int)ev->prev);
82     dlog("     fd      = %d", ev->fd);
83     dlog("     pers    = %d", ev->persist);
84     dlog("     timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec);
85     dlog("     func    = %x", (unsigned int)ev->func);
86     dlog("     param   = %x", (unsigned int)ev->param);
87     dlog("~~~~~~~~~~~~~~~~~~");
88 }
89 #else
90 #define dlog(x...)
91 #define dump_event(x)
92 #endif
93
94 static void getNow(struct timeval * tv)
95 {
96 #ifdef HAVE_POSIX_CLOCKS
97     struct timespec ts;
98     clock_gettime(CLOCK_MONOTONIC, &ts);
99     tv->tv_sec = ts.tv_sec;
100     tv->tv_usec = ts.tv_nsec/1000;
101 #else
102     gettimeofday(tv, NULL);
103 #endif
104 }
105
106 static void init_list(struct ril_event * list)
107 {
108     memset(list, 0, sizeof(struct ril_event));
109     list->next = list;
110     list->prev = list;
111     list->fd = -1;
112 }
113
114 static void addToList(struct ril_event * ev, struct ril_event * list)
115 {
116     ev->next = list;
117     ev->prev = list->prev;
118     ev->prev->next = ev;
119     list->prev = ev;
120     dump_event(ev);
121 }
122
123 static void removeFromList(struct ril_event * ev)
124 {
125     dlog("~~~~ Removing event ~~~~");
126     dump_event(ev);
127
128     ev->next->prev = ev->prev;
129     ev->prev->next = ev->next;
130     ev->next = NULL;
131     ev->prev = NULL;
132 }
133
134
135 static void removeWatch(struct ril_event * ev, int index)
136 {
137     watch_table[index] = NULL;
138     ev->index = -1;
139
140     FD_CLR(ev->fd, &readFds);
141
142     if (ev->fd+1 == nfds) {
143         int n = 0;
144
145         for (int i = 0; i < MAX_FD_EVENTS; i++) {
146             struct ril_event * rev = watch_table[i];
147
148             if ((rev != NULL) && (rev->fd > n)) {
149                 n = rev->fd;
150             }
151         }
152         nfds = n + 1; 
153         dlog("~~~~ nfds = %d ~~~~", nfds);
154     }
155 }
156
157 static void processTimeouts()
158 {
159     dlog("~~~~ +processTimeouts ~~~~");
160     MUTEX_ACQUIRE();
161     struct timeval now;
162     struct ril_event * tev = timer_list.next;
163     struct ril_event * next;
164
165     getNow(&now);
166     // walk list, see if now >= ev->timeout for any events
167
168     dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
169     while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
170         // Timer expired
171         dlog("~~~~ firing timer ~~~~");
172         next = tev->next;
173         removeFromList(tev);
174         addToList(tev, &pending_list);
175         tev = next;
176     }
177     MUTEX_RELEASE();
178     dlog("~~~~ -processTimeouts ~~~~");
179 }
180
181 static void processReadReadies(fd_set * rfds, int n)
182 {
183     dlog("~~~~ +processReadReadies (%d) ~~~~", n);
184     MUTEX_ACQUIRE();
185
186     for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
187         struct ril_event * rev = watch_table[i];
188         if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
189             addToList(rev, &pending_list);
190             if (rev->persist == false) {
191                 removeWatch(rev, i);
192             }
193             n--;
194         }
195     }
196
197     MUTEX_RELEASE();
198     dlog("~~~~ -processReadReadies (%d) ~~~~", n);
199 }
200
201 static void firePending()
202 {
203     dlog("~~~~ +firePending ~~~~");
204     struct ril_event * ev = pending_list.next;
205     while (ev != &pending_list) {
206         struct ril_event * next = ev->next;
207         removeFromList(ev);
208         ev->func(ev->fd, 0, ev->param); 
209         ev = next;
210     }
211     dlog("~~~~ -firePending ~~~~");
212 }
213
214 static int calcNextTimeout(struct timeval * tv)
215 {
216     struct ril_event * tev = timer_list.next;
217     struct timeval now;
218
219     getNow(&now);
220
221     // Sorted list, so calc based on first node
222     if (tev == &timer_list) {
223         // no pending timers
224         return -1;
225     }
226
227     dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
228     dlog("~~~~ next = %ds + %dus ~~~~",
229             (int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec);
230     if (timercmp(&tev->timeout, &now, >)) {
231         timersub(&tev->timeout, &now, tv);
232     } else {
233         // timer already expired.
234         tv->tv_sec = tv->tv_usec = 0;
235     }
236     return 0;
237 }
238
239 // Initialize internal data structs
240 void ril_event_init()
241 {
242     MUTEX_INIT();
243
244     FD_ZERO(&readFds);
245     init_list(&timer_list);
246     init_list(&pending_list);
247     memset(watch_table, 0, sizeof(watch_table));
248 }
249
250 // Initialize an event
251 void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param)
252 {
253     dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev);
254     memset(ev, 0, sizeof(struct ril_event));
255     ev->fd = fd;
256     ev->index = -1;
257     ev->persist = persist;
258     ev->func = func;
259     ev->param = param;
260     fcntl(fd, F_SETFL, O_NONBLOCK);
261 }
262
263 // Add event to watch list
264 void ril_event_add(struct ril_event * ev)
265 {
266     dlog("~~~~ +ril_event_add ~~~~");
267     MUTEX_ACQUIRE();
268     for (int i = 0; i < MAX_FD_EVENTS; i++) {
269         if (watch_table[i] == NULL) {
270             watch_table[i] = ev;
271             ev->index = i;
272             dlog("~~~~ added at %d ~~~~", i);
273             dump_event(ev);
274             FD_SET(ev->fd, &readFds);
275             if (ev->fd >= nfds) nfds = ev->fd+1;
276             dlog("~~~~ nfds = %d ~~~~", nfds);
277             break;
278         } 
279     }
280     MUTEX_RELEASE();
281     dlog("~~~~ -ril_event_add ~~~~");
282 }
283
284 // Add timer event
285 void ril_timer_add(struct ril_event * ev, struct timeval * tv)
286 {
287     dlog("~~~~ +ril_timer_add ~~~~");
288     MUTEX_ACQUIRE();
289
290     struct ril_event * list;
291     if (tv != NULL) {
292         // add to timer list
293         list = timer_list.next;
294         ev->fd = -1; // make sure fd is invalid
295
296         struct timeval now;
297         getNow(&now);
298         timeradd(&now, tv, &ev->timeout);
299
300         // keep list sorted
301         while (timercmp(&list->timeout, &ev->timeout, < )
302                 && (list != &timer_list)) {
303             list = list->next;
304         }
305         // list now points to the first event older than ev
306         addToList(ev, list);
307     } 
308
309     MUTEX_RELEASE();
310     dlog("~~~~ -ril_timer_add ~~~~");
311 }
312
313 // Remove event from watch or timer list
314 void ril_event_del(struct ril_event * ev)
315 {
316     dlog("~~~~ +ril_event_del ~~~~");
317     MUTEX_ACQUIRE();
318
319     if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) {
320         return;
321     }
322
323     removeWatch(ev, ev->index);
324
325     MUTEX_RELEASE();
326     dlog("~~~~ -ril_event_del ~~~~");
327 }
328
329 void ril_event_loop()
330 {
331     int n;
332     fd_set rfds;
333     struct timeval tv;
334     struct timeval * ptv;
335
336
337     for (;;) {
338
339         // make local copy of read fd_set
340         memcpy(&rfds, &readFds, sizeof(fd_set));
341         if (-1 == calcNextTimeout(&tv)) {
342             // no pending timers; block indefinitely
343             dlog("~~~~ no timers; blocking indefinitely ~~~~");
344             ptv = NULL;
345         } else {
346             dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
347             ptv = &tv;
348         }
349         n = select(nfds, &rfds, NULL, NULL, ptv);
350         dlog("~~~~ %d events fired ~~~~", n);
351         if (n < 0) {
352             if (errno == EINTR) continue;
353
354             LOGE("ril_event: select error (%d)", errno);
355             // bail?
356             return;
357         }
358
359         // Check for timeouts
360         processTimeouts();
361         // Check for read-ready
362         processReadReadies(&rfds, n);
363         // Fire away
364         firePending();
365     }
366 }