当前位置: 首页 > news >正文

记RT-Thread rt_timer_start函数的问题

我使用的RT-Thread版本为4.0.3。
我看了5.0.1的代码,此问已经被修复。

在4.0.3版本中的rt_timer_start函数源码如下:

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_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_SOFTif (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.*/if ((t->timeout_tick - timer->timeout_tick) == 0){continue;}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;}/* Interestingly, this super simple timer insert counter works very very* well on distributing the list height uniformly. By means of "very very* well", I mean it beats the randomness of timer->timeout_tick very easily* (actually, the timeout_tick is not random and easy to be attacked). */random_nr++;tst_nr = random_nr;rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1],&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++){if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK))rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl],&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl]));elsebreak;/* Shift over the bits we have tested. Works well with 1 bit and 2* bits. */tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1;}timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;/* enable interrupt */rt_hw_interrupt_enable(level);#ifdef RT_USING_TIMER_SOFTif (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER){/* check whether timer thread is ready */if ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND){/* resume timer thread to check soft timer */rt_thread_resume(&timer_thread);rt_schedule();}}
#endifreturn RT_EOK;
}

如果存在多个地方对同一个timer进行启动操作,例如在线程中start和中断中 start,有可能会在第一次rt_hw_interrupt_enable和第二次rt_hw_interrupt_disable之间代码执行被中断,使得这个timer被中断代码插入定时器链表,中断执行完成之后,线程代码继续执行,此时链表中已经存在这个timer,这个timer会再一次被insert,定时器链表由此被破坏。
我遇到的情况是这个timer被再一次insert后,next和prev指针都被修改为指向timer自身链表节点。在这种情况下,如果对链表进行遍历,会在这个timer链表节点死循环。

http://www.lryc.cn/news/112060.html

相关文章:

  • C++初阶——拷贝构造和运算符重载(const成员)
  • go练习 day01
  • C# Blazor 学习笔记(0.1):如何开始Blazor和vs基本设置
  • 原码的乘法运算 补码乘法运算
  • 找不到d3dx9_43.dll丢失怎么解决(分享几种解决方法)
  • 篇四:建造者模式:逐步构造复杂对象
  • vs导出和导入动态库和静态库
  • 30 使用easyExcel依赖生成Excel
  • 排序进行曲-v2.0
  • 反弹shell的N种姿势
  • 创意视频剪辑教程:快速合并视频并标题,让你的作品更吸睛!
  • 解决Hadoop审计日志hdfs-audit.log过大的问题
  • 【Java】java和kotlin关于Json写文件
  • 【深度学习】采用自动编码器生成新图像
  • 华为云交付
  • dns瞅一瞅
  • springAOP的实例
  • 【JavaEE】深入了解Spring中Bean的可见范围(作用域)以及前世今生(生命周期)
  • P1320 压缩技术(续集版)
  • k8s(七) 叩丁狼 service Ingress
  • Android Studio 关于BottomNavigationView 无法预览视图我的解决办法
  • 【STM32】小电流FOC驱控一体板(开源)
  • 代码分析:循环创建N个子进程——为什么最后一个属于父进程?
  • 【SpringBoot面试题整理-超级有效】
  • 岩土工程仪器多通道振弦传感器信号转换器应用于隧道安全监测
  • 西瓜书读书笔记整理(五)—— 第四章 决策树
  • STM32 4G学习
  • Golang 中实现实时聊天通讯
  • 前端面试的性能优化部分(5)每天10个小知识点
  • 【链表OJ 1】移除链表元素val