RIL层源码分析w(2)

2019-09-01 20:03

//初始化Event链表 void ril_event_init() //初始化一个Event

void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param) //把一个Event添加到watch_table中 void ril_event_add(struct ril_event * ev) //把一个Event添加到timer_list中

void ril_timer_add(struct ril_event * ev, struct timeval * tv) //把一个Event从watch_table中删除 void ril_event_del(struct ril_event * ev) //主循环

void ril_event_loop()

通过上面的主要函数我们可以大致推测出,管理Event的过程应该是生成相应的Event节点,然后将Event添加到链表,处理Event之后就需要把当前的Event从链表中删除。而且我们看出,Event管理中应该存在多个链表,那么究竟有哪些链表在运行呢?

RIL的Event管理体系中存在3个链表结构:watch_table,timer_list,pending_list,并使用了一个设备句柄池readFDS,把所有的Socket管道的文件句柄保存起来。而管理的过程可以归纳为以下6点: 1、可以将一个Event添加到watch_table或者timer_list中;

2、如果Event是添加到watch_table中,需要把当前Event的fd(事件设备句柄)添加到readFDS中; 3、如果Event是添加到timer_list中,不需要把当前Event的fd(事件设备句柄)添加到readFDS中,而且当前Event的fd值是无效的;

4、在循环检测过程中,如果发现watch_table中有Event就会把当前Event添加到pending_list中,如果当前Event的persist属性为false,说明不需要保留当前节点,就把当前的Event从watch_table中删除;如果persist为true,说明需要保留,就不需要从watch_table中删除当前节点。

5、在循环检测过程中,如果发现timer_list中的Event超时时,把当前Event移动到pending_list中,同时删除timer_list中的节点。

6、在循环检测的过程中,等watch_table和timer_list处理完毕后,就去pending_list中执行里面的Event所指向的func。

有了以上的认识,我们来看一下具体的流程。从Event的创建入口开始: @ril.cpp

RIL_startEventLoop(void) {

//打开Event线程,并调用eventLoop进入循环

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

然后我们进入到线程的入口函数中查看: eventLoop(void *param) { //Event的初始化 ril_event_init(); //创建一个Event

ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL); //将上面创建的Event加入到watch_table中,这里起到唤醒LoopEvent的作用,后面详细说明 rilEventAddWakeup (&s_wakeupfd_event); //进入loop循环 ril_event_loop(); }

可以看出,Event的搭建由两个步骤:1、初始化链表;2、进入loop循环。我们分别看一下两个过程:

1.2、EventLoop的搭建过程

1.2.1、Event初始化过程

其实就是ril_event_init过程。

@ril_event.cpp void ril_event_init() {

FD_ZERO(&readFds); init_list(&timer_list); init_list(&pending_list);

memset(watch_table, 0, sizeof(watch_table)); }

初始化的过程很简单,就是对loop框架中涉及到的文件句柄集和3个重要链表的初始化。 1.2.2、Event循环的过程 ril_event.cpp

void ril_event_loop() {

//死循环检测Event消息 for (;;) {

//计算下一次超时时间 if (-1 == calcNextTimeout(&tv)) { //NULL说明select是阻塞模式 ptv = NULL; } else {

//非空说明在超时时间内是阻塞模式 ptv = &tv; }

//用select去扫描readFds中的所有管道集合,检测RILJ是否有新数据出现。 n = select(nfds, &rfds, NULL, NULL, ptv);

//检查超时事件,如果超时,将Event放入pending_list中 processTimeouts();

//检查watch_table,将Event加入pending_list中 processReadReadies(&rfds, n); //执行pending_list中的Event firePending(); } }

上面的for循环可以清晰的看到,当RILJ发送数据后,在EventLoop中会依次被timer_list、watch_table、pending_list处理;接着来分别看一下3个表的处理流程: a、timer_list表

static void processTimeouts() {

//如果timer_list中某个事件已经超时

while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { //从timer_list中删除 removeFromList(tev); //添加到pending_list中 addToList(tev, &pending_list); } }

b、watch_table表

static void processReadReadies(fd_set * rfds, int n) {

for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { //添加到pending_list addToList(rev, &pending_list); if (rev->persist == false) {

//如果persist为false才去删除当前Event removeWatch(rev, i); } } }

c、pending_list表 static void firePending() {

while (ev != &pending_list) { //删除当前节点

removeFromList(ev);

//执行其func并把参数传递进去 ev->func(ev->fd, 0, ev->param); } }

上面的循环过程说明,eventLoop的是通过在内部循环中用Linux中的select方法检测readFds中所有的文件句柄(或者说管道),如果发现有新的数据进来,就去遍历watch_table和timer_list表,把需要处理的eventLoop加入到pending_list中,然后进入pending_list中去执行每个Event的func。

下面是EventLoop循环的流程图:

上面提到了循环接收数据的过程,那么具体的处理这些命令的过程是怎样的呢?这个过程等我们了解了reference的过程后再去讲解。

再次提醒一下,这里侦测到的数据主要是RILJ发送下来的命令(而不是Modem侧上来的AT命令)。

二、reference库的加载

在这一步中,RIL需要加载一个AT相关的***ril.so的动态链接库。之所以使用库的形式,就是考虑到每个厂商使用的Modem不同,我们没法用统一的接口去向底层负责,因此使用库的形式。这样一来,不同的Modem厂


RIL层源码分析w(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:2018年湖南省政府采购评审专家库培训测评-多选题部分答案

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: