OSDN Git Service

Restart, cleanup or retry inactve connections.
[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 #ifndef timeradd
38 #define timeradd(tvp, uvp, vvp)                                         \
39         do {                                                            \
40                 (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;          \
41                 (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
42                 if ((vvp)->tv_usec >= 1000000) {                        \
43                         (vvp)->tv_sec++;                                \
44                         (vvp)->tv_usec -= 1000000;                      \
45                 }                                                       \
46         } while (0)
47 #endif
48
49 #ifndef timercmp
50 #define timercmp(a, b, op)               \
51         ((a)->tv_sec == (b)->tv_sec      \
52         ? (a)->tv_usec op (b)->tv_usec   \
53         : (a)->tv_sec op (b)->tv_sec)
54 #endif
55
56 #ifndef timersub
57 #define timersub(a, b, res)                           \
58     do {                                              \
59         (res)->tv_sec = (a)->tv_sec - (b)->tv_sec;    \
60         (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
61         if ((res)->tv_usec < 0) {                     \
62             (res)->tv_usec += 1000000;                \
63             (res)->tv_sec -= 1;                       \
64         }                                             \
65     } while(0);
66 #endif
67
68 static fd_set readFds;
69 static int nfds = 0;
70
71 static struct ril_event * watch_table[MAX_FD_EVENTS];
72 static struct ril_event timer_list;
73 static struct ril_event pending_list;
74
75 #define DEBUG 0
76
77 #if DEBUG
78 #define dlog(x...) RLOGD( x )
79 static void dump_event(struct ril_event * ev)
80 {
81     dlog("~~~~ Event %x ~~~~", (unsigned int)ev);
82     dlog("     next    = %x", (unsigned int)ev->next);
83     dlog("     prev    = %x", (unsigned int)ev->prev);
84     dlog("     fd      = %d", ev->fd);
85     dlog("     pers    = %d", ev->persist);
86     dlog("     timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec);
87     dlog("     func    = %x", (unsigned int)ev->func);
88     dlog("     param   = %x", (unsigned int)ev->param);
89     dlog("~~~~~~~~~~~~~~~~~~");
90 }
91 #else
92 #define dlog(x...) do {} while(0)
93 #define dump_event(x) do {} while(0)
94 #endif
95
96 static void getNow(struct timeval * tv)
97 {
98 #ifdef HAVE_POSIX_CLOCKS
99     struct timespec ts;
100     clock_gettime(CLOCK_MONOTONIC, &ts);
101     tv->tv_sec = ts.tv_sec;
102     tv->tv_usec = ts.tv_nsec/1000;
103 #else
104     gettimeofday(tv, NULL);
105 #endif
106 }
107
108 static void init_list(struct ril_event * list)
109 {
110     memset(list, 0, sizeof(struct ril_event));
111     list->next = list;
112     list->prev = list;
113     list->fd = -1;
114 }
115
116 static void addToList(struct ril_event * ev, struct ril_event * list)
117 {
118     ev->next = list;
119     ev->prev = list->prev;
120     ev->prev->next = ev;
121     list->prev = ev;
122     dump_event(ev);
123 }
124
125 static void removeFromList(struct ril_event * ev)
126 {
127     dlog("~~~~ Removing event ~~~~");
128     dump_event(ev);
129
130     ev->next->prev = ev->prev;
131     ev->prev->next = ev->next;
132     ev->next = NULL;
133     ev->prev = NULL;
134 }
135
136
137 static void removeWatch(struct ril_event * ev, int index)
138 {
139     watch_table[index] = NULL;
140     ev->index = -1;
141
142     FD_CLR(ev->fd, &readFds);
143
144     if (ev->fd+1 == nfds) {
145         int n = 0;
146
147         for (int i = 0; i < MAX_FD_EVENTS; i++) {
148             struct ril_event * rev = watch_table[i];
149
150             if ((rev != NULL) && (rev->fd > n)) {
151                 n = rev->fd;
152             }
153         }
154         nfds = n + 1;
155         dlog("~~~~ nfds = %d ~~~~", nfds);
156     }
157 }
158
159 static void processTimeouts()
160 {
161     dlog("~~~~ +processTimeouts ~~~~");
162     MUTEX_ACQUIRE();
163     struct timeval now;
164     struct ril_event * tev = timer_list.next;
165     struct ril_event * next;
166
167     getNow(&now);
168     // walk list, see if now >= ev->timeout for any events
169
170     dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
171     while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
172         // Timer expired
173         dlog("~~~~ firing timer ~~~~");
174         next = tev->next;
175         removeFromList(tev);
176         addToList(tev, &pending_list);
177         tev = next;
178     }
179     MUTEX_RELEASE();
180     dlog("~~~~ -processTimeouts ~~~~");
181 }
182
183 static void processReadReadies(fd_set * rfds, int n)
184 {
185     dlog("~~~~ +processReadReadies (%d) ~~~~", n);
186     MUTEX_ACQUIRE();
187
188     for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
189         struct ril_event * rev = watch_table[i];
190         if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
191             addToList(rev, &pending_list);
192             if (rev->persist == false) {
193                 removeWatch(rev, i);
194             }
195             n--;
196         }
197     }
198
199     MUTEX_RELEASE();
200     dlog("~~~~ -processReadReadies (%d) ~~~~", n);
201 }
202
203 static void firePending()
204 {
205     dlog("~~~~ +firePending ~~~~");
206     struct ril_event * ev = pending_list.next;
207     while (ev != &pending_list) {
208         struct ril_event * next = ev->next;
209         removeFromList(ev);
210         ev->func(ev->fd, 0, ev->param);
211         ev = next;
212     }
213     dlog("~~~~ -firePending ~~~~");
214 }
215
216 static int calcNextTimeout(struct timeval * tv)
217 {
218     struct ril_event * tev = timer_list.next;
219     struct timeval now;
220
221     getNow(&now);
222
223     // Sorted list, so calc based on first node
224     if (tev == &timer_list) {
225         // no pending timers
226         return -1;
227     }
228
229     dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
230     dlog("~~~~ next = %ds + %dus ~~~~",
231             (int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec);
232     if (timercmp(&tev->timeout, &now, >)) {
233         timersub(&tev->timeout, &now, tv);
234     } else {
235         // timer already expired.
236         tv->tv_sec = tv->tv_usec = 0;
237     }
238     return 0;
239 }
240
241 // Initialize internal data structs
242 void ril_event_init()
243 {
244     MUTEX_INIT();
245
246     FD_ZERO(&readFds);
247     init_list(&timer_list);
248     init_list(&pending_list);
249     memset(watch_table, 0, sizeof(watch_table));
250 }
251
252 // Initialize an event
253 void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param)
254 {
255     dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev);
256     memset(ev, 0, sizeof(struct ril_event));
257     ev->fd = fd;
258     ev->index = -1;
259     ev->persist = persist;
260     ev->func = func;
261     ev->param = param;
262     fcntl(fd, F_SETFL, O_NONBLOCK);
263 }
264
265 // Add event to watch list
266 void ril_event_add(struct ril_event * ev)
267 {
268     dlog("~~~~ +ril_event_add ~~~~");
269     MUTEX_ACQUIRE();
270     for (int i = 0; i < MAX_FD_EVENTS; i++) {
271         if (watch_table[i] == NULL) {
272             watch_table[i] = ev;
273             ev->index = i;
274             dlog("~~~~ added at %d ~~~~", i);
275             dump_event(ev);
276             FD_SET(ev->fd, &readFds);
277             if (ev->fd >= nfds) nfds = ev->fd+1;
278             dlog("~~~~ nfds = %d ~~~~", nfds);
279             break;
280         }
281     }
282     MUTEX_RELEASE();
283     dlog("~~~~ -ril_event_add ~~~~");
284 }
285
286 // Add timer event
287 void ril_timer_add(struct ril_event * ev, struct timeval * tv)
288 {
289     dlog("~~~~ +ril_timer_add ~~~~");
290     MUTEX_ACQUIRE();
291
292     struct ril_event * list;
293     if (tv != NULL) {
294         // add to timer list
295         list = timer_list.next;
296         ev->fd = -1; // make sure fd is invalid
297
298         struct timeval now;
299         getNow(&now);
300         timeradd(&now, tv, &ev->timeout);
301
302         // keep list sorted
303         while (timercmp(&list->timeout, &ev->timeout, < )
304                 && (list != &timer_list)) {
305             list = list->next;
306         }
307         // list now points to the first event older than ev
308         addToList(ev, list);
309     }
310
311     MUTEX_RELEASE();
312     dlog("~~~~ -ril_timer_add ~~~~");
313 }
314
315 // Remove event from watch or timer list
316 void ril_event_del(struct ril_event * ev)
317 {
318     dlog("~~~~ +ril_event_del ~~~~");
319     MUTEX_ACQUIRE();
320
321     if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) {
322         MUTEX_RELEASE();
323         return;
324     }
325
326     removeWatch(ev, ev->index);
327
328     MUTEX_RELEASE();
329     dlog("~~~~ -ril_event_del ~~~~");
330 }
331
332 #if DEBUG
333 static void printReadies(fd_set * rfds)
334 {
335     for (int i = 0; (i < MAX_FD_EVENTS); i++) {
336         struct ril_event * rev = watch_table[i];
337         if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
338           dlog("DON: fd=%d is ready", rev->fd);
339         }
340     }
341 }
342 #else
343 #define printReadies(rfds) do {} while(0)
344 #endif
345
346 void ril_event_loop()
347 {
348     int n;
349     fd_set rfds;
350     struct timeval tv;
351     struct timeval * ptv;
352
353
354     for (;;) {
355
356         // make local copy of read fd_set
357         memcpy(&rfds, &readFds, sizeof(fd_set));
358         if (-1 == calcNextTimeout(&tv)) {
359             // no pending timers; block indefinitely
360             dlog("~~~~ no timers; blocking indefinitely ~~~~");
361             ptv = NULL;
362         } else {
363             dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
364             ptv = &tv;
365         }
366         printReadies(&rfds);
367         n = select(nfds, &rfds, NULL, NULL, ptv);
368         printReadies(&rfds);
369         dlog("~~~~ %d events fired ~~~~", n);
370         if (n < 0) {
371             if (errno == EINTR) continue;
372
373             RLOGE("ril_event: select error (%d)", errno);
374             // bail?
375             return;
376         }
377
378         // Check for timeouts
379         processTimeouts();
380         // Check for read-ready
381         processReadReadies(&rfds, n);
382         // Fire away
383         firePending();
384     }
385 }