timer.c 22 KB

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