summaryrefslogtreecommitdiff
path: root/src/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/timer.c')
-rw-r--r--src/timer.c111
1 files changed, 67 insertions, 44 deletions
diff --git a/src/timer.c b/src/timer.c
index 28a5a9e494..d882711151 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;
@@ -221,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);
@@ -284,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);
@@ -321,7 +331,6 @@ rt_err_t rt_timer_start(rt_timer_t timer)
_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)));
@@ -332,9 +341,6 @@ rt_err_t rt_timer_start(rt_timer_t timer)
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)
{
@@ -408,7 +414,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_SUSPEND)
+ 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);
@@ -445,13 +452,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);
@@ -467,10 +473,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:
@@ -500,8 +509,12 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
/*timer is stop*/
*(rt_tick_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
}
- break;
+ break;
+
+ default:
+ break;
}
+ rt_hw_interrupt_enable(level);
return RT_EOK;
}
@@ -518,6 +531,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"));
@@ -541,7 +555,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);
@@ -551,6 +570,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;
+ }
+ rt_list_remove(&(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
{
@@ -558,14 +583,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 */
@@ -586,26 +605,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
@@ -615,26 +635,35 @@ 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;
+ }
+ rt_list_remove(&(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
{
@@ -642,17 +671,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"));
}