timer.c 26 KB

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