在Rt-thread中,定义了一个全局的系统定时器列表,当线程需要挂起的时候,就把线程内置的定时器将线程挂起到这个系统定时器列表中。这个列表维护一条双向链路,节点按照定时器的延时时间大小进行升序排列。定时器列表的定义如下:
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
struct rt_list_node
{
struct rt_list_node *next; /**< point to next node. */
struct rt_list_node *prev; /**< point to prev node. */
};
一 初始化定时器列表
在rt_list_init中进行next,prev指针的初始化
两个指针均指向节点本身
二 定时器在线程中的定义
在线程结构体rt_thread中定义了rt_timer。rt_timer的定义如下:
struct rt_timer
{
struct rt_object parent; /**< inherit from rt_object */
rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL];
void (*timeout_func)(void *parameter); /**< timeout function */
void *parameter; /**< timeout function's parameter */
rt_tick_t init_tick; /**< timer timeout tick */
rt_tick_t timeout_tick; /**< timeout tick */
};
(1) 定时器也属于内核对象,所以自身结构中也会包含一个内核对象rt_object。通过这个成员将定时器挂到对象容器里面
(2) rt_list_t,定时器自身的节点。通过该节点可以实现将定时器插入到系统定时器列表
(3) timeout_func:定时器超时后的回调函数
(4) init_tick:定时器实际需要延时的时间
(5) timeout_tick:定时器超时后的tick值
三 定时器的初始化
rt_timer_init对定时器进行初始化
(1) 首先调用rt_object_init将该定时器插入到对应的容器中去
(2) 初始化rt_timer变量。对回调函数,延时ticket值进行赋值。并初始化定时器的内置节点,即将节点的next和prev这两个指针指向节点本身。当启动定时器的时候,定时器就通过该节点将自身插入到系统定时器列表rt_timer_list中
四 开启定时器:
定时器初始化完后,调用rt_timer_start将定时器插入到rt_timer_list中去
1 首先是计算定时器超时的tick值
timer->timeout_tick = rt_tick_get() + timer->init_tick; 当系统定时器rt_tick的值等于timeout_tick时候,表示定时器到期。另外要求定时器超时时间不能大于RT_TICK_MAX / 2。RT_TICK_MAX的值定义在rtdef.h中。默认是最大值为0xffffffff
下面的代码首先找到需要插入的位置。定时器在列表中是以降序的方式进行排列
2 最后调用rt_list_insert_after() 将定时器插入。
五 定时器停止
调用_rt_timer_remove将timer从定时器列表中删除