Home | History | Annotate | Download | only in libril
      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     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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
    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
    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
    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
    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 
    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