diff --git a/src/timer.c b/src/timer.c index 29bfecd3d8de23194533236d2a6797881efc3153..f6857798e35397ea706c73e1515567e85b7c7cc2 100644 --- a/src/timer.c +++ b/src/timer.c @@ -17,6 +17,7 @@ * 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 */ #include @@ -26,6 +27,14 @@ static rt_list_t rt_timer_list = RT_LIST_OBJECT_INIT(rt_timer_list); #ifdef RT_USING_TIMER_SOFT +#ifndef RT_TIMER_THREAD_STACK_SIZE +#define RT_TIMER_THREAD_STACK_SIZE 512 +#endif + +#ifndef RT_TIMER_THREAD_PRIO +#define RT_TIMER_THREAD_PRIO 0 +#endif + /* soft timer list */ static rt_list_t rt_soft_timer_list; static struct rt_thread timer_thread; @@ -52,42 +61,42 @@ static void (*rt_timer_timeout_hook)(struct rt_timer *timer); */ void rt_timer_timeout_sethook(void (*hook)(struct rt_timer *timer)) { - rt_timer_timeout_hook = hook; + rt_timer_timeout_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) + void (*timeout)(void *parameter), void *parameter, + rt_tick_t time, rt_uint8_t flag) { - /* set flag */ - timer->parent.flag = flag; + /* set flag */ + timer->parent.flag = flag; - /* set deactivated */ - timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + /* set deactivated */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - timer->timeout_func = timeout; - timer->parameter = parameter; + timer->timeout_func = timeout; + timer->parameter = parameter; - timer->timeout_tick = 0; - timer->init_tick = time; + timer->timeout_tick = 0; + timer->init_tick = time; - /* initialize timer list */ - rt_list_init(&(timer->list)); + /* initialize timer list */ + rt_list_init(&(timer->list)); } static rt_tick_t rt_timer_list_next_timeout(rt_list_t *timer_list) { - struct rt_timer *timer; + struct rt_timer *timer; - if (rt_list_isempty(timer_list)) - return RT_TICK_MAX; - - timer = rt_list_entry(timer_list->next, struct rt_timer, list); + if (rt_list_isempty(timer_list)) + return RT_TICK_MAX; + + timer = rt_list_entry(timer_list->next, struct rt_timer, list); - return timer->timeout_tick; + return timer->timeout_tick; } /** @@ -108,17 +117,17 @@ static rt_tick_t rt_timer_list_next_timeout(rt_list_t *timer_list) * @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) + 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 check */ + RT_ASSERT(timer != RT_NULL); - /* timer object initialization */ - rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name); + /* timer object initialization */ + rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name); - _rt_timer_init(timer, timeout, parameter, time, flag); + _rt_timer_init(timer, timeout, parameter, time, flag); } RTM_EXPORT(rt_timer_init); @@ -131,23 +140,23 @@ RTM_EXPORT(rt_timer_init); */ rt_err_t rt_timer_detach(rt_timer_t timer) { - register rt_base_t level; + register rt_base_t level; - /* timer check */ - RT_ASSERT(timer != RT_NULL); + /* timer check */ + RT_ASSERT(timer != RT_NULL); - /* disable interrupt */ - level = rt_hw_interrupt_disable(); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); - /* remove it from timer list */ - rt_list_remove(&(timer->list)); + /* remove it from timer list */ + rt_list_remove(&(timer->list)); - /* enable interrupt */ - rt_hw_interrupt_enable(level); + /* enable interrupt */ + rt_hw_interrupt_enable(level); - rt_object_detach((rt_object_t)timer); + rt_object_detach((rt_object_t)timer); - return -RT_EOK; + return -RT_EOK; } RTM_EXPORT(rt_timer_detach); @@ -164,20 +173,20 @@ RTM_EXPORT(rt_timer_detach); * @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) + void *parameter, rt_tick_t time, rt_uint8_t flag) { - struct rt_timer *timer; + 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; - } + /* 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); + _rt_timer_init(timer, timeout, parameter, time, flag); - return timer; + return timer; } RTM_EXPORT(rt_timer_create); @@ -190,23 +199,23 @@ RTM_EXPORT(rt_timer_create); */ rt_err_t rt_timer_delete(rt_timer_t timer) { - register rt_base_t level; + register rt_base_t level; - /* timer check */ - RT_ASSERT(timer != RT_NULL); + /* timer check */ + RT_ASSERT(timer != RT_NULL); - /* disable interrupt */ - level = rt_hw_interrupt_disable(); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); - /* remove it from timer list */ - rt_list_remove(&(timer->list)); + /* remove it from timer list */ + rt_list_remove(&(timer->list)); - /* enable interrupt */ - rt_hw_interrupt_enable(level); + /* enable interrupt */ + rt_hw_interrupt_enable(level); - rt_object_delete((rt_object_t)timer); + rt_object_delete((rt_object_t)timer); - return -RT_EOK; + return -RT_EOK; } RTM_EXPORT(rt_timer_delete); #endif @@ -220,76 +229,76 @@ RTM_EXPORT(rt_timer_delete); */ rt_err_t rt_timer_start(rt_timer_t timer) { - struct rt_timer *t; - register rt_base_t level; - rt_list_t *n, *timer_list; + struct rt_timer *t; + register rt_base_t level; + rt_list_t *n, *timer_list; - /* timer check */ - RT_ASSERT(timer != RT_NULL); - if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) - return -RT_ERROR; + /* timer check */ + RT_ASSERT(timer != RT_NULL); + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + return -RT_ERROR; - RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent))); + 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; + /* 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(); + /* 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 + 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; - } - - for (n = timer_list->next; n != timer_list; n = n->next) - { - t = rt_list_entry(n, struct rt_timer, list); - - /* - * It supposes that the new tick shall less than the half duration of - * tick max. - */ - if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX/2) - { - rt_list_insert_before(n, &(timer->list)); - break; - } - } - /* no found suitable position in timer list */ - if (n == timer_list) - { - rt_list_insert_before(n, &(timer->list)); - } - - timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; - - /* enable interrupt */ - rt_hw_interrupt_enable(level); + { + /* insert timer to system timer list */ + timer_list = &rt_timer_list; + } + + for (n = timer_list->next; n != timer_list; n = n->next) + { + t = rt_list_entry(n, struct rt_timer, list); + + /* + * It supposes that the new tick shall less than the half duration of + * tick max. + */ + if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX/2) + { + rt_list_insert_before(n, &(timer->list)); + break; + } + } + /* no found suitable position in timer list */ + if (n == timer_list) + { + rt_list_insert_before(n, &(timer->list)); + } + + 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_READY) - { - /* resume timer thread to check soft timer */ - rt_thread_resume(&timer_thread); - rt_schedule(); - } - } + if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) + { + /* check whether timer thread is ready */ + if (timer_thread.stat != RT_THREAD_READY) + { + /* resume timer thread to check soft timer */ + rt_thread_resume(&timer_thread); + rt_schedule(); + } + } #endif - return -RT_EOK; + return -RT_EOK; } RTM_EXPORT(rt_timer_start); @@ -302,28 +311,28 @@ RTM_EXPORT(rt_timer_start); */ rt_err_t rt_timer_stop(rt_timer_t timer) { - register rt_base_t level; + register rt_base_t level; - /* timer check */ - RT_ASSERT(timer != RT_NULL); - if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) - return -RT_ERROR; + /* timer check */ + RT_ASSERT(timer != RT_NULL); + if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + return -RT_ERROR; - RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent))); + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent))); - /* disable interrupt */ - level = rt_hw_interrupt_disable(); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); - /* remove it from timer list */ - rt_list_remove(&(timer->list)); + /* remove it from timer list */ + rt_list_remove(&(timer->list)); - /* enable interrupt */ - rt_hw_interrupt_enable(level); + /* enable interrupt */ + rt_hw_interrupt_enable(level); - /* change stat */ - timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + /* change stat */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - return RT_EOK; + return RT_EOK; } RTM_EXPORT(rt_timer_stop); @@ -338,29 +347,29 @@ RTM_EXPORT(rt_timer_stop); */ rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void *arg) { - /* timer check */ - RT_ASSERT(timer != RT_NULL); + /* timer check */ + RT_ASSERT(timer != RT_NULL); - switch (cmd) - { - case RT_TIMER_CTRL_GET_TIME: - *(rt_tick_t *)arg = timer->init_tick; - break; + 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_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_ONESHOT: + timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC; + break; - case RT_TIMER_CTRL_SET_PERIODIC: - 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; + return RT_EOK; } RTM_EXPORT(rt_timer_control); @@ -372,61 +381,61 @@ RTM_EXPORT(rt_timer_control); */ 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)) - { - t = rt_list_entry(rt_timer_list.next, struct rt_timer, list); - - /* - * 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_timeout_hook, (t)); - - /* remove timer from timer list firstly */ - rt_list_remove(&(t->list)); - - /* call timeout function */ - t->timeout_func(t->parameter); - - /* re-get tick */ - current_tick = rt_tick_get(); - - 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")); + 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)) + { + t = rt_list_entry(rt_timer_list.next, struct rt_timer, list); + + /* + * 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_timeout_hook, (t)); + + /* remove timer from timer list firstly */ + rt_list_remove(&(t->list)); + + /* call timeout function */ + t->timeout_func(t->parameter); + + /* re-get tick */ + current_tick = rt_tick_get(); + + 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")); } /** @@ -436,7 +445,7 @@ void rt_timer_check(void) */ rt_tick_t rt_timer_next_timeout_tick(void) { - return rt_timer_list_next_timeout(&rt_timer_list); + return rt_timer_list_next_timeout(&rt_timer_list); } #ifdef RT_USING_TIMER_SOFT @@ -446,84 +455,96 @@ rt_tick_t rt_timer_next_timeout_tick(void) */ 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(); - - for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list);) - { - t = rt_list_entry(n, struct rt_timer, list); - - /* - * 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_timeout_hook, (t)); - - /* move node to the next */ - n = n->next; - - /* remove timer from timer list firstly */ - rt_list_remove(&(t->list)); - - /* call timeout function */ - t->timeout_func(t->parameter); - - /* re-get tick */ - current_tick = rt_tick_get(); - - 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; /* not check anymore */ - } - - RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n")); + 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(); + + for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list);) + { + t = rt_list_entry(n, struct rt_timer, list); + + /* + * 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_timeout_hook, (t)); + + /* move node to the next */ + n = n->next; + + /* remove timer from timer list firstly */ + rt_list_remove(&(t->list)); + + /* call timeout function */ + t->timeout_func(t->parameter); + + /* re-get tick */ + current_tick = rt_tick_get(); + + 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; /* not check anymore */ + } + + RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n")); } /* system timer thread entry */ static void rt_thread_timer_entry(void *parameter) { - rt_tick_t next_timeout; - - while (1) - { - next_timeout = rt_timer_list_next_timeout(&rt_soft_timer_list); - if (next_timeout == RT_TICK_MAX) - { - rt_thread_suspend(rt_thread_self()); - rt_schedule(); - } - else - { - rt_thread_delay(next_timeout); - } - - /* lock scheduler */ - rt_enter_critical(); - /* check software timer */ - rt_soft_timer_check(); - /* unlock scheduler */ - rt_exit_critical(); - } + 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); + } + } + + /* lock scheduler */ + rt_enter_critical(); + /* check software timer */ + rt_soft_timer_check(); + /* unlock scheduler */ + rt_exit_critical(); + } } #endif @@ -547,17 +568,17 @@ void rt_system_timer_init(void) void rt_system_timer_thread_init(void) { #ifdef RT_USING_TIMER_SOFT - rt_list_init(&rt_soft_timer_list); + rt_list_init(&rt_soft_timer_list); - /* 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); + /* 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); + /* startup */ + rt_thread_startup(&timer_thread); #endif }