浅析Android的RILD服务进程的消息循环(2)

初始化过程还是要从rild的main入口开始分析起,位于文件hardware/ril/rild/rild.c。简单期间,只介绍本文相关的部分。main()函数会调用函数RIL_register(),然后会调用RIL_startEventLoop()。RIL_startEventLoop()中会创建线程eventLoop,这个实际上就是rild的消息循环所在的线程。

ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);  

        eventLoop()首先会进行初始化:

ril_event_init();  

        然后,会通过pipe()函数创建管道。pipe()函数会创建一对文件描述符,一个用于读,另一个用于写。都被记录在全局变量中。它实际上是用来发送定时消息的,后面会介绍。

ret = pipe(filedes);   // ......    s_fdWakeupRead = filedes[0]; // 消息循环中侦听    s_fdWakeupWrite = filedes[1]; // 用于通知消息循环定义消息已发送  

        最后一步就是进入消息循环:

// Only returns on error    ril_event_loop();  

ril_event_loop()

ril_event_loop()中,每次循环都主要做三件事:
        1.初始化。主要是获取要等待的描述符,以及获取超时信息,以便能够及时处理定时消息。
        2.等待。等待socket客户端有新的消息,或一定的时间间隔,之后处理定时消息。
        3.依次处理三种类型的消息。
        下面分别叙述之。先是获取要等待的描述符,这里为什么要这么做呢?我的理解是在添加新的消息时,有可能会修改全局的描述符列表。也就是说,全局的描述符列表有可能在本次循环的处理过程中发生变化。

// make local copy of read fd_set    memcpy(&rfds, &readFds, sizeof(fd_set));  

        接下来,就是计算select()函数的超时参数。select的最后一个参数代表超时。若为NULL,则select死等;若为0,则select立即返回;若大于0,则限制了select最长的等待时间。

if (-1 == calcNextTimeout(&tv)) { // 获取超时参数,若失败则返回-1。        // 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;   }  

        calcNextTimeout()函数先是判断超时消息的列表是否为空,为空则返回-1;

// Sorted list, so calc based on first node    if (tev == &timer_list) {       // no pending timers        return -1;   }  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwzzjg.html