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