Skip to content

Commit 1c6700a

Browse files
committed
[kernel] fix the timer issue
1 parent c758168 commit 1c6700a

File tree

1 file changed

+58
-27
lines changed

1 file changed

+58
-27
lines changed

src/timer.c

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
2626

2727
#ifdef RT_USING_TIMER_SOFT
28+
29+
#define RT_SOFT_TIMER_IDLE 1
30+
#define RT_SOFT_TIMER_BUSY 0
31+
2832
#ifndef RT_TIMER_THREAD_STACK_SIZE
2933
#define RT_TIMER_THREAD_STACK_SIZE 512
3034
#endif
@@ -33,6 +37,8 @@ static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
3337
#define RT_TIMER_THREAD_PRIO 0
3438
#endif
3539

40+
/* soft timer status */
41+
static rt_uint8_t soft_timer_status = RT_SOFT_TIMER_IDLE;
3642
/* soft timer list */
3743
static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
3844
static struct rt_thread timer_thread;
@@ -221,6 +227,8 @@ rt_err_t rt_timer_detach(rt_timer_t timer)
221227
level = rt_hw_interrupt_disable();
222228

223229
_rt_timer_remove(timer);
230+
/* stop timer */
231+
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
224232

225233
/* enable interrupt */
226234
rt_hw_interrupt_enable(level);
@@ -284,6 +292,8 @@ rt_err_t rt_timer_delete(rt_timer_t timer)
284292
level = rt_hw_interrupt_disable();
285293

286294
_rt_timer_remove(timer);
295+
/* stop timer */
296+
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
287297

288298
/* enable interrupt */
289299
rt_hw_interrupt_enable(level);
@@ -408,7 +418,8 @@ rt_err_t rt_timer_start(rt_timer_t timer)
408418
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
409419
{
410420
/* check whether timer thread is ready */
411-
if ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
421+
if ((soft_timer_status == RT_SOFT_TIMER_IDLE) &&
422+
((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
412423
{
413424
/* resume timer thread to check soft timer */
414425
rt_thread_resume(&timer_thread);
@@ -445,13 +456,12 @@ rt_err_t rt_timer_stop(rt_timer_t timer)
445456
level = rt_hw_interrupt_disable();
446457

447458
_rt_timer_remove(timer);
459+
/* change status */
460+
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
448461

449462
/* enable interrupt */
450463
rt_hw_interrupt_enable(level);
451464

452-
/* change stat */
453-
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
454-
455465
return RT_EOK;
456466
}
457467
RTM_EXPORT(rt_timer_stop);
@@ -467,10 +477,13 @@ RTM_EXPORT(rt_timer_stop);
467477
*/
468478
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
469479
{
480+
register rt_base_t level;
481+
470482
/* timer check */
471483
RT_ASSERT(timer != RT_NULL);
472484
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
473485

486+
level = rt_hw_interrupt_disable();
474487
switch (cmd)
475488
{
476489
case RT_TIMER_CTRL_GET_TIME:
@@ -505,6 +518,7 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
505518
default:
506519
break;
507520
}
521+
rt_hw_interrupt_enable(level);
508522

509523
return RT_EOK;
510524
}
@@ -521,6 +535,7 @@ void rt_timer_check(void)
521535
struct rt_timer *t;
522536
rt_tick_t current_tick;
523537
register rt_base_t level;
538+
rt_list_t list = RT_LIST_OBJECT_INIT(list);
524539

525540
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
526541

@@ -544,7 +559,12 @@ void rt_timer_check(void)
544559

545560
/* remove timer from timer list firstly */
546561
_rt_timer_remove(t);
547-
562+
if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC))
563+
{
564+
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
565+
}
566+
/* add timer to temporary list */
567+
rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
548568
/* call timeout function */
549569
t->timeout_func(t->parameter);
550570

@@ -554,21 +574,21 @@ void rt_timer_check(void)
554574
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
555575
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
556576

577+
/* Check whether the timer object is detached or started again */
578+
if (rt_list_isempty(&list))
579+
{
580+
continue;
581+
}
582+
557583
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
558584
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
559585
{
560586
/* start it */
561587
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
562588
rt_timer_start(t);
563589
}
564-
else
565-
{
566-
/* stop timer */
567-
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
568-
}
569590
}
570-
else
571-
break;
591+
else break;
572592
}
573593

574594
/* enable interrupt */
@@ -589,18 +609,20 @@ rt_tick_t rt_timer_next_timeout_tick(void)
589609

590610
#ifdef RT_USING_TIMER_SOFT
591611
/**
592-
* This function will check timer list, if a timeout event happens, the
612+
* This function will check software-timer list, if a timeout event happens, the
593613
* corresponding timeout function will be invoked.
594614
*/
595615
void rt_soft_timer_check(void)
596616
{
597617
rt_tick_t current_tick;
598618
struct rt_timer *t;
619+
register rt_base_t level;
620+
rt_list_t list = RT_LIST_OBJECT_INIT(list);
599621

600622
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));
601623

602-
/* lock scheduler */
603-
rt_enter_critical();
624+
/* disable interrupt */
625+
level = rt_hw_interrupt_disable();
604626

605627
while (!rt_list_isempty(&rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
606628
{
@@ -619,17 +641,32 @@ void rt_soft_timer_check(void)
619641

620642
/* remove timer from timer list firstly */
621643
_rt_timer_remove(t);
644+
if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC))
645+
{
646+
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
647+
}
648+
/* add timer to temporary list */
649+
rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
650+
651+
soft_timer_status = RT_SOFT_TIMER_BUSY;
652+
/* enable interrupt */
653+
rt_hw_interrupt_enable(level);
622654

623-
/* not lock scheduler when performing timeout function */
624-
rt_exit_critical();
625655
/* call timeout function */
626656
t->timeout_func(t->parameter);
627657

628658
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
629659
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
630660

631-
/* lock scheduler */
632-
rt_enter_critical();
661+
/* disable interrupt */
662+
level = rt_hw_interrupt_disable();
663+
664+
soft_timer_status = RT_SOFT_TIMER_IDLE;
665+
/* Check whether the timer object is detached or started again */
666+
if (rt_list_isempty(&list))
667+
{
668+
continue;
669+
}
633670

634671
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
635672
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
@@ -638,17 +675,11 @@ void rt_soft_timer_check(void)
638675
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
639676
rt_timer_start(t);
640677
}
641-
else
642-
{
643-
/* stop timer */
644-
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
645-
}
646678
}
647679
else break; /* not check anymore */
648680
}
649-
650-
/* unlock scheduler */
651-
rt_exit_critical();
681+
/* enable interrupt */
682+
rt_hw_interrupt_enable(level);
652683

653684
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
654685
}

0 commit comments

Comments
 (0)