在ril.cpp中定义了3个队列,分别是watch_table,timer_list和pending_list,他们里面都存放的是ril_event结构,他们的主要作用如下:
1. watch_table是一个指针数组,它里面存放的是靠多路复用来驱动的ril_event,起作用的是fd参数,使用ril_event_add朝里面添加event,使用ril_event_del来删除里面的event。
2. timer_list里面存放的是靠timer来驱动的event列表,使用ril_timer_add朝里面添加event。只有一个函数会调用ril_timer_add把event添加进来,那就是internalRequestTimedCallback这个函数,该函数又由RIL_requestTimedCallback来调用。在ril_event_loop里面,select多路复用的timeout时间就是当前timer_list里面最近一个将要超时的event的超时时间。
3. pending_list,是一个存储即将被执行的ril_event的列表(所谓即将执行,就是调用该event的callback函数),下面两个情况会把event添加到该列表:a: watch_table里面某一个event的fd里面有数据可读; b. timer_list里面某一个event已经timeout了。
void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { /* make local copy of read fd_set readFds里面的fd都是watch_table里面的event的fd */ memcpy(&rfds, &readFds, sizeof(fd_set)); /*计算select需要等待的时间,这个值是从timer_list里面的event计算出来的*/ if (-1 == calcNextTimeout(&tv)) { // no pending timers; block indefinitely dlog("~~~~ no timers; blocking indefinitely ~~~~"); ptv = NULL; } else { dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); ptv = &tv; } /*多路复用,等待有数据可读,或者超时*/ n = select(nfds, &rfds, NULL, NULL, ptv); dlog("~~~~ %d events fired ~~~~", n); if (n < 0) { if (errno == EINTR) continue; LOGE("ril_event: select error (%d)", errno); // bail? return; } /* Check for timeouts timer_event里面有event超时了,需要调用超时event的callback来执行相关操作,把这些event加入到pending_list里面*/ processTimeouts(); /* Check for read-ready 处理watch_table里面的有数据可读的fd所在的event,将其放入到timer_list里面*/ processReadReadies(&rfds, n); /* Fire away 执行pending_list里面的event*/ firePending(); } }
/* 取得最近马上要超时的一个event的超时时间离现在的微秒数,因为在timer_event列表 里面的event都是按照时间排序排列好的,所以我们只判断最前面一个event就行了。 返回的这个值就是ril_event_loop函数里面select的超时时间 */ static int calcNextTimeout(struct timeval * tv) { struct ril_event * tev = timer_list.next; struct timeval now; getNow(&now); // Sorted list, so calc based on first node if (tev == &timer_list) { // no pending timers return -1; } dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); dlog("~~~~ next = %ds + %dus ~~~~", (int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec); if (timercmp(&tev->timeout, &now, >)) { timersub(&tev->timeout, &now, tv); } else { // timer already expired. tv->tv_sec = tv->tv_usec = 0; } return 0; }