Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT_USING_TIMER_SOFT
软件定时器
5
现实的工程使用 soft timer 的一个坑,疑似 bug,希望解惑
发布于 2022-02-28 11:46:26 浏览:2731
订阅该版
[tocm] ### 背景 用的 rt_thread 4.0.1。机器运行在海上,绝对不算是小的设备,把核心的控制滤波代码放在了 soft timer 里定时且周期性的调用(从 freertos 里迁移的,有类似用法)。 而去年大约 11 月末就发现有一台机器运行非常奇怪,soft timer 里面的控制代码似乎像是永久休眠了,而其他线程却是正常运行,跟公司内部的后台网络都能正常连上。通过局域网连 telnet 看一些如 list_timer 之类的命令可以看到 timer 线程就是一直处于阻塞的状态。 然后修改了应用代码,把可能阻塞的功能都移出。保险起见,还把喂狗程序放到了 soft timer 里。大约 1 月初批量升级后,于上个礼拜一天之内连续出现几台机器出现重启。首先可以排除 arm 硬件异常和软件 assert 失败的情况,因为这两种情况程序里都会执行硬件保护 + 文件系统记录 + 重启。而这几台没有文件记录,正好看门狗中断则没加文件记录。那么大概率还是被阻塞了。 ### 为什么会有疑惑 1. 海上难以现场检查调试,工况也复杂,只能艰难地模拟,而另一方面,应用已经足够精简,自己的应用的代码问题检查似乎到头了。 2. 时间太过蹊跷,算了一下两次的时间跨度都是约 50 天。一毫秒一个 tick 的话,对于类型属于 uint32_t 的机器正好 49 天。而 soft timer 里面的执行的代码无非就是周期性的几个 tick 执行一次,跟 tick 溢出没有关系,应该没有密切的联系。 最后,直到我看到了 timer_thread 的代码 ### 个人看法 soft timer 里面都是在 timer_thread 里通过回调调用的,这个线程是这样 ```c static void rt_thread_timer_entry(void *parameter) { rt_tick_t next_timeout; while (1) { /* get the next timeout tick */ next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list); if (next_timeout == RT_TICK_MAX) { /* no software timer exist, suspend self. */ rt_thread_suspend(rt_thread_self()); rt_schedule(); } else { rt_tick_t current_tick; /* get current tick */ current_tick = rt_tick_get(); if ((next_timeout - current_tick) < RT_TICK_MAX / 2) { /* get the delta timeout tick */ next_timeout = next_timeout - current_tick; rt_thread_delay(next_timeout); } } /* check software timer */ rt_soft_timer_check(); } } ``` 一眼看到了这句 ```c if (next_timeout == RT_TICK_MAX) ``` 我有个疑惑,假设 next_timeout 是真的等于 0xFFFFFFFF,但结果依旧还是把 timer_thread 阻塞了,这逻辑处理是否有问题? ### 自己的测试 带着自己的疑惑,自己测试了下,测试代码如下 ```c void test_softTimer(void); int main(void) { rt_assert_set_hook(rt_assert_fun); test_softTimer(); } uint32_t test_softTimer_count_1; uint32_t test_softTimer_count_2; uint32_t test_softTimer_count_3; static void test_softTimer_entry_1(void *para) { test_softTimer_count_1 += 1; } static void test_softTimer_entry_2(void *para) { test_softTimer_count_2 += 1; } static void test_softTimer_entry_3(void *para) { test_softTimer_count_3 += 1; } void test_softTimer(void) { rt_timer_t timer1, timer2, timer3; timer1 = rt_timer_create("test 1", test_softTimer_entry_1, RT_NULL, 1, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); timer2 = rt_timer_create("test 2", test_softTimer_entry_2, RT_NULL, 2, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); timer3 = rt_timer_create("test 3", test_softTimer_entry_3, RT_NULL, 3, RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER); rt_timer_start(timer1); rt_timer_start(timer2); rt_timer_start(timer3); } MSH_CMD_EXPORT(test_softTimer, test_softTimer); void list_count(void) { rt_kprintf("[1]:%d\n[2]:%d\n[3]:%d\n", test_softTimer_count_1, test_softTimer_count_2, test_softTimer_count_3); } MSH_CMD_EXPORT(list_count, list_count); ``` ``` //static rt_tick_t rt_tick = 0; rt_tick_t rt_tick = 0xFFFFFAD0;//修改下 rt_tick 的初始值 ``` 一个关键是要把 rt_tick 这个变量设置成一个合适的值,要确保所有初始化里的 rt_timer_start 都执行完(rt_timer_start 会恢复阻塞的 timer_thread),然后再等到 rt_tick 接近 `0xFFFFFFFF`, 然后观察 timer_thread 是否把自己给阻塞了。 附上几张测试记录: 起初的状况 ![Snipaste_2022-02-28_10-25-42.png](https://oss-club.rt-thread.org/uploads/20220228/db7797f7d27bfc49896e5f6b01eb8fc5.png.webp) 出现问题的状况 ![Snipaste_2022-02-28_10-17-21.png](https://oss-club.rt-thread.org/uploads/20220228/d32eaaaffac39773f336e8d7df506fef.png.webp) ``` msh />list_thread pri status sp stack size max used left tick error -------- --- ------- ---------- ---------- ------ ---------- --- tshell 24 running 0x0000014c 0x00001000 21% 0x00000007 000 tcpip 8 suspend 0x00000164 0x00002800 03% 0x00000014 000 etx 12 suspend 0x0000015c 0x00002800 03% 0x00000010 000 erx 12 suspend 0x0000014c 0x00002800 03% 0x00000010 000 mmcsd_de 6 suspend 0x00000174 0x00005000 05% 0x0000000c 000 tidle0 31 ready 0x000000d8 0x00000200 48% 0x0000000d 000 timer 0 suspend 0x00000114 0x00001000 07% 0x00000009 000 msh />list_timer periodic timeout flag -------- ---------- ---------- ----------- test 3 0x00000003 0x00000001 activated test 2 0x00000002 0x00000000 activated test 1 0x00000001 0xffffffff activated tshell 0x00000005 0x0000396b deactivated tcpip 0x00000064 0x000039c3 activated etx 0x00000000 0x00000000 deactivated erx 0x00000000 0x00000000 deactivated mmcsd_de 0x00000001 0xfffffcd3 deactivated tidle0 0x00000000 0x00000000 deactivated timer 0x00000001 0xfffffffe deactivated current tick:0x00003995 msh />list_t list_timer list_thread msh />list_c list_count msh />list_count [1]:1218 [2]:609 [3]:406 msh />list_count [1]:1218 [2]:609 [3]:406 msh />list_count [1]:1218 [2]:609 [3]:406 msh /> ``` 计数值也不再增长,断点也不在停留在 `timer_thread`。看上去问题复现了。
查看更多
mysterywolf
认证专家
2022-03-03
https://github.com/mysterywolf
感谢反馈!
8
个回答
默认排序
按发布时间排序
flyboy
2022-03-10
Do my self();
https://github.com/RT-Thread/rt-thread/pull/5637 尝试修复了一下,楼主可以看看有没有解决你的问题
sync
2022-02-28
这家伙很懒,什么也没写!
楼主更新下版本试试,看了下4.0.1里面的timer.c和后面的是不一样的
出出啊
2022-02-28
恃人不如自恃,人之为己者不如己之自为也
当软定时器列表上没有定时器有定时需求的时候,软定时器线程就会进入永久睡眠。只有 rt_timer_start 才会唤醒“永久睡眠”的软定时器线程。 `rt_timer_list_next_timeout` 获得定时器列表上最早到达定时需求的定时间隔,运算错误出现 0xFFFFFFFF 的可能性还是很小的。 `RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2);` 定时器要求定时间隔必须小于 0xffffffff 的一半,如果你用了比这个值大的。那你肯定用错了
按时计划
2022-02-28
这家伙很懒,什么也没写!
我的想法就是有没有这样的可能: 在 tick 快溢出的时候,timer 线程错误的把本该在 0xFFFFFFFF 这个极端的时间点 timeout 回调错误的当成了自我休眠的信号,这里是否有可能有 bug? 我的测试代码很简单,就是几个周期性的 soft timer,然而就是出现了休眠的情况。这写的不合理吗? 如果是我平台的问题,你们的平台也可以试一下。想办法让 tick 接近 0xFFFFFFFF 看是否会永久休眠。 --- 下午的时间 最后把自己临时改的试了下,好像没问题了 自己拿 这个版本的 timer.c 改了下,能跑了,不知道会不会有新问题 ``` /* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2006-03-12 Bernard first version * 2006-04-29 Bernard implement thread timer * 2006-06-04 Bernard implement rt_timer_control * 2006-08-10 Bernard fix the periodic timer bug * 2006-09-03 Bernard implement rt_timer_detach * 2009-11-11 LiJin add soft timer * 2010-05-12 Bernard fix the timer check bug. * 2010-11-02 Charlie re-implement tick overflow issue * 2012-12-15 Bernard fix the next timeout issue in soft timer * 2014-07-12 Bernard does not lock scheduler when invoking soft-timer * timeout function. */ #include
#include
/* hard timer list */ static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; #ifdef RT_USING_TIMER_SOFT #ifndef RT_TIMER_THREAD_STACK_SIZE #define RT_TIMER_THREAD_STACK_SIZE 1024 #endif #ifndef RT_TIMER_THREAD_PRIO #define RT_TIMER_THREAD_PRIO 0 #endif /* soft timer list */ rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; struct rt_thread timer_thread; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE]; #endif #ifdef RT_USING_HOOK extern void (*rt_object_take_hook)(struct rt_object *object); extern void (*rt_object_put_hook)(struct rt_object *object); static void (*rt_timer_enter_hook)(struct rt_timer *timer); static void (*rt_timer_exit_hook)(struct rt_timer *timer); /** * @addtogroup Hook */ /**@{*/ /** * This function will set a hook function, which will be invoked when enter * timer timeout callback function. * * @param hook the hook function */ void rt_timer_enter_sethook(void (*hook)(struct rt_timer *timer)) { rt_timer_enter_hook = hook; } /** * This function will set a hook function, which will be invoked when exit * timer timeout callback function. * * @param hook the hook function */ void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer)) { rt_timer_exit_hook = hook; } /**@}*/ #endif static void _rt_timer_init(rt_timer_t timer, void (*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag) { int i; /* set flag */ timer->parent.flag = flag; /* set deactivated */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; timer->timeout_func = timeout; timer->parameter = parameter; timer->timeout_tick = 0; timer->init_tick = time; /* initialize timer list */ for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) { rt_list_init(&(timer->row[i])); } } #if 0 /* the fist timer always in the last row */ static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[]) { struct rt_timer *timer; if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) return RT_TICK_MAX; timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); return timer->timeout_tick; } #else static rt_uint32_t rt_timer_list_next_timeout(rt_list_t timer_list[], rt_tick_t * tick) { struct rt_timer *timer; if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) return 0; timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); *tick = timer->timeout_tick; return 1; } #endif 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]); } } #if RT_DEBUG_TIMER static int rt_timer_count_height(struct rt_timer *timer) { int i, cnt = 0; for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) { if (!rt_list_isempty(&timer->row[i])) cnt++; } return cnt; } void rt_timer_dump(rt_list_t timer_heads[]) { rt_list_t *list; for (list = timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1].next; list != &timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1]; list = list->next) { struct rt_timer *timer = rt_list_entry(list, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); rt_kprintf("%d", rt_timer_count_height(timer)); } rt_kprintf("\n"); } #endif /** * @addtogroup Clock */ /**@{*/ /** * This function will initialize a timer, normally this function is used to * initialize a static timer object. * * @param timer the static timer object * @param name the name of timer * @param timeout the timeout function * @param parameter the parameter of timeout function * @param time the tick of timer * @param flag the flag of timer */ void rt_timer_init(rt_timer_t timer, const char *name, void (*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag) { /* timer check */ RT_ASSERT(timer != RT_NULL); /* timer object initialization */ rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name); _rt_timer_init(timer, timeout, parameter, time, flag); } RTM_EXPORT(rt_timer_init); /** * 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); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_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; } RTM_EXPORT(rt_timer_detach); #ifdef RT_USING_HEAP /** * This function will create a timer * * @param name the name of timer * @param timeout the timeout function * @param parameter the parameter of timeout function * @param time the tick of timer * @param flag the flag of timer * * @return the created timer object */ rt_timer_t rt_timer_create(const char *name, void (*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag) { struct rt_timer *timer; /* allocate a object */ timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name); if (timer == RT_NULL) { return RT_NULL; } _rt_timer_init(timer, timeout, parameter, time, flag); return timer; } RTM_EXPORT(rt_timer_create); /** * 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); #endif /** * 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_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. */ 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])); else break; /* 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_SOFT if (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(); } } #endif return RT_EOK; } RTM_EXPORT(rt_timer_start); /** * 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; } RTM_EXPORT(rt_timer_stop); /** * 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; } RTM_EXPORT(rt_timer_control); /** * This function will check timer list, if a timeout event happens, the * corresponding timeout function will be invoked. * * @note this function shall be invoked in operating system timer interrupt. */ void rt_timer_check(void) { struct rt_timer *t; rt_tick_t current_tick; register rt_base_t level; RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n")); current_tick = rt_tick_get(); /* disable interrupt */ level = rt_hw_interrupt_disable(); while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) { t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); /* * It supposes that the new tick shall less than the half duration of * tick max. */ if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) { RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t)); /* remove timer from timer list firstly */ _rt_timer_remove(t); /* call timeout function */ t->timeout_func(t->parameter); /* re-get tick */ current_tick = rt_tick_get(); RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t)); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) { /* start it */ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; rt_timer_start(t); } else { /* stop timer */ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; } } else break; } /* enable interrupt */ rt_hw_interrupt_enable(level); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n")); } /** * This function will return the next timeout tick in the system. * * @return the next timeout tick in the system */ #if 0 rt_tick_t rt_timer_next_timeout_tick(void) { return rt_timer_list_next_timeout(rt_timer_list); } #endif #ifdef RT_USING_TIMER_SOFT /** * This function will check timer list, if a timeout event happens, the * corresponding timeout function will be invoked. */ void rt_soft_timer_check(void) { rt_tick_t current_tick; rt_list_t *n; struct rt_timer *t; RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n")); current_tick = rt_tick_get(); /* lock scheduler */ rt_enter_critical(); for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next; n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);) { t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); /* * It supposes that the new tick shall less than the half duration of * tick max. */ if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) { RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t)); /* move node to the next */ n = n->next; /* remove timer from timer list firstly */ _rt_timer_remove(t); /* not lock scheduler when performing timeout function */ rt_exit_critical(); /* call timeout function */ t->timeout_func(t->parameter); /* re-get tick */ current_tick = rt_tick_get(); RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t)); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); /* lock scheduler */ rt_enter_critical(); if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) { /* start it */ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; rt_timer_start(t); } else { /* stop timer */ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; } } else break; /* not check anymore */ } /* unlock scheduler */ rt_exit_critical(); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n")); } #if 0 /* system timer thread entry */ static void rt_thread_timer_entry(void *parameter) { rt_tick_t next_timeout; while (1) { /* get the next timeout tick */ next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list); if (next_timeout == RT_TICK_MAX) { /* no software timer exist, suspend self. */ rt_thread_suspend(rt_thread_self()); rt_schedule(); } else { rt_tick_t current_tick; /* get current tick */ current_tick = rt_tick_get(); if ((next_timeout - current_tick) < RT_TICK_MAX / 2) { /* get the delta timeout tick */ next_timeout = next_timeout - current_tick; rt_thread_delay(next_timeout); } } /* check software timer */ rt_soft_timer_check(); } } #else static void rt_thread_timer_entry(void *parameter) { rt_tick_t next_timeout; rt_uint32_t status; while (1) { /* get the next timeout tick */ status = rt_timer_list_next_timeout(rt_soft_timer_list, &next_timeout); if (status == 0) { /* no software timer exist, suspend self. */ rt_thread_suspend(rt_thread_self()); rt_schedule(); } else { rt_tick_t current_tick; /* get current tick */ current_tick = rt_tick_get(); if ((next_timeout - current_tick) < RT_TICK_MAX / 2) { /* get the delta timeout tick */ next_timeout = next_timeout - current_tick; rt_thread_delay(next_timeout); } } /* check software timer */ rt_soft_timer_check(); } } #endif #endif /** * @ingroup SystemInit * * This function will initialize system timer */ void rt_system_timer_init(void) { int i; for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++) { rt_list_init(rt_timer_list + i); } } /** * @ingroup SystemInit * * This function will initialize system timer thread */ void rt_system_timer_thread_init(void) { #ifdef RT_USING_TIMER_SOFT int i; for (i = 0; i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]); i++) { rt_list_init(rt_soft_timer_list + i); } /* start software timer thread */ rt_thread_init(&timer_thread, "timer", rt_thread_timer_entry, RT_NULL, &timer_thread_stack[0], sizeof(timer_thread_stack), RT_TIMER_THREAD_PRIO, 10); /* startup */ rt_thread_startup(&timer_thread); #endif } /**@}*/ ``` 也不会自动永久休眠了 ``` msh />list_count [1]:97951 [2]:48975 [3]:32650 msh />list_count [1]:98540 [2]:49270 [3]:32846 msh />list_count [1]:99089 [2]:49544 [3]:33029 msh />list_count [1]:99703 [2]:49851 [3]:33234 msh />list_count [1]:100297 [2]:50148 [3]:33432 msh />list_count [1]:100886 [2]:50443 [3]:33628 msh />list_count [1]:101460 [2]:50730 [3]:33820 msh />list_count [1]:102009 [2]:51004 [3]:34003 msh />list_count [1]:102558 [2]:51279 [3]:34186 msh />list_count [1]:103112 [2]:51556 [3]:34370 msh />list_count [1]:103601 [2]:51800 [3]:34533 msh />list_count [1]:104890 [2]:52445 [3]:34963 msh /> msh /> msh />list_count [1]:241529 [2]:120764 [3]:80509 msh />list_count [1]:242388 [2]:121194 [3]:80796 msh />list_timer periodic timeout flag -------- ---------- ---------- ----------- test 3 0x00000003 0x00043600 activated test 2 0x00000002 0x00043602 activated test 1 0x00000001 0x00043605 activated tshell 0x00000005 0x000435f7 deactivated tcpip 0x00000064 0x00043657 activated etx 0x00000000 0x00000000 deactivated erx 0x00000000 0x00000000 deactivated mmcsd_de 0x00000001 0xffffffdf deactivated tidle0 0x00000000 0x00000000 deactivated timer 0x00000001 0x0004361f activated current tick:0x00043621 msh /> ```
RTT_逍遥
认证专家
2022-02-28
https://github.com/supperthomas
RT_TICK_MAX这个值需要作为一个阻塞的标志来使用,如果你的系统比较特殊的话,那你觉得这里应该如何修改呢?可以想想象如何修复。
yks
2022-03-01
这家伙很懒,什么也没写!
关注一波,感觉楼主修改后,更符合`void rt_thread_timer_entry(void *parameter)`里面的注释:没有软定时器挂起自己。
yichen_1911
2024-09-06
这家伙很懒,什么也没写!
rtthread 团队在搞什么?3.1.5版本停更这么久了,楼主提出的问题也不修复,在低功耗项目上也遇到类似的问题了,感谢楼主。希望rtthread团队早日解决这些问题。
撰写答案
登录
注册新账号
关注者
2
被浏览
2.7k
关于作者
按时计划
这家伙很懒,什么也没写!
提问
3
回答
3
被采纳
1
关注TA
发私信
相关问题
1
软件定时器反复启动,会怎样?
2
软件定时器有没有定时器复位功能
3
软件定时器的回调函数里可以挂起或解挂另一个线程吗?
4
RT_TIMER里面分了HARD和SOFT类型,本质有啥区别
5
定时器不准及定时器冲突问题
6
RT_Thread nano开启软件定时器后线程卡死
7
在软件定时器还在运行的时候,调用rt_timer_start函数会怎么样?
8
软件定时器线程优先级怎么通过代码设置?
9
软件定时器优先级问题导致系统重启?
10
线程调度的问题,线程无法被及时抢占
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
2
RT-Thread EtherKit开源以太网硬件正式发布
3
如何在master上的BSP中添加配置yml文件
4
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
5
RT-Thread 发布 EtherKit开源以太网硬件!
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
15
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部