目的:
1 了解时钟源码删除及控制部分源码
正文
1 删除和脱离源码
detach 脱离;分离
类:是 C++ / python / java 这类语言封装函数功能的一种表示,举一个例子你要吃水果,那这个动作交给程序执行就是,拿起水果,张嘴, 咀嚼,吞咽;总共四个步骤,而类就是集合这四个动作的结合体,但是不同的水果吃的方法不同,只要继承这个类,比如苹果类,西瓜类,具体动作不一样,但是目的和流程一样,也就是面向对象编程。
rt_tiemr_detach() 函数的目的就是将一个定时器从执行列表中拿出来,然后将它放入一个等待列表之中,要么被删除要么就是重新被取出来使用。
//filePath: src/timer.c
/**
* This function will detach a timer from timer management. 将定时器从管理列表中剔除但是不会释放所占用资源
*
* @param timer the static timer object
*
* @return the operation status, RT_EOK on OK; RT_ERROR on error
*/
rt_err_t rt_timer_detach(rt_timer_t timer)
{
register rt_base_t level;
/* timer check */
RT_ASSERT(timer != RT_NULL);
//判断 timer 的父类是否为定时器类,rt_timer_t 结构体对象属性是通过 parent 来体现的
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
//判断 timer 的父类是一个系统对象
RT_ASSERT(rt_object_is_systemobject(&timer->parent));//
/* disable interrupt */
level = rt_hw_interrupt_disable();//操作期间避免硬件中断
_rt_timer_remove(timer);//将其从定时器列表中剔除 //函数源代码在下文
/* enable interrupt */
rt_hw_interrupt_enable(level);//恢复硬件中断
rt_object_detach((rt_object_t)timer);//将这个定时器放到脱离等待列表中
return RT_EOK;//返回OK
}
RTM_EXPORT(rt_timer_detach);
rt_timer_delete() 函数作用与 detach 一样,目的都是将一个定时器的对象从定时器列表中取出来,但是最后会将这个定时器删除释放其占用的资源。
/**
* This function will delete a timer and release timer memory 删除定时器并释放资源
*
* @param timer the timer to be deleted
*
* @return the operation status, RT_EOK on OK; RT_ERROR on error
*/
rt_err_t rt_timer_delete(rt_timer_t timer)
{
register rt_base_t level;
/* timer check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE);
/* disable interrupt */
level = rt_hw_interrupt_disable();
_rt_timer_remove(timer); //函数源代码在下文
/* enable interrupt */
rt_hw_interrupt_enable(level);
rt_object_delete((rt_object_t)timer);
return RT_EOK;
}
RTM_EXPORT(rt_timer_delete);
RT_TIMER_SKIP_LIST_LEVEL 代表跳表的层级,具体可以看之前理论篇的内容,这里也就是对多个索引列表进行检索,以较快的速度确定目标定时器的位置,并将它删除
rt_inline void _rt_timer_remove(rt_timer_t timer)
{
int i;
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
{
rt_list_remove(&timer->row[i]);
}
}
/**
* @brief remove node from list.
* @param n the node to remove from the list.
*/
rt_inline void rt_list_remove(rt_list_t *n)
{
//重新整理指针指向
n->next->prev = n->prev;
n->prev->next = n->next;
n->next = n->prev = n;
}
2 控制函数
这是定时器启动函数
1 验证定时器是有效的
2 排除这个定时器已经在定时器列表中运行,所以先进行一次删除
3 保留定时器类型,但是将定时器状态切换成非运行状态(RT_TIMER_FLAG_DEACTIVATED)
4 将超时需要执行的函数挂载
5 判断超时时间 在 2^16 (0 ~ 65535)内
6 设定超时时间 = 当前节拍数 + 目标超时时间
7 根据定时器类型,加入硬件超时列表或软件超时列表
8 遍历所有定时器列表,找出超时的定时器(优先执行插入时间早的超时函数)
9 将当前定时器插入到列表之中
/**
* This function will start the timer
*
* @param timer the timer to be started
*
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_timer_start(rt_timer_t timer)
{
unsigned int row_lvl;
rt_list_t *timer_list;
register rt_base_t level;
rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
unsigned int tst_nr;
static unsigned int random_nr;
/* timer check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
/* stop timer firstly */
level = rt_hw_interrupt_disable();
/* remove timer from list */
_rt_timer_remove(timer); //删除定时器
/* change status of timer */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
//RT_TIMER_FLAG_ACTIVATED = 0x1 --> ~0x1 = 0xFE = 1111 1110 & 任何值 = 第一位永远是 0
//RT_TIMER_FLAG_DEACTIVATED (吊销) = 0x0
//所以这一步的目的是保留定时器类型(硬定时器/软定时器),同时将定时器状态改为非工作状态
rt_hw_interrupt_enable(level);
//这步的目的就是挂载超时之后调用的函数
RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));
/*
* get timeout tick,
* the max timeout tick shall not great than RT_TICK_MAX/2
*/
RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2); //确定定时范围
timer->timeout_tick = rt_tick_get() + timer->init_tick; //根据当前时钟节拍数 + 超时时间 得到应该赋值的超时时间
/* disable interrupt */
level = rt_hw_interrupt_disable();
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
/* insert timer to soft timer list */
timer_list = rt_soft_timer_list;
}
else
#endif
{
/* insert timer to system timer list */
timer_list = rt_timer_list;
}
//这个目的 第一 先遍历一遍确定有没有超时的定时器,有就将它们处理掉
//第二 就是将目标定时器插入到列表中
row_head[0] = &timer_list[0];
for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)//跳表有很多层,一层一层遍历
{
for (; row_head[row_lvl] != timer_list[row_lvl].prev;
row_head[row_lvl] = row_head[row_lvl]->next)
{
struct rt_timer *t;
rt_list_t *p = row_head[row_lvl]->next;
/* fix up the entry pointer */
t = rt_list_entry(p, struct rt_timer, row[row_lvl]);//获得这一级定时器列表的入口指针
//这段话:如果有两个定时器同时超时了,优先执行插入时间较早的定时器
/* If we have two timers that timeout at the same time, it's
* preferred that the timer inserted early get called early.
* So insert the new timer to the end the the some-timeout timer
* list.
*/
//timer 的超时时间是由 当下节拍数 10 + 目标设定超时 300 共同构成 也就是 设定 310
if ((t->timeout_tick - timer->timeout_tick) == 0) //超时了就继续检查
{
continue;
}
//RT_TICK_MAX 0xffffffff 2^32 次
else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2) //当前取出的定时器没有超时,就结束
{
break;
}
}
if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1) //将定时器插入到这个跳表层级中
row_head[row_lvl + 1] = row_head[row_lvl] + 1;
}
/**
* This function will stop the timer
*
* @param timer the timer to be stopped
*
* @return the operation status, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_timer_stop(rt_timer_t timer)
{
register rt_base_t level;
/* timer check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
return -RT_ERROR;
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent)));
/* disable interrupt */
level = rt_hw_interrupt_disable();
_rt_timer_remove(timer);
/* enable interrupt */
rt_hw_interrupt_enable(level);
/* change stat */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
return RT_EOK;
}
就是对定时器的类型进行切换
/**
* This function will get or set some options of the timer
*
* @param timer the timer to be get or set
* @param cmd the control command
* @param arg the argument
*
* @return RT_EOK
*/
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
{
/* timer check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
switch (cmd)
{
case RT_TIMER_CTRL_GET_TIME: //获得设定的超时时间(就是 初始设定不包含时钟节拍的)
*(rt_tick_t *)arg = timer->init_tick;
break;
case RT_TIMER_CTRL_SET_TIME: //设置初始时间
timer->init_tick = *(rt_tick_t *)arg;
break;
case RT_TIMER_CTRL_SET_ONESHOT: //工作类型,只超时一次就停止
timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
break;
case RT_TIMER_CTRL_SET_PERIODIC://循环工作
timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
break;
}
return RT_EOK;
}