summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c')
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c
new file mode 100644
index 000000000..8fccf4c2f
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c
@@ -0,0 +1,469 @@
+/*
+ * 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_microsecond() / 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);
+}