runtime_timer.c 10 KB

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