| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- /*
- * Copyright (C) 2019 Intel Corporation. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- #include "runtime_timer.h"
- #if 1
- #define PRINT(...) (void)0
- #else
- #define PRINT printf
- #endif
- typedef struct _app_timer {
- struct _app_timer *next;
- uint32 id;
- uint32 interval;
- uint64 expiry;
- bool is_periodic;
- } app_timer_t;
- struct _timer_ctx {
- app_timer_t *app_timers;
- app_timer_t *idle_timers;
- app_timer_t *free_timers;
- uint32 max_timer_id;
- int pre_allocated;
- uint32 owner;
- /* mutex and condition */
- korp_cond cond;
- korp_mutex mutex;
- timer_callback_f timer_callback;
- check_timer_expiry_f refresh_checker;
- };
- uint64
- bh_get_tick_ms()
- {
- return os_time_get_boot_us() / 1000;
- }
- uint32
- bh_get_elpased_ms(uint32 *last_system_clock)
- {
- uint32 elpased_ms;
- /* attention: the bh_get_tick_ms() return 64 bits integer, but
- the bh_get_elpased_ms() is designed to use 32 bits clock count */
- uint32 now = (uint32)bh_get_tick_ms();
- /* system clock overrun */
- if (now < *last_system_clock) {
- PRINT("system clock overrun!\n");
- elpased_ms = now + (UINT32_MAX - *last_system_clock) + 1;
- }
- else {
- elpased_ms = now - *last_system_clock;
- }
- *last_system_clock = now;
- return elpased_ms;
- }
- static app_timer_t *
- remove_timer_from(timer_ctx_t ctx, uint32 timer_id, bool active_list)
- {
- app_timer_t **head, *prev, *t;
- os_mutex_lock(&ctx->mutex);
- if (active_list)
- head = &ctx->app_timers;
- else
- head = &ctx->idle_timers;
- t = *head;
- prev = NULL;
- while (t) {
- if (t->id == timer_id) {
- if (prev == NULL) {
- *head = t->next;
- PRINT("removed timer [%d] at head from list %d\n", t->id,
- active_list);
- }
- else {
- prev->next = t->next;
- PRINT("removed timer [%d] after [%d] from list %d\n", t->id,
- prev->id, active_list);
- }
- os_mutex_unlock(&ctx->mutex);
- if (active_list && prev == NULL && ctx->refresh_checker)
- ctx->refresh_checker(ctx);
- return t;
- }
- else {
- prev = t;
- t = t->next;
- }
- }
- os_mutex_unlock(&ctx->mutex);
- return NULL;
- }
- static app_timer_t *
- remove_timer(timer_ctx_t ctx, uint32 timer_id, bool *active)
- {
- app_timer_t *t = remove_timer_from(ctx, timer_id, true);
- if (t) {
- if (active)
- *active = true;
- return t;
- }
- if (active)
- *active = false;
- return remove_timer_from(ctx, timer_id, false);
- }
- static void
- reschedule_timer(timer_ctx_t ctx, app_timer_t *timer)
- {
- app_timer_t *t;
- app_timer_t *prev = NULL;
- os_mutex_lock(&ctx->mutex);
- t = ctx->app_timers;
- timer->next = NULL;
- timer->expiry = bh_get_tick_ms() + timer->interval;
- while (t) {
- if (timer->expiry < t->expiry) {
- if (prev == NULL) {
- timer->next = ctx->app_timers;
- ctx->app_timers = timer;
- PRINT("rescheduled timer [%d] at head\n", timer->id);
- }
- else {
- timer->next = t;
- prev->next = timer;
- PRINT("rescheduled timer [%d] after [%d]\n", timer->id,
- prev->id);
- }
- goto out;
- }
- else {
- prev = t;
- t = t->next;
- }
- }
- if (prev) {
- /* insert to the list end */
- prev->next = timer;
- PRINT("rescheduled timer [%d] at end, after [%d]\n", timer->id,
- prev->id);
- }
- else {
- /* insert at the begin */
- bh_assert(ctx->app_timers == NULL);
- ctx->app_timers = timer;
- PRINT("rescheduled timer [%d] as first\n", timer->id);
- }
- out:
- os_mutex_unlock(&ctx->mutex);
- /* ensure the refresh_checker() is called out of the lock */
- if (prev == NULL && ctx->refresh_checker)
- ctx->refresh_checker(ctx);
- }
- static void
- release_timer(timer_ctx_t ctx, app_timer_t *t)
- {
- if (ctx->pre_allocated) {
- os_mutex_lock(&ctx->mutex);
- t->next = ctx->free_timers;
- ctx->free_timers = t;
- PRINT("recycle timer :%d\n", t->id);
- os_mutex_unlock(&ctx->mutex);
- }
- else {
- PRINT("destroy timer :%d\n", t->id);
- BH_FREE(t);
- }
- }
- void
- release_timer_list(app_timer_t **p_list)
- {
- app_timer_t *t = *p_list;
- while (t) {
- app_timer_t *next = t->next;
- PRINT("destroy timer list:%d\n", t->id);
- BH_FREE(t);
- t = next;
- }
- *p_list = NULL;
- }
- /*
- * API exposed
- */
- timer_ctx_t
- create_timer_ctx(timer_callback_f timer_handler,
- check_timer_expiry_f expiery_checker, int prealloc_num,
- unsigned int owner)
- {
- timer_ctx_t ctx = (timer_ctx_t)BH_MALLOC(sizeof(struct _timer_ctx));
- if (ctx == NULL)
- return NULL;
- memset(ctx, 0, sizeof(struct _timer_ctx));
- ctx->timer_callback = timer_handler;
- ctx->pre_allocated = prealloc_num;
- ctx->refresh_checker = expiery_checker;
- ctx->owner = owner;
- while (prealloc_num > 0) {
- app_timer_t *timer = (app_timer_t *)BH_MALLOC(sizeof(app_timer_t));
- if (timer == NULL)
- goto cleanup;
- memset(timer, 0, sizeof(*timer));
- timer->next = ctx->free_timers;
- ctx->free_timers = timer;
- prealloc_num--;
- }
- if (os_cond_init(&ctx->cond) != 0)
- goto cleanup;
- if (os_mutex_init(&ctx->mutex) != 0) {
- os_cond_destroy(&ctx->cond);
- goto cleanup;
- }
- PRINT("timer ctx created. pre-alloc: %d\n", ctx->pre_allocated);
- return ctx;
- cleanup:
- if (ctx) {
- release_timer_list(&ctx->free_timers);
- BH_FREE(ctx);
- }
- PRINT("timer ctx create failed\n");
- return NULL;
- }
- void
- destroy_timer_ctx(timer_ctx_t ctx)
- {
- while (ctx->free_timers) {
- void *tmp = ctx->free_timers;
- ctx->free_timers = ctx->free_timers->next;
- BH_FREE(tmp);
- }
- cleanup_app_timers(ctx);
- os_cond_destroy(&ctx->cond);
- os_mutex_destroy(&ctx->mutex);
- BH_FREE(ctx);
- }
- unsigned int
- timer_ctx_get_owner(timer_ctx_t ctx)
- {
- return ctx->owner;
- }
- void
- add_idle_timer(timer_ctx_t ctx, app_timer_t *timer)
- {
- os_mutex_lock(&ctx->mutex);
- timer->next = ctx->idle_timers;
- ctx->idle_timers = timer;
- os_mutex_unlock(&ctx->mutex);
- }
- uint32
- sys_create_timer(timer_ctx_t ctx, int interval, bool is_period, bool auto_start)
- {
- app_timer_t *timer;
- if (ctx->pre_allocated) {
- if (ctx->free_timers == NULL) {
- return (uint32)-1;
- }
- else {
- timer = ctx->free_timers;
- ctx->free_timers = timer->next;
- }
- }
- else {
- timer = (app_timer_t *)BH_MALLOC(sizeof(app_timer_t));
- if (timer == NULL)
- return (uint32)-1;
- }
- memset(timer, 0, sizeof(*timer));
- ctx->max_timer_id++;
- if (ctx->max_timer_id == (uint32)-1)
- ctx->max_timer_id++;
- timer->id = ctx->max_timer_id;
- timer->interval = (uint32)interval;
- timer->is_periodic = is_period;
- if (auto_start)
- reschedule_timer(ctx, timer);
- else
- add_idle_timer(ctx, timer);
- return timer->id;
- }
- bool
- sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id)
- {
- bool from_active;
- app_timer_t *t = remove_timer(ctx, timer_id, &from_active);
- if (t == NULL)
- return false;
- add_idle_timer(ctx, t);
- PRINT("sys_timer_stop called\n");
- return from_active;
- }
- bool
- sys_timer_destroy(timer_ctx_t ctx, uint32 timer_id)
- {
- bool from_active;
- app_timer_t *t = remove_timer(ctx, timer_id, &from_active);
- if (t == NULL)
- return false;
- release_timer(ctx, t);
- PRINT("sys_timer_destroy called\n");
- return true;
- }
- bool
- sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval)
- {
- app_timer_t *t = remove_timer(ctx, timer_id, NULL);
- if (t == NULL)
- return false;
- t->interval = (uint32)interval;
- reschedule_timer(ctx, t);
- PRINT("sys_timer_restart called\n");
- return true;
- }
- /*
- * API called by the timer manager from another thread or the kernel timer
- * handler
- */
- /**
- * lookup the app queue by the module name
- * post a timeout message to the app queue
- */
- static void
- handle_expired_timers(timer_ctx_t ctx, app_timer_t *expired)
- {
- while (expired) {
- app_timer_t *t = expired;
- ctx->timer_callback(t->id, ctx->owner);
- /* get next expired timer first, since the following
- operation may change expired->next */
- expired = expired->next;
- if (t->is_periodic) {
- /* if it is repeating, then reschedule it */
- reschedule_timer(ctx, t);
- }
- else {
- /* else move it to idle list */
- add_idle_timer(ctx, t);
- }
- }
- }
- uint32
- get_expiry_ms(timer_ctx_t ctx)
- {
- uint32 ms_to_next_expiry;
- uint64 now = bh_get_tick_ms();
- os_mutex_lock(&ctx->mutex);
- if (ctx->app_timers == NULL)
- ms_to_next_expiry = (uint32)-1;
- else if (ctx->app_timers->expiry >= now)
- ms_to_next_expiry = (uint32)(ctx->app_timers->expiry - now);
- else
- ms_to_next_expiry = 0;
- os_mutex_unlock(&ctx->mutex);
- return ms_to_next_expiry;
- }
- uint32
- check_app_timers(timer_ctx_t ctx)
- {
- app_timer_t *t, *expired = NULL, *expired_end = NULL;
- uint64 now = bh_get_tick_ms();
- os_mutex_lock(&ctx->mutex);
- t = ctx->app_timers;
- while (t) {
- if (now >= t->expiry) {
- ctx->app_timers = t->next;
- /* append t to the end of expired list */
- t->next = NULL;
- if (!expired_end) {
- expired = expired_end = t;
- }
- else {
- expired_end->next = t;
- expired_end = t;
- }
- t = ctx->app_timers;
- }
- else {
- break;
- }
- }
- os_mutex_unlock(&ctx->mutex);
- handle_expired_timers(ctx, expired);
- return get_expiry_ms(ctx);
- }
- void
- cleanup_app_timers(timer_ctx_t ctx)
- {
- os_mutex_lock(&ctx->mutex);
- release_timer_list(&ctx->app_timers);
- release_timer_list(&ctx->idle_timers);
- os_mutex_unlock(&ctx->mutex);
- }
|