问题发生的场景和现象:
使用armlink大神的modbus库,在串口中断中会调用rt_timer_start来启动定时器,判断下一个modbus帧是否超时。
在程序运行后有极小的几率会在串口中断中卡死。
问题大致定位的位置
如上文所述,在串口中断USART_IRQHandler中会调用rt_timer_start来启动定时器实现modbus的时序控制,同时也单独启动了一个modbus线程,其中也会执行rt_timer_start来控制modbus的超时。但是在执行rt_timer_start时有极小几率(约1%)会卡死, 卡死位置在timer.c下面这个for循环中:
观察变量可以看到如下结果:定时器链表 rt_timer_list 链表变成了死循环链表:
通过多次断点尝试,发现了如下的调用栈和调用位置:
猜测的原因和解决办法
可以看到在执行rt_timer_start时被打断了,打断后又执行了一遍rt_timer_start,导致的后果的是,执行顺序变成了:
_rt_timer_remove 执行完之后被打断
_rt_timer_remove
rt_list_insert_after
回到被打断的位置,继续往下执行:rt_list_insert_after
第一次remove已经移除了链表节点,第二次remove无效;第三次第四次插入两次,造成链表变成死循环链表。
可能的解决办法
个人认为解决办法在于 timer.c 中:
在324行手动开启了中断,之后又在336行几乎是又立即关闭了中断。所以我个人认为:
324行这里是否不需要开启中断。
或者另一方面来说,rt_timer_start这个函数本身就是线程不安全的?即使这样也希望能做一个断言判断一下,不然这样在死循环里不出来很难排查问题。
原作者:RT-Thread物联网操作系统
更多回帖