runtime_timer.c 11 KB

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