runtime_timer.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "runtime_timer.h"
  6. #if 1
  7. #define PRINT(...) (void)0
  8. #else
  9. #define PRINT printf
  10. #endif
  11. typedef struct _app_timer {
  12. struct _app_timer *next;
  13. uint32 id;
  14. uint32 interval;
  15. uint64 expiry;
  16. bool is_periodic;
  17. } app_timer_t;
  18. struct _timer_ctx {
  19. app_timer_t *app_timers;
  20. app_timer_t *idle_timers;
  21. app_timer_t *free_timers;
  22. uint32 max_timer_id;
  23. int pre_allocated;
  24. uint32 owner;
  25. /* mutex and condition */
  26. korp_cond cond;
  27. korp_mutex mutex;
  28. timer_callback_f timer_callback;
  29. check_timer_expiry_f refresh_checker;
  30. };
  31. uint64
  32. bh_get_tick_ms()
  33. {
  34. return os_time_get_boot_us() / 1000;
  35. }
  36. uint32
  37. bh_get_elpased_ms(uint32 *last_system_clock)
  38. {
  39. uint32 elapsed_ms;
  40. /* attention: the bh_get_tick_ms() returns a 64-bit integer, but
  41. bh_get_elpased_ms() is designed to use a 32-bit clock count */
  42. uint32 now = (uint32)bh_get_tick_ms();
  43. /* system clock overrun */
  44. if (now < *last_system_clock) {
  45. PRINT("system clock overrun!\n");
  46. elapsed_ms = now + (UINT32_MAX - *last_system_clock) + 1;
  47. }
  48. else {
  49. elapsed_ms = now - *last_system_clock;
  50. }
  51. *last_system_clock = now;
  52. return elapsed_ms;
  53. }
  54. static app_timer_t *
  55. remove_timer_from(timer_ctx_t ctx, uint32 timer_id, bool active_list)
  56. {
  57. app_timer_t **head, *prev, *t;
  58. os_mutex_lock(&ctx->mutex);
  59. if (active_list)
  60. head = &ctx->app_timers;
  61. else
  62. head = &ctx->idle_timers;
  63. t = *head;
  64. prev = NULL;
  65. while (t) {
  66. if (t->id == timer_id) {
  67. if (prev == NULL) {
  68. *head = t->next;
  69. PRINT("removed timer [%d] at head from list %d\n", t->id,
  70. active_list);
  71. }
  72. else {
  73. prev->next = t->next;
  74. PRINT("removed timer [%d] after [%d] from list %d\n", t->id,
  75. prev->id, active_list);
  76. }
  77. os_mutex_unlock(&ctx->mutex);
  78. if (active_list && prev == NULL && ctx->refresh_checker)
  79. ctx->refresh_checker(ctx);
  80. return t;
  81. }
  82. else {
  83. prev = t;
  84. t = t->next;
  85. }
  86. }
  87. os_mutex_unlock(&ctx->mutex);
  88. return NULL;
  89. }
  90. static app_timer_t *
  91. remove_timer(timer_ctx_t ctx, uint32 timer_id, bool *active)
  92. {
  93. app_timer_t *t = remove_timer_from(ctx, timer_id, true);
  94. if (t) {
  95. if (active)
  96. *active = true;
  97. return t;
  98. }
  99. if (active)
  100. *active = false;
  101. return remove_timer_from(ctx, timer_id, false);
  102. }
  103. static void
  104. reschedule_timer(timer_ctx_t ctx, app_timer_t *timer)
  105. {
  106. app_timer_t *t;
  107. app_timer_t *prev = NULL;
  108. os_mutex_lock(&ctx->mutex);
  109. t = ctx->app_timers;
  110. timer->next = NULL;
  111. timer->expiry = bh_get_tick_ms() + timer->interval;
  112. while (t) {
  113. if (timer->expiry < t->expiry) {
  114. if (prev == NULL) {
  115. timer->next = ctx->app_timers;
  116. ctx->app_timers = timer;
  117. PRINT("rescheduled timer [%d] at head\n", timer->id);
  118. }
  119. else {
  120. timer->next = t;
  121. prev->next = timer;
  122. PRINT("rescheduled timer [%d] after [%d]\n", timer->id,
  123. prev->id);
  124. }
  125. goto out;
  126. }
  127. else {
  128. prev = t;
  129. t = t->next;
  130. }
  131. }
  132. if (prev) {
  133. /* insert to the list end */
  134. prev->next = timer;
  135. PRINT("rescheduled timer [%d] at end, after [%d]\n", timer->id,
  136. prev->id);
  137. }
  138. else {
  139. /* insert at the beginning */
  140. bh_assert(ctx->app_timers == NULL);
  141. ctx->app_timers = timer;
  142. PRINT("rescheduled timer [%d] as first\n", timer->id);
  143. }
  144. out:
  145. os_mutex_unlock(&ctx->mutex);
  146. /* ensure the refresh_checker() is called out of the lock */
  147. if (prev == NULL && ctx->refresh_checker)
  148. ctx->refresh_checker(ctx);
  149. }
  150. static void
  151. release_timer(timer_ctx_t ctx, app_timer_t *t)
  152. {
  153. if (ctx->pre_allocated) {
  154. os_mutex_lock(&ctx->mutex);
  155. t->next = ctx->free_timers;
  156. ctx->free_timers = t;
  157. PRINT("recycle timer :%d\n", t->id);
  158. os_mutex_unlock(&ctx->mutex);
  159. }
  160. else {
  161. PRINT("destroy timer :%d\n", t->id);
  162. BH_FREE(t);
  163. }
  164. }
  165. void
  166. release_timer_list(app_timer_t **p_list)
  167. {
  168. app_timer_t *t = *p_list;
  169. while (t) {
  170. app_timer_t *next = t->next;
  171. PRINT("destroy timer list:%d\n", t->id);
  172. BH_FREE(t);
  173. t = next;
  174. }
  175. *p_list = NULL;
  176. }
  177. /*
  178. * API exposed
  179. */
  180. timer_ctx_t
  181. create_timer_ctx(timer_callback_f timer_handler,
  182. check_timer_expiry_f expiry_checker, int prealloc_num,
  183. unsigned int owner)
  184. {
  185. timer_ctx_t ctx = (timer_ctx_t)BH_MALLOC(sizeof(struct _timer_ctx));
  186. if (ctx == NULL)
  187. return NULL;
  188. memset(ctx, 0, sizeof(struct _timer_ctx));
  189. ctx->timer_callback = timer_handler;
  190. ctx->pre_allocated = prealloc_num;
  191. ctx->refresh_checker = expiry_checker;
  192. ctx->owner = owner;
  193. while (prealloc_num > 0) {
  194. app_timer_t *timer = (app_timer_t *)BH_MALLOC(sizeof(app_timer_t));
  195. if (timer == NULL)
  196. goto cleanup;
  197. memset(timer, 0, sizeof(*timer));
  198. timer->next = ctx->free_timers;
  199. ctx->free_timers = timer;
  200. prealloc_num--;
  201. }
  202. if (os_cond_init(&ctx->cond) != 0)
  203. goto cleanup;
  204. if (os_mutex_init(&ctx->mutex) != 0) {
  205. os_cond_destroy(&ctx->cond);
  206. goto cleanup;
  207. }
  208. PRINT("timer ctx created. pre-alloc: %d\n", ctx->pre_allocated);
  209. return ctx;
  210. cleanup:
  211. if (ctx) {
  212. release_timer_list(&ctx->free_timers);
  213. BH_FREE(ctx);
  214. }
  215. PRINT("timer ctx create failed\n");
  216. return NULL;
  217. }
  218. void
  219. destroy_timer_ctx(timer_ctx_t ctx)
  220. {
  221. while (ctx->free_timers) {
  222. void *tmp = ctx->free_timers;
  223. ctx->free_timers = ctx->free_timers->next;
  224. BH_FREE(tmp);
  225. }
  226. cleanup_app_timers(ctx);
  227. os_cond_destroy(&ctx->cond);
  228. os_mutex_destroy(&ctx->mutex);
  229. BH_FREE(ctx);
  230. }
  231. unsigned int
  232. timer_ctx_get_owner(timer_ctx_t ctx)
  233. {
  234. return ctx->owner;
  235. }
  236. void
  237. add_idle_timer(timer_ctx_t ctx, app_timer_t *timer)
  238. {
  239. os_mutex_lock(&ctx->mutex);
  240. timer->next = ctx->idle_timers;
  241. ctx->idle_timers = timer;
  242. os_mutex_unlock(&ctx->mutex);
  243. }
  244. uint32
  245. sys_create_timer(timer_ctx_t ctx, int interval, bool is_period, bool auto_start)
  246. {
  247. app_timer_t *timer;
  248. if (ctx->pre_allocated) {
  249. if (ctx->free_timers == NULL) {
  250. return (uint32)-1;
  251. }
  252. else {
  253. timer = ctx->free_timers;
  254. ctx->free_timers = timer->next;
  255. }
  256. }
  257. else {
  258. timer = (app_timer_t *)BH_MALLOC(sizeof(app_timer_t));
  259. if (timer == NULL)
  260. return (uint32)-1;
  261. }
  262. memset(timer, 0, sizeof(*timer));
  263. ctx->max_timer_id++;
  264. if (ctx->max_timer_id == (uint32)-1)
  265. ctx->max_timer_id++;
  266. timer->id = ctx->max_timer_id;
  267. timer->interval = (uint32)interval;
  268. timer->is_periodic = is_period;
  269. if (auto_start)
  270. reschedule_timer(ctx, timer);
  271. else
  272. add_idle_timer(ctx, timer);
  273. return timer->id;
  274. }
  275. bool
  276. sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id)
  277. {
  278. bool from_active;
  279. app_timer_t *t = remove_timer(ctx, timer_id, &from_active);
  280. if (t == NULL)
  281. return false;
  282. add_idle_timer(ctx, t);
  283. PRINT("sys_timer_stop called\n");
  284. return from_active;
  285. }
  286. bool
  287. sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id)
  288. {
  289. bool from_active;
  290. app_timer_t *t = remove_timer(ctx, timer_id, &from_active);
  291. if (t == NULL)
  292. return false;
  293. release_timer(ctx, t);
  294. PRINT("sys_timer_destroy called\n");
  295. return true;
  296. }
  297. bool
  298. sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval)
  299. {
  300. app_timer_t *t = remove_timer(ctx, timer_id, NULL);
  301. if (t == NULL)
  302. return false;
  303. t->interval = (uint32)interval;
  304. reschedule_timer(ctx, t);
  305. PRINT("sys_timer_restart called\n");
  306. return true;
  307. }
  308. /*
  309. * API called by the timer manager from another thread or the kernel timer
  310. * handler
  311. */
  312. /**
  313. * lookup the app queue by the module name
  314. * post a timeout message to the app queue
  315. */
  316. static void
  317. handle_expired_timers(timer_ctx_t ctx, app_timer_t *expired)
  318. {
  319. while (expired) {
  320. app_timer_t *t = expired;
  321. ctx->timer_callback(t->id, ctx->owner);
  322. /* get next expired timer first, since the following
  323. operation may change expired->next */
  324. expired = expired->next;
  325. if (t->is_periodic) {
  326. /* if it is repeating, then reschedule it */
  327. reschedule_timer(ctx, t);
  328. }
  329. else {
  330. /* else move it to idle list */
  331. add_idle_timer(ctx, t);
  332. }
  333. }
  334. }
  335. uint32
  336. get_expiry_ms(timer_ctx_t ctx)
  337. {
  338. uint32 ms_to_next_expiry;
  339. uint64 now = bh_get_tick_ms();
  340. os_mutex_lock(&ctx->mutex);
  341. if (ctx->app_timers == NULL)
  342. ms_to_next_expiry = (uint32)-1;
  343. else if (ctx->app_timers->expiry >= now)
  344. ms_to_next_expiry = (uint32)(ctx->app_timers->expiry - now);
  345. else
  346. ms_to_next_expiry = 0;
  347. os_mutex_unlock(&ctx->mutex);
  348. return ms_to_next_expiry;
  349. }
  350. uint32
  351. check_app_timers(timer_ctx_t ctx)
  352. {
  353. app_timer_t *t, *expired = NULL, *expired_end = NULL;
  354. uint64 now = bh_get_tick_ms();
  355. os_mutex_lock(&ctx->mutex);
  356. t = ctx->app_timers;
  357. while (t) {
  358. if (now >= t->expiry) {
  359. ctx->app_timers = t->next;
  360. /* append t to the end of expired list */
  361. t->next = NULL;
  362. if (!expired_end) {
  363. expired = expired_end = t;
  364. }
  365. else {
  366. expired_end->next = t;
  367. expired_end = t;
  368. }
  369. t = ctx->app_timers;
  370. }
  371. else {
  372. break;
  373. }
  374. }
  375. os_mutex_unlock(&ctx->mutex);
  376. handle_expired_timers(ctx, expired);
  377. return get_expiry_ms(ctx);
  378. }
  379. void
  380. cleanup_app_timers(timer_ctx_t ctx)
  381. {
  382. os_mutex_lock(&ctx->mutex);
  383. release_timer_list(&ctx->app_timers);
  384. release_timer_list(&ctx->idle_timers);
  385. os_mutex_unlock(&ctx->mutex);
  386. }