分享

Android RIL源码研究笔记 のril_event

 android之情殇 2013-07-24

Android源码目录hardware/ril/libril目录中总共包含5个C/CPP文件,它们分别是ril_commands.h、ril_unsol_commands.h、ril_event.h、ril_event.cpp和ril.cpp。这篇文章主要分析ril_event的相关代码。
   ril_event主要处理电话模块涉及的端口、modem等产生的事件,并将多个事件按时间顺序进行组织,并保存在事件队别中,主要使用了三个队列,分别是:watch_table[],timer_list和pending_list。代码是以C语言方式实现的,先来看头文件ril_event.h:
 
[cpp]
// 每次监视的最大的文件描述符句柄数,可以根据需要自行修改 
#define MAX_FD_EVENTS 8 
 
// ril_event的回调函数 
typedef void (*ril_event_cb)(int fd, short events, void *userdata); 
 
struct ril_event { 
    // 用于将ril_event串成双向链表的前向指针和后向指针 
    struct ril_event *next; 
    struct ril_event *prev; 
     
    //ril事件相关的文件描述符句柄(可以是文件、管道、Socket等) 
    int fd; 
     
    //这个事件在监控列表中的索引 
    int index; 
     
    //当一个事件处理完后(即从watch_table移到pending_list中等待处理), 
    //persist参数决定这个事件是否一直存在于监控列表watch_table[]中 
    bool persist; 
     
    //事件的超时时间 
    struct timeval timeout; 
     
    //回调函数及其传入的参数 
    ril_event_cb func; 
    void *param; 
}; 
 
//以下是ril事件相关的一些操作函数 
// 初始化内部数据结构 
void ril_event_init(); 
 
// 初始化一个ril事件 
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param); 
 
// 将事件添加到监控列表watch_table[]中 
void ril_event_add(struct ril_event * ev); 
 
// 增加一个timer事件到timer_list链表中 
void ril_timer_add(struct ril_event * ev, struct timeval * tv); 
 
// 将指定的事件从监控列表watch_table[]中移除 
void ril_event_del(struct ril_event * ev); 
 
// 事件循环 
void ril_event_loop(); 

接着分析ril_event .cpp文件:
 
[cpp]
#define LOG_TAG "RILC" 
 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <fcntl.h> 
#include <utils/Log.h> 
#include <ril_event.h> 
#include <string.h> 
#include <sys/time.h> 
#include <time.h> 
 
#include <pthread.h> 
 
// 使用互斥量mutex进行线程同步,可参见《Linux程序设计》相关章节 
static pthread_mutex_t listMutex; 
#define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex) 
#define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex) 
#define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL) 
#define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex) 
 
