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