• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 )
dump_event(struct ril_event * ev)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 
getNow(struct timeval * tv)96 static 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 
init_list(struct ril_event * list)104 static 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 
addToList(struct ril_event * ev,struct ril_event * list)112 static 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 
removeFromList(struct ril_event * ev)121 static 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 
removeWatch(struct ril_event * ev,int index)134 static 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 
processTimeouts()158 static 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 
processReadReadies(fd_set * rfds,int n)182 static 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 
firePending()202 static 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 
calcNextTimeout(struct timeval * tv)215 static 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
ril_event_init()241 void 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
ril_event_set(struct ril_event * ev,int fd,bool persist,ril_event_cb func,void * param)252 void 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
ril_event_add(struct ril_event * ev)265 void 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
ril_timer_add(struct ril_event * ev,struct timeval * tv)286 void 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
ril_event_del(struct ril_event * ev)315 void 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
printReadies(fd_set * rfds)332 static 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 
ril_event_loop()345 void 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