// 两个timeval类型的值相加 
#ifndef timeradd 
#define timeradd(tvp, uvp, vvp)                     \ 
    do {                                \ 
        (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;     \ 
        (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \ 
        if ((vvp)->tv_usec >= 1000000) {          \ 
            (vvp)->tv_sec++;             \ 
            (vvp)->tv_usec -= 1000000;           \ 
        }                           \ 
    } while (0) 
#endif 
 
// 两个timeval类型的值进行比较 
#ifndef timercmp 
#define timercmp(a, b, op)               \ 
        ((a)->tv_sec == (b)->tv_sec      \ 
        (a)->tv_usec op (b)->tv_usec   \ 
        : (a)->tv_sec op (b)->tv_sec) 
#endif 
 
// 两个timeval类型的值相减 
#ifndef timersub 
#define timersub(a, b, res)                           \ 
    do {                                              \ 
        (res)->tv_sec = (a)->tv_sec - (b)->tv_sec;    \ 
        (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 
        if ((res)->tv_usec < 0) {                     \ 
            (res)->tv_usec += 1000000;                \ 
            (res)->tv_sec -= 1;                       \ 
        }                                             \ 
    } while(0); 
#endi 
 
// 保存Rild中所有设备文件句柄,便于使用select函数完成事件的监听 
static fd_set readFds; 
// 记录readFds中最大fd值+1 
static int nfds = 0; 
 
// 为了统一管理ril事件,Android提供如下三个队列: 
// 监控事件列表,需要检测的事件都需要先存入该列表中 
static struct ril_event * watch_table[MAX_FD_EVENTS]; 
 
// timer事件队列,事件超时后即移入pending_list队列中 
static struct ril_event timer_list; 
 
// 待处理的事件队列,即事件已经触发,后续需要调用事件的回调函数 
static struct ril_event pending_list; 
 
#define DEBUG 0 
 
#if DEBUG 
#define dlog(x...) LOGD( x ) 
static void dump_event(struct ril_event * ev) 

    dlog("~~~~ Event %x ~~~~", (unsigned int)ev); 
    dlog("     next    = %x", (unsigned int)ev->next); 
    dlog("     prev    = %x", (unsigned int)ev->prev); 
    dlog("     fd      = %d", ev->fd); 
    dlog("     pers    = %d", ev->persist); 
    dlog("     timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec); 
    dlog("     func    = %x", (unsigned int)ev->func); 
    dlog("     param   = %x", (unsigned int)ev->param); 
    dlog("~~~~~~~~~~~~~~~~~~"); 

#else 
#define dlog(x...) do {} while(0) 
#define dump_event(x) do {} while(0) 
#endif 
 
// 获取此刻timeval值 
static void getNow(struct timeval * tv) 

#ifdef HAVE_POSIX_CLOCKS 
    struct timespec ts; 
    clock_gettime(CLOCK_MONOTONIC, &ts); 
    tv->tv_sec = ts.tv_sec; 
    tv->tv_usec = ts.tv_nsec/1000; 
#else 
    gettimeofday(tv, NULL); 
#endif 

 
// 初始化指定的ril_event链表 
static void init_list(struct ril_event * list) 

    memset(list, 0, sizeof(struct ril_event)); 
    list->next = list; 
    list->prev = list; 
    list->fd = -1; 

 
// 增加一个ril_event事件到ril_event队列头 
static void addToList(struct ril_event * ev, struct ril_event * list) 

    ev->next = list; 
    ev->prev = list->prev; 
    ev->prev->next = ev; 
    list->prev = ev; 
    dump_event(ev); 

 
// 从ril_event队列中移除指定的ril_event 
static void removeFromList(struct ril_event * ev) 

    dlog("~~~~ Removing event ~~~~"); 
    dump_event(ev); 
 
    ev->next->prev = ev->prev; 
    ev->prev->next = ev->next; 
    ev->next = NULL; 
    ev->prev = NULL; 

 
// 从watch_table[]中移除指定索引的事件 
static void removeWatch(struct ril_event * ev, int index) 

    // 索引index对应的事件置为空,同时事件ev的索引设为无效值-1 
    watch_table[index] = NULL; 
    ev->index = -1; 
 
    // 将该事件对应的文件描述符句柄从readFds中清除 
    FD_CLR(ev->fd, &readFds); 
 
    if (ev->fd+1 == nfds) { 
        int n = 0; 
 
        for (int i = 0; i < MAX_FD_EVENTS; i++) { 
            struct ril_event * rev = watch_table[i]; 
 
            if ((rev != NULL) && (rev->fd > n)) { 
                n = rev->fd; 
            } 
        } 
        nfds = n + 1; 
        dlog("~~~~ nfds = %d ~~~~", nfds); 
    } 

 
// 遍历timer_list队列中的事件,当事件超时时间到时 
// 将事件移除,并添加到pending_list队列中 
static void processTimeouts() 

    dlog("~~~~ +processTimeouts ~~~~"); 
    MUTEX_ACQUIRE(); 
    struct timeval now; 
    struct ril_event * tev = timer_list.next; 
    struct ril_event * next; 
 
    getNow(&now); 
    // walk list, see if now >= ev->timeout for any events 
 
    dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); 
    while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { 
        // Timer expired 
        dlog("~~~~ firing timer ~~~~"); 
        next = tev->next; 
        removeFromList(tev); 
        addToList(tev, &pending_list); 
        tev = next; 
    } 
    MUTEX_RELEASE(); 
    dlog("~~~~ -processTimeouts ~~~~"); 

 
// 遍历监控列表watch_table[]中的事件,并将有数据可读的事件 
// 添加到pending_list链表中,同时如果事件的persist不为true 
// 则将该事件从watch_table[]中移除 
static void processReadReadies(fd_set * rfds, int n) 

    dlog("~~~~ +processReadReadies (%d) ~~~~", n); 
    MUTEX_ACQUIRE(); 
 
    for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { 
        struct ril_event * rev = watch_table[i]; 
        if (rev != NULL && FD_ISSET(rev->fd, rfds)) { 
            addToList(rev, &pending_list); 
            if (rev->persist == false) { 
                removeWatch(rev, i); 
            } 
            n--; 
        } 
    } 
 
    MUTEX_RELEASE(); 
    dlog("~~~~ -processReadReadies (%d) ~~~~", n); 

 
// 依次调用待处理队列pending_list中的事件的回调函数 
static void firePending() 

    dlog("~~~~ +firePending ~~~~"); 
    struct ril_event * ev = pending_list.next; 
    while (ev != &pending_list) { 
        struct ril_event * next = ev->next; 
        removeFromList(ev); 
        ev->func(ev->fd, 0, ev->param); 
        ev = next; 
    } 
    dlog("~~~~ -firePending ~~~~"); 

 
// 计算timer_list链表中下一个事件的新的超时时间 
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; 

 
// 初始化内部数据结构(互斥量、FD集合、三个事件队列) 
void ril_event_init() 

    MUTEX_INIT(); 
 
    FD_ZERO(&readFds); 
    init_list(&timer_list); 
    init_list(&pending_list); 
    memset(watch_table, 0, sizeof(watch_table)); 

 
// 初始化一个ril事件 
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param) 

    dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev); 
    memset(ev, 0, sizeof(struct ril_event)); 
    ev->fd = fd; 
    ev->index = -1; 
    ev->persist = persist; 
    ev->func = func; 
    ev->param = param; 
     
    //linux的文件上锁函数,给文件描述符fd上非阻塞的文件锁 
    fcntl(fd, F_SETFL, O_NONBLOCK); 

 
// 将事件添加到监控列表watch_table[]中 
void ril_event_add(struct ril_event * ev) 

    dlog("~~~~ +ril_event_add ~~~~"); 
    MUTEX_ACQUIRE(); 
    for (int i = 0; i < MAX_FD_EVENTS; i++) { 
        if (watch_table[i] == NULL) { 
            watch_table[i] = ev; 
            ev->index = i; 
            dlog("~~~~ added at %d ~~~~", i); 
            dump_event(ev); 
            FD_SET(ev->fd, &readFds); 
            if (ev->fd >= nfds) nfds = ev->fd+1; 
            dlog("~~~~ nfds = %d ~~~~", nfds); 
            break; 
        } 
    } 
    MUTEX_RELEASE(); 
    dlog("~~~~ -ril_event_add ~~~~"); 

 
// 增加一个timer事件到timer_list链表中 
void ril_timer_add(struct ril_event * ev, struct timeval * tv) 

    dlog("~~~~ +ril_timer_add ~~~~"); 
    MUTEX_ACQUIRE(); 
 
    struct ril_event * list; 
    if (tv != NULL) { 
        // add to timer list 
        list = timer_list.next; 
        ev->fd = -1; // make sure fd is invalid 
 
        struct timeval now; 
        getNow(&now); 
        timeradd(&now, tv, &ev->timeout); 
 
        // 根据timeout值从小到大在链表中排序 
        while (timercmp(&list->timeout, &ev->timeout, < ) 
                && (list != &timer_list)) { 
            list = list->next; 
        } 
        // 循环结束后,list指向链表中第一个timeout值大于ev的事件 
    // 将新加入的事件ev加到list此刻指向的事件前面 
        addToList(ev, list); 
    } 
 
    MUTEX_RELEASE(); 
    dlog("~~~~ -ril_timer_add ~~~~"); 

 
// 将事件从watch_table[]中移除 
void ril_event_del(struct ril_event * ev) 

    dlog("~~~~ +ril_event_del ~~~~"); 
    MUTEX_ACQUIRE(); 
 
    if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) { 
        MUTEX_RELEASE(); 
        return; 
    } 
 
    removeWatch(ev, ev->index); 
 
    MUTEX_RELEASE(); 
    dlog("~~~~ -ril_event_del ~~~~"); 

 
