Skip to content

Commit

Permalink
[kernel] fix the timer issue
Browse files Browse the repository at this point in the history
  • Loading branch information
BernardXiong committed Sep 30, 2020
1 parent c758168 commit 1c6700a
Showing 1 changed file with 58 additions and 27 deletions.
85 changes: 58 additions & 27 deletions src/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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:
Expand Down Expand Up @@ -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;
}
Expand All @@ -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"));

Expand All @@ -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);

Expand All @@ -554,21 +574,21 @@ 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))
{
/* 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;
else break;
}

/* enable interrupt */
Expand All @@ -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]))
{
Expand All @@ -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))
Expand All @@ -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"));
}
Expand Down

0 comments on commit 1c6700a

Please sign in to comment.