xref: /nrf52832-nimble/rt-thread/src/timer.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2006-03-12     Bernard      first version
9  * 2006-04-29     Bernard      implement thread timer
10  * 2006-06-04     Bernard      implement rt_timer_control
11  * 2006-08-10     Bernard      fix the periodic timer bug
12  * 2006-09-03     Bernard      implement rt_timer_detach
13  * 2009-11-11     LiJin        add soft timer
14  * 2010-05-12     Bernard      fix the timer check bug.
15  * 2010-11-02     Charlie      re-implement tick overflow issue
16  * 2012-12-15     Bernard      fix the next timeout issue in soft timer
17  * 2014-07-12     Bernard      does not lock scheduler when invoking soft-timer
18  *                             timeout function.
19  */
20 
21 #include <rtthread.h>
22 #include <rthw.h>
23 
24 /* hard timer list */
25 static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
26 
27 #ifdef RT_USING_TIMER_SOFT
28 #ifndef RT_TIMER_THREAD_STACK_SIZE
29 #define RT_TIMER_THREAD_STACK_SIZE     512
30 #endif
31 
32 #ifndef RT_TIMER_THREAD_PRIO
33 #define RT_TIMER_THREAD_PRIO           0
34 #endif
35 
36 /* soft timer list */
37 static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
38 static struct rt_thread timer_thread;
39 ALIGN(RT_ALIGN_SIZE)
40 static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
41 #endif
42 
43 #ifdef RT_USING_HOOK
44 extern void (*rt_object_take_hook)(struct rt_object *object);
45 extern void (*rt_object_put_hook)(struct rt_object *object);
46 static void (*rt_timer_enter_hook)(struct rt_timer *timer);
47 static void (*rt_timer_exit_hook)(struct rt_timer *timer);
48 
49 /**
50  * @addtogroup Hook
51  */
52 
53 /**@{*/
54 
55 /**
56  * This function will set a hook function, which will be invoked when enter
57  * timer timeout callback function.
58  *
59  * @param hook the hook function
60  */
rt_timer_enter_sethook(void (* hook)(struct rt_timer * timer))61 void rt_timer_enter_sethook(void (*hook)(struct rt_timer *timer))
62 {
63     rt_timer_enter_hook = hook;
64 }
65 
66 /**
67  * This function will set a hook function, which will be invoked when exit
68  * timer timeout callback function.
69  *
70  * @param hook the hook function
71  */
rt_timer_exit_sethook(void (* hook)(struct rt_timer * timer))72 void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer))
73 {
74     rt_timer_exit_hook = hook;
75 }
76 
77 /**@}*/
78 #endif
79 
_rt_timer_init(rt_timer_t timer,void (* timeout)(void * parameter),void * parameter,rt_tick_t time,rt_uint8_t flag)80 static void _rt_timer_init(rt_timer_t timer,
81                            void (*timeout)(void *parameter),
82                            void      *parameter,
83                            rt_tick_t  time,
84                            rt_uint8_t flag)
85 {
86     int i;
87 
88     /* set flag */
89     timer->parent.flag  = flag;
90 
91     /* set deactivated */
92     timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
93 
94     timer->timeout_func = timeout;
95     timer->parameter    = parameter;
96 
97     timer->timeout_tick = 0;
98     timer->init_tick    = time;
99 
100     /* initialize timer list */
101     for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
102     {
103         rt_list_init(&(timer->row[i]));
104     }
105 }
106 
107 /* the fist timer always in the last row */
rt_timer_list_next_timeout(rt_list_t timer_list[])108 static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[])
109 {
110     struct rt_timer *timer;
111 
112     if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
113         return RT_TICK_MAX;
114 
115     timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
116                           struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
117 
118     return timer->timeout_tick;
119 }
120 
_rt_timer_remove(rt_timer_t timer)121 rt_inline void _rt_timer_remove(rt_timer_t timer)
122 {
123     int i;
124 
125     for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
126     {
127         rt_list_remove(&timer->row[i]);
128     }
129 }
130 
131 #if RT_DEBUG_TIMER
rt_timer_count_height(struct rt_timer * timer)132 static int rt_timer_count_height(struct rt_timer *timer)
133 {
134     int i, cnt = 0;
135 
136     for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
137     {
138         if (!rt_list_isempty(&timer->row[i]))
139             cnt++;
140     }
141     return cnt;
142 }
143 
rt_timer_dump(rt_list_t timer_heads[])144 void rt_timer_dump(rt_list_t timer_heads[])
145 {
146     rt_list_t *list;
147 
148     for (list = timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
149          list != &timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1];
150          list = list->next)
151     {
152         struct rt_timer *timer = rt_list_entry(list,
153                                                struct rt_timer,
154                                                row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
155         rt_kprintf("%d", rt_timer_count_height(timer));
156     }
157     rt_kprintf("\n");
158 }
159 #endif
160 
161 /**
162  * @addtogroup Clock
163  */
164 
165 /**@{*/
166 
167 /**
168  * This function will initialize a timer, normally this function is used to
169  * initialize a static timer object.
170  *
171  * @param timer the static timer object
172  * @param name the name of timer
173  * @param timeout the timeout function
174  * @param parameter the parameter of timeout function
175  * @param time the tick of timer
176  * @param flag the flag of timer
177  */
rt_timer_init(rt_timer_t timer,const char * name,void (* timeout)(void * parameter),void * parameter,rt_tick_t time,rt_uint8_t flag)178 void rt_timer_init(rt_timer_t  timer,
179                    const char *name,
180                    void (*timeout)(void *parameter),
181                    void       *parameter,
182                    rt_tick_t   time,
183                    rt_uint8_t  flag)
184 {
185     /* timer check */
186     RT_ASSERT(timer != RT_NULL);
187 
188     /* timer object initialization */
189     rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
190 
191     _rt_timer_init(timer, timeout, parameter, time, flag);
192 }
193 RTM_EXPORT(rt_timer_init);
194 
195 /**
196  * This function will detach a timer from timer management.
197  *
198  * @param timer the static timer object
199  *
200  * @return the operation status, RT_EOK on OK; RT_ERROR on error
201  */
rt_timer_detach(rt_timer_t timer)202 rt_err_t rt_timer_detach(rt_timer_t timer)
203 {
204     register rt_base_t level;
205 
206     /* timer check */
207     RT_ASSERT(timer != RT_NULL);
208     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
209     RT_ASSERT(rt_object_is_systemobject(&timer->parent));
210 
211     /* disable interrupt */
212     level = rt_hw_interrupt_disable();
213 
214     _rt_timer_remove(timer);
215 
216     /* enable interrupt */
217     rt_hw_interrupt_enable(level);
218 
219     rt_object_detach((rt_object_t)timer);
220 
221     return RT_EOK;
222 }
223 RTM_EXPORT(rt_timer_detach);
224 
225 #ifdef RT_USING_HEAP
226 /**
227  * This function will create a timer
228  *
229  * @param name the name of timer
230  * @param timeout the timeout function
231  * @param parameter the parameter of timeout function
232  * @param time the tick of timer
233  * @param flag the flag of timer
234  *
235  * @return the created timer object
236  */
rt_timer_create(const char * name,void (* timeout)(void * parameter),void * parameter,rt_tick_t time,rt_uint8_t flag)237 rt_timer_t rt_timer_create(const char *name,
238                            void (*timeout)(void *parameter),
239                            void       *parameter,
240                            rt_tick_t   time,
241                            rt_uint8_t  flag)
242 {
243     struct rt_timer *timer;
244 
245     /* allocate a object */
246     timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name);
247     if (timer == RT_NULL)
248     {
249         return RT_NULL;
250     }
251 
252     _rt_timer_init(timer, timeout, parameter, time, flag);
253 
254     return timer;
255 }
256 RTM_EXPORT(rt_timer_create);
257 
258 /**
259  * This function will delete a timer and release timer memory
260  *
261  * @param timer the timer to be deleted
262  *
263  * @return the operation status, RT_EOK on OK; RT_ERROR on error
264  */
rt_timer_delete(rt_timer_t timer)265 rt_err_t rt_timer_delete(rt_timer_t timer)
266 {
267     register rt_base_t level;
268 
269     /* timer check */
270     RT_ASSERT(timer != RT_NULL);
271     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
272     RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE);
273 
274     /* disable interrupt */
275     level = rt_hw_interrupt_disable();
276 
277     _rt_timer_remove(timer);
278 
279     /* enable interrupt */
280     rt_hw_interrupt_enable(level);
281 
282     rt_object_delete((rt_object_t)timer);
283 
284     return RT_EOK;
285 }
286 RTM_EXPORT(rt_timer_delete);
287 #endif
288 
289 /**
290  * This function will start the timer
291  *
292  * @param timer the timer to be started
293  *
294  * @return the operation status, RT_EOK on OK, -RT_ERROR on error
295  */
rt_timer_start(rt_timer_t timer)296 rt_err_t rt_timer_start(rt_timer_t timer)
297 {
298     unsigned int row_lvl;
299     rt_list_t *timer_list;
300     register rt_base_t level;
301     rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
302     unsigned int tst_nr;
303     static unsigned int random_nr;
304 
305     /* timer check */
306     RT_ASSERT(timer != RT_NULL);
307     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
308 
309     /* stop timer firstly */
310     level = rt_hw_interrupt_disable();
311     /* remove timer from list */
312     _rt_timer_remove(timer);
313     /* change status of timer */
314     timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
315     rt_hw_interrupt_enable(level);
316 
317     RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));
318 
319     /*
320      * get timeout tick,
321      * the max timeout tick shall not great than RT_TICK_MAX/2
322      */
323     RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2);
324     timer->timeout_tick = rt_tick_get() + timer->init_tick;
325 
326     /* disable interrupt */
327     level = rt_hw_interrupt_disable();
328 
329 #ifdef RT_USING_TIMER_SOFT
330     if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
331     {
332         /* insert timer to soft timer list */
333         timer_list = rt_soft_timer_list;
334     }
335     else
336 #endif
337     {
338         /* insert timer to system timer list */
339         timer_list = rt_timer_list;
340     }
341 
342     row_head[0]  = &timer_list[0];
343     for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
344     {
345         for (; row_head[row_lvl] != timer_list[row_lvl].prev;
346              row_head[row_lvl]  = row_head[row_lvl]->next)
347         {
348             struct rt_timer *t;
349             rt_list_t *p = row_head[row_lvl]->next;
350 
351             /* fix up the entry pointer */
352             t = rt_list_entry(p, struct rt_timer, row[row_lvl]);
353 
354             /* If we have two timers that timeout at the same time, it's
355              * preferred that the timer inserted early get called early.
356              * So insert the new timer to the end the the some-timeout timer
357              * list.
358              */
359             if ((t->timeout_tick - timer->timeout_tick) == 0)
360             {
361                 continue;
362             }
363             else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2)
364             {
365                 break;
366             }
367         }
368         if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1)
369             row_head[row_lvl + 1] = row_head[row_lvl] + 1;
370     }
371 
372     /* Interestingly, this super simple timer insert counter works very very
373      * well on distributing the list height uniformly. By means of "very very
374      * well", I mean it beats the randomness of timer->timeout_tick very easily
375      * (actually, the timeout_tick is not random and easy to be attacked). */
376     random_nr++;
377     tst_nr = random_nr;
378 
379     rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1],
380                          &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
381     for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
382     {
383         if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK))
384             rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl],
385                                  &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl]));
386         else
387             break;
388         /* Shift over the bits we have tested. Works well with 1 bit and 2
389          * bits. */
390         tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1;
391     }
392 
393     timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
394 
395     /* enable interrupt */
396     rt_hw_interrupt_enable(level);
397 
398 #ifdef RT_USING_TIMER_SOFT
399     if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
400     {
401         /* check whether timer thread is ready */
402         if ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
403         {
404             /* resume timer thread to check soft timer */
405             rt_thread_resume(&timer_thread);
406             rt_schedule();
407         }
408     }
409 #endif
410 
411     return RT_EOK;
412 }
413 RTM_EXPORT(rt_timer_start);
414 
415 /**
416  * This function will stop the timer
417  *
418  * @param timer the timer to be stopped
419  *
420  * @return the operation status, RT_EOK on OK, -RT_ERROR on error
421  */
rt_timer_stop(rt_timer_t timer)422 rt_err_t rt_timer_stop(rt_timer_t timer)
423 {
424     register rt_base_t level;
425 
426     /* timer check */
427     RT_ASSERT(timer != RT_NULL);
428     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
429 
430     if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
431         return -RT_ERROR;
432 
433     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent)));
434 
435     /* disable interrupt */
436     level = rt_hw_interrupt_disable();
437 
438     _rt_timer_remove(timer);
439 
440     /* enable interrupt */
441     rt_hw_interrupt_enable(level);
442 
443     /* change stat */
444     timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
445 
446     return RT_EOK;
447 }
448 RTM_EXPORT(rt_timer_stop);
449 
450 /**
451  * This function will get or set some options of the timer
452  *
453  * @param timer the timer to be get or set
454  * @param cmd the control command
455  * @param arg the argument
456  *
457  * @return RT_EOK
458  */
rt_timer_control(rt_timer_t timer,int cmd,void * arg)459 rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
460 {
461     /* timer check */
462     RT_ASSERT(timer != RT_NULL);
463     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
464 
465     switch (cmd)
466     {
467     case RT_TIMER_CTRL_GET_TIME:
468         *(rt_tick_t *)arg = timer->init_tick;
469         break;
470 
471     case RT_TIMER_CTRL_SET_TIME:
472         timer->init_tick = *(rt_tick_t *)arg;
473         break;
474 
475     case RT_TIMER_CTRL_SET_ONESHOT:
476         timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
477         break;
478 
479     case RT_TIMER_CTRL_SET_PERIODIC:
480         timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
481         break;
482     }
483 
484     return RT_EOK;
485 }
486 RTM_EXPORT(rt_timer_control);
487 
488 /**
489  * This function will check timer list, if a timeout event happens, the
490  * corresponding timeout function will be invoked.
491  *
492  * @note this function shall be invoked in operating system timer interrupt.
493  */
rt_timer_check(void)494 void rt_timer_check(void)
495 {
496     struct rt_timer *t;
497     rt_tick_t current_tick;
498     register rt_base_t level;
499 
500     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
501 
502     current_tick = rt_tick_get();
503 
504     /* disable interrupt */
505     level = rt_hw_interrupt_disable();
506 
507     while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
508     {
509         t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
510                           struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
511 
512         /*
513          * It supposes that the new tick shall less than the half duration of
514          * tick max.
515          */
516         if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
517         {
518             RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
519 
520             /* remove timer from timer list firstly */
521             _rt_timer_remove(t);
522 
523             /* call timeout function */
524             t->timeout_func(t->parameter);
525 
526             /* re-get tick */
527             current_tick = rt_tick_get();
528 
529             RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
530             RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
531 
532             if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
533                 (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
534             {
535                 /* start it */
536                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
537                 rt_timer_start(t);
538             }
539             else
540             {
541                 /* stop timer */
542                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
543             }
544         }
545         else
546             break;
547     }
548 
549     /* enable interrupt */
550     rt_hw_interrupt_enable(level);
551 
552     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n"));
553 }
554 
555 /**
556  * This function will return the next timeout tick in the system.
557  *
558  * @return the next timeout tick in the system
559  */
rt_timer_next_timeout_tick(void)560 rt_tick_t rt_timer_next_timeout_tick(void)
561 {
562     return rt_timer_list_next_timeout(rt_timer_list);
563 }
564 
565 #ifdef RT_USING_TIMER_SOFT
566 /**
567  * This function will check timer list, if a timeout event happens, the
568  * corresponding timeout function will be invoked.
569  */
rt_soft_timer_check(void)570 void rt_soft_timer_check(void)
571 {
572     rt_tick_t current_tick;
573     rt_list_t *n;
574     struct rt_timer *t;
575 
576     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));
577 
578     current_tick = rt_tick_get();
579 
580     /* lock scheduler */
581     rt_enter_critical();
582 
583     for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
584          n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);)
585     {
586         t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
587 
588         /*
589          * It supposes that the new tick shall less than the half duration of
590          * tick max.
591          */
592         if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
593         {
594             RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
595 
596             /* move node to the next */
597             n = n->next;
598 
599             /* remove timer from timer list firstly */
600             _rt_timer_remove(t);
601 
602             /* not lock scheduler when performing timeout function */
603             rt_exit_critical();
604             /* call timeout function */
605             t->timeout_func(t->parameter);
606 
607             /* re-get tick */
608             current_tick = rt_tick_get();
609 
610             RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
611             RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
612 
613             /* lock scheduler */
614             rt_enter_critical();
615 
616             if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
617                 (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
618             {
619                 /* start it */
620                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
621                 rt_timer_start(t);
622             }
623             else
624             {
625                 /* stop timer */
626                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
627             }
628         }
629         else break; /* not check anymore */
630     }
631 
632     /* unlock scheduler */
633     rt_exit_critical();
634 
635     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
636 }
637 
638 /* system timer thread entry */
rt_thread_timer_entry(void * parameter)639 static void rt_thread_timer_entry(void *parameter)
640 {
641     rt_tick_t next_timeout;
642 
643     while (1)
644     {
645         /* get the next timeout tick */
646         next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list);
647         if (next_timeout == RT_TICK_MAX)
648         {
649             /* no software timer exist, suspend self. */
650             rt_thread_suspend(rt_thread_self());
651             rt_schedule();
652         }
653         else
654         {
655             rt_tick_t current_tick;
656 
657             /* get current tick */
658             current_tick = rt_tick_get();
659 
660             if ((next_timeout - current_tick) < RT_TICK_MAX / 2)
661             {
662                 /* get the delta timeout tick */
663                 next_timeout = next_timeout - current_tick;
664                 rt_thread_delay(next_timeout);
665             }
666         }
667 
668         /* check software timer */
669         rt_soft_timer_check();
670     }
671 }
672 #endif
673 
674 /**
675  * @ingroup SystemInit
676  *
677  * This function will initialize system timer
678  */
rt_system_timer_init(void)679 void rt_system_timer_init(void)
680 {
681     int i;
682 
683     for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++)
684     {
685         rt_list_init(rt_timer_list + i);
686     }
687 }
688 
689 /**
690  * @ingroup SystemInit
691  *
692  * This function will initialize system timer thread
693  */
rt_system_timer_thread_init(void)694 void rt_system_timer_thread_init(void)
695 {
696 #ifdef RT_USING_TIMER_SOFT
697     int i;
698 
699     for (i = 0;
700          i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]);
701          i++)
702     {
703         rt_list_init(rt_soft_timer_list + i);
704     }
705 
706     /* start software timer thread */
707     rt_thread_init(&timer_thread,
708                    "timer",
709                    rt_thread_timer_entry,
710                    RT_NULL,
711                    &timer_thread_stack[0],
712                    sizeof(timer_thread_stack),
713                    RT_TIMER_THREAD_PRIO,
714                    10);
715 
716     /* startup */
717     rt_thread_startup(&timer_thread);
718 #endif
719 }
720 
721 /**@}*/
722