#if DEBUG 
// 打印监控列表中可用的事件 
static void printReadies(fd_set * rfds) 

    for (int i = 0; (i < MAX_FD_EVENTS); i++) { 
        struct ril_event * rev = watch_table[i]; 
        if (rev != NULL && FD_ISSET(rev->fd, rfds)) { 
          dlog("DON: fd=%d is ready", rev->fd); 
        } 
    } 

#else 
#define printReadies(rfds) do {} while(0) 
#endif 
 
void ril_event_loop() 

    int n; 
    fd_set rfds; 
    struct timeval tv; 
    struct timeval * ptv; 
 
    for (;;) { 
        // make local copy of read fd_set 
        memcpy(&rfds, &readFds, sizeof(fd_set)); 
    // 根据timer_list来计算select函数的等待时间 
    // timer_list之前已按事件的超时时间排好序了 
        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; 
        } 
        printReadies(&rfds); 
    // 使用select函数实现多路IO复用 
        n = select(nfds, &rfds, NULL, NULL, ptv); 
        printReadies(&rfds); 
        dlog("~~~~ %d events fired ~~~~", n); 
        if (n < 0) { 
            if (errno == EINTR) continue; 
 
            LOGE("ril_event: select error (%d)", errno); 
            // bail? 
            return; 
        } 
 
        // Check for timeouts 
        processTimeouts(); 
        // Check for read-ready 
        processReadReadies(&rfds, n); 
        // Fire away 
        firePending(); 
    } 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多