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 模块详解和测试》http://blog.csdn.net/linzhaolove/article/details/9410529
此文章主要以dpdk提供的实例代码 example/timer 为例来进行讲解
我们详细介绍一下这个函数,此函数在dpdk/lib/librte_timer/rte_timer.c文件中定义;
在rte_get_hpet_cycles()中,涉及到的 eal_hpet_msb变量,是在hpet_msb_inc() 线程函数中实时更新的;
接下来调用一个更底层的函数__rte_timer_reset()对定时器进行配置;
在了解timer_add()函数内部源码后了解到,插入列表时是按有序插入的,需要先查看第一个定时器,如果列表是空的,或者期望值小于第一定时器,就将其直接插入最前面,如果期望值大于第一个,就需要遍历链表将其插入合适的位置;
最后更新定时器的状态为pending状态
如果定时器没到期,就直接跳出循环,如果到期了,就将其从pending列表中删除,然后将其插入的expried期满列表中;
接下来在遍历expried期满列表,然后
在执行完回调函数后,我们要判断其周期模式,如果 单周期的我们要将其done完成列表中删除,还要重新初始化其状态;
如果是周期性的定时器,我们要恢复期为pending状态;
技术水平有待提高,如果文章有错误的地方希望读者指正,相互交流,互相学习;O(∩_∩)O~
写博文体会:代码不写不讲,对其只是一知半解。讲了写了,就知道自己在哪儿不足。不单单是在代码的理解上有收获,还有代码的架构,自己组织语言的能力,等等都会有收获。
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 ring 模块源码详解
- intel dpdk api ring 模块源码详解
- intel dpdk api ring 模块源码详解
- 关于Activity启动模式的基本使用,API使用详解。
- Linux用户抢占和内核抢占详解(概念, 实现和触发时机)--Linux进程的管理与调度(二十)
- Linux进程描述符task_struct结构体详解--Linux进程的管理与调度
- 利用systemctl管理Tomcat启动、停止、重启及开机启动详解
- Java定时任务调度工具详解之Timer篇
- ZigBee学习之绑定表管理函数详解——ZStack API解读
- intel dpdk api pci设备驱动注册和初始化过程
- ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)
- Linux基本配置和管理 4 ---- Linux系统启动详解
- Linux用户抢占和内核抢占详解(概念, 实现和触发时机)--Linux进程的管理与调度
- Linux进程上下文切换过程context_switch详解--Linux进程的管理与调度(二十一)【转】
- IBM AIX 5.3 系统管理 -- 系统启动过程详解
- Linux的命名空间详解--Linux进程的管理与调度(二)
- Timer与TimerTask的基本API,以及服务运行时改变调度时间
- intel dpdk api rte_eal_hugepage_init() 函数介绍
- 管理TAP端口并加入网桥 ----------intel dpdk 例子:Exception Path Sample Application
- IBM AIX 5.3 系统管理 -- 系统启动过程详解