在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;
}