timer.c 23 KB

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