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