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