20191002(13)RT-Thread 时钟管理 源码解读(2)删除及控制部分

mac2022-06-30  18

目的:

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; }
最新回复(0)