summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBernard Xiong <[email protected]>2020-09-30 23:50:18 +0800
committerBernard Xiong <[email protected]>2020-09-30 23:50:18 +0800
commit1c6700acfdc6df71e14361d1c586ca32bb731e44 (patch)
tree24d30d61d94aa9b4dfc04628f01b68cbf5315300 /src
parentc758168877bef84355905c6e80f79a5abd6b16fc (diff)
[kernel] fix the timer issue
Diffstat (limited to 'src')
-rw-r--r--src/timer.c85
1 files changed, 58 insertions, 27 deletions
diff --git a/src/timer.c b/src/timer.c
index 52707f2306..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;
@@ -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);
@@ -408,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_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 +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);
@@ -467,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:
@@ -505,6 +518,7 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
default:
break;
}
+ rt_hw_interrupt_enable(level);
return RT_EOK;
}
@@ -521,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"));
@@ -544,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);
@@ -554,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))
{
@@ -561,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 */
@@ -589,18 +609,20 @@ 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;
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"));
- /* lock scheduler */
- rt_enter_critical();
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
while (!rt_list_isempty(&rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
{
@@ -619,17 +641,32 @@ void rt_soft_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]));
+
+ 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);
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))
@@ -638,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"));
}