diff options
Diffstat (limited to 'src/timer.c')
| -rw-r--r-- | src/timer.c | 137 |
1 files changed, 93 insertions, 44 deletions
diff --git a/src/timer.c b/src/timer.c index fd938065db..4b9003794c 100644 --- a/src/timer.c +++ b/src/timer.c @@ -25,6 +25,10 @@ static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; #ifdef RT_USING_TIMER_SOFT + +#define RT_SOFT_TIMER_IDLE 1 +#define RT_SOFT_TIMER_BUSY 0 + #ifndef RT_TIMER_THREAD_STACK_SIZE #define RT_TIMER_THREAD_STACK_SIZE 512 #endif @@ -33,6 +37,8 @@ static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; #define RT_TIMER_THREAD_PRIO 0 #endif +/* soft timer status */ +static rt_uint8_t soft_timer_status = RT_SOFT_TIMER_IDLE; /* soft timer list */ static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; static struct rt_thread timer_thread; @@ -108,14 +114,23 @@ static void _rt_timer_init(rt_timer_t timer, static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[]) { struct rt_timer *timer; + register rt_base_t level; + rt_tick_t timeout_tick = RT_TICK_MAX; - if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) - return RT_TICK_MAX; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); - timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, - struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + if (!rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) + { + timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, + struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + timeout_tick = timer->timeout_tick; + } - return timer->timeout_tick; + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return timeout_tick; } rt_inline void _rt_timer_remove(rt_timer_t timer) @@ -212,6 +227,8 @@ rt_err_t rt_timer_detach(rt_timer_t timer) level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -275,6 +292,8 @@ rt_err_t rt_timer_delete(rt_timer_t timer) level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -399,7 +418,8 @@ rt_err_t rt_timer_start(rt_timer_t timer) 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_READY) + if ((soft_timer_status == RT_SOFT_TIMER_IDLE) && + ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)) { /* resume timer thread to check soft timer */ rt_thread_resume(&timer_thread); @@ -436,13 +456,12 @@ rt_err_t rt_timer_stop(rt_timer_t timer) level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); + /* change status */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* enable interrupt */ rt_hw_interrupt_enable(level); - /* change stat */ - timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - return RT_EOK; } RTM_EXPORT(rt_timer_stop); @@ -458,10 +477,13 @@ RTM_EXPORT(rt_timer_stop); */ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg) { + register rt_base_t level; + /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); + level = rt_hw_interrupt_disable(); switch (cmd) { case RT_TIMER_CTRL_GET_TIME: @@ -479,7 +501,24 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg) case RT_TIMER_CTRL_SET_PERIODIC: timer->parent.flag |= RT_TIMER_FLAG_PERIODIC; break; + + case RT_TIMER_CTRL_GET_STATE: + if(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + { + /*timer is start and run*/ + *(rt_tick_t *)arg = RT_TIMER_FLAG_ACTIVATED; + } + else + { + /*timer is stop*/ + *(rt_tick_t *)arg = RT_TIMER_FLAG_DEACTIVATED; + } + break; + + default: + break; } + rt_hw_interrupt_enable(level); return RT_EOK; } @@ -496,6 +535,7 @@ void rt_timer_check(void) struct rt_timer *t; rt_tick_t current_tick; register rt_base_t level; + rt_list_t list = RT_LIST_OBJECT_INIT(list); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n")); @@ -519,7 +559,12 @@ void rt_timer_check(void) /* remove timer from timer list firstly */ _rt_timer_remove(t); - + if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC)) + { + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + } + /* add timer to temporary list */ + rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); /* call timeout function */ t->timeout_func(t->parameter); @@ -529,6 +574,12 @@ void rt_timer_check(void) RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t)); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); + /* Check whether the timer object is detached or started again */ + if (rt_list_isempty(&list)) + { + continue; + } + if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) { @@ -536,14 +587,8 @@ void rt_timer_check(void) t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; rt_timer_start(t); } - else - { - /* stop timer */ - t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - } } - else - break; + else break; } /* enable interrupt */ @@ -564,26 +609,27 @@ rt_tick_t rt_timer_next_timeout_tick(void) #ifdef RT_USING_TIMER_SOFT /** - * This function will check timer list, if a timeout event happens, the + * This function will check software-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; + register rt_base_t level; + rt_list_t list = RT_LIST_OBJECT_INIT(list); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n")); - current_tick = rt_tick_get(); - - /* lock scheduler */ - rt_enter_critical(); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); - for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next; - n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);) + while (!rt_list_isempty(&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]); + t = rt_list_entry(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, + struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + + current_tick = rt_tick_get(); /* * It supposes that the new tick shall less than the half duration of @@ -593,25 +639,34 @@ void rt_soft_timer_check(void) { 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); + if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC)) + { + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + } + /* add timer to temporary list */ + rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); + + soft_timer_status = RT_SOFT_TIMER_BUSY; + /* enable interrupt */ + rt_hw_interrupt_enable(level); - /* 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(); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + soft_timer_status = RT_SOFT_TIMER_IDLE; + /* Check whether the timer object is detached or started again */ + if (rt_list_isempty(&list)) + { + continue; + } if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) @@ -620,17 +675,11 @@ void rt_soft_timer_check(void) 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(); + /* enable interrupt */ + rt_hw_interrupt_enable(level); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n")); } |
