您的位置:首页 > 其它

intel dpdk api timer 详解启动和调度管理

2013-07-23 16:47 429 查看
声明:此文档只做学习交流使用,请勿用作其他商业用途
author:朝阳_tony
E-mail : linzhaolover@gmail.com
Create Date: 2013-7-23 14:19:54 Tuesday
Last Change: 2013-7-23 16:47:32 Tuesday

转载请注明出处:http://blog.csdn.net/linzhaolove

此文中源码可以去http://dpdk.org/dev 网页中下载;更多官方文档请访问http://dpdk.org

intel DPDK交流群希望大家加入互相学习,QQ群号:289784125

摘要

timer是dpdk的一个实现异步调度执行的库,主要有初始化,启动,调度管理,还有停止几个部分组成,由于其启动和调度管理部分比较难理解,所以将其单独拿出来讲;
如果你对整个模块的流程感兴趣,可以阅读我的文章 《timer 模块详解和测试》http://blog.csdn.net/linzhaolove/article/details/9410529
此文章主要以dpdk提供的实例代码 example/timer  为例来进行讲解

1、定时器启动

定时器的启动时调用了rte_timer_reset()函数实现;
我们详细介绍一下这个函数,此函数在dpdk/lib/librte_timer/rte_timer.c文件中定义;
uint64_t cur_time = rte_get_hpet_cycles();
在rte_timer_reset中首先会调用rte_get_hpet_cycles()获取当前hpet模块的cycles数,而定时器的时钟精准度也是依赖hpet模块;我在其他的博文中已经讲过hpet模块;
在rte_get_hpet_cycles()中,涉及到的 eal_hpet_msb变量,是在hpet_msb_inc() 线程函数中实时更新的;
if (type == PERIODICAL)
period = ticks;
else
period = 0;
 过类型判断你当前设置的周期性的定时器,还是单次运行定时器;
接下来调用一个更底层的函数__rte_timer_reset()对定时器进行配置;
/* wait that the timer is in correct status before update,
* and mark it as beeing configured */
ret = timer_set_config_state(tim, &prev_status);
首先要设置当前定时器的状态为 配置状态;
tim->period = period;
tim->expire = expire;
tim->f = fct;
tim->arg = arg;
然后配置其  周期,期望值,回调函数,以及给回调函数传递的参数;

timer_add(tim, tim_lcore, local_is_locked);
将定时器插入到对应的lcore 的pending列表中,
在了解timer_add()函数内部源码后了解到,插入列表时是按有序插入的,需要先查看第一个定时器,如果列表是空的,或者期望值小于第一定时器,就将其直接插入最前面,如果期望值大于第一个,就需要遍历链表将其插入合适的位置;

最后更新定时器的状态为pending状态
status.state = RTE_TIMER_PENDING;
status.owner = (int16_t)tim_lcore;
tim->status.u32 = status.u32;


2、定时器调度管理

在每个逻辑core中都有一个处理函数lcore_mainloop()去调用,rte_timer_manage();完成每个逻辑core上的,定时器管理功能;
/* optimize for the case where per-cpu list is empty */
if (LIST_EMPTY(&priv_timer[lcore_id].pending))
return;
在rte_timer_manage()中,先判断pending列表是否为空,如果是空,就要及时返回;

/* browse ordered list, add expired timers in 'expired' list */
rte_spinlock_lock(&priv_timer[lcore_id].list_lock);

LIST_FOREACH_SAFE(tim, tim2, &priv_timer[lcore_id].pending, next) {
if ((int64_t)(cur_time - tim->expire) < 0)
break;

LIST_REMOVE(tim, next);
LIST_INSERT_HEAD(&priv_timer[lcore_id].expired, tim, next);
}
这添加了自旋锁防止误操作;

如果定时器没到期,就直接跳出循环,如果到期了,就将其从pending列表中删除,然后将其插入的expried期满列表中;

接下来在遍历expried期满列表,然后
/* for each timer of 'expired' list, check state and execute callback */
while ((tim = LIST_FIRST(&priv_timer[lcore_id].expired)) != NULL) {
ret = timer_set_running_state(tim);

/* remove from expired list, and add it in done list */
LIST_REMOVE(tim, next);
LIST_INSERT_HEAD(&priv_timer[lcore_id].done, tim, next);
将其从expired 期满列表,移动到done完成列表;
/* execute callback function with list unlocked */
tim->f(tim, tim->arg);
执行定时器调用回调函数;

在执行完回调函数后,我们要判断其周期模式,如果  单周期的我们要将其done完成列表中删除,还要重新初始化其状态;
/* remove from done list and mark timer as stopped */
LIST_REMOVE(tim, next);
__TIMER_STAT_ADD(pending, -1);
status.state = RTE_TIMER_STOP;
status.owner = RTE_TIMER_NO_OWNER;


如果是周期性的定时器,我们要恢复期为pending状态;
/* keep it in done list and mark timer as pending */
status.state = RTE_TIMER_PENDING;
status.owner = (int16_t)lcore_id;


技术水平有待提高,如果文章有错误的地方希望读者指正,相互交流,互相学习;O(∩_∩)O~

写博文体会:代码不写不讲,对其只是一知半解。讲了写了,就知道自己在哪儿不足。不单单是在代码的理解上有收获,还有代码的架构,自己组织语言的能力,等等都会有收获。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  intel dpdk api