runtime_timer.c 9.9 KB

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