WebAssembly Micro Runtime first version

This commit is contained in:
Wang Xin
2019-05-07 10:18:18 +08:00
parent 15aa50914b
commit a75a5f0f41
252 changed files with 33487 additions and 0 deletions

View File

@ -0,0 +1,21 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include_directories (. ../include ../platform/include ../platform/${PLATFORM} coap/er-coap coap/extension)
file (GLOB_RECURSE source_all *.c )
add_library (vmutilslib ${source_all})

View File

@ -0,0 +1,16 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
obj-y += bh_list.o bh_log.o attr-container.o bh_queue.o
obj-y += coap/

View File

@ -0,0 +1,114 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bh_list.h"
#include "bh_assert.h"
#ifdef BH_DEBUG
/**
* Test whehter a pointer value has exist in given list.
*
* @param list pointer to list.
* @param elem pointer to elem that will be inserted into list.
* @return <code>true</code> if the pointer has been in the list;
* <code>false</code> otherwise.
*/
BH_STATIC bool bh_list_is_elem_exist(bh_list *list, void *elem);
#endif
bh_list_status bh_list_init(bh_list *list)
{
if (!list)
return BH_LIST_ERROR;
(list->head).next = NULL;
list->len = 0;
return BH_LIST_SUCCESS;
}
bh_list_status _bh_list_insert(bh_list *list, void *elem)
{
bh_list_link *p = NULL;
if (!list || !elem)
return BH_LIST_ERROR;
#ifdef BH_DEBUG
bh_assert (!bh_list_is_elem_exist(list, elem));
#endif
p = (bh_list_link *) elem;
p->next = (list->head).next;
(list->head).next = p;
list->len++;
return BH_LIST_SUCCESS;
}
bh_list_status bh_list_remove(bh_list *list, void *elem)
{
bh_list_link *cur = NULL;
bh_list_link *prev = NULL;
if (!list || !elem)
return BH_LIST_ERROR;
cur = (list->head).next;
while (cur) {
if (cur == elem) {
if (prev)
prev->next = cur->next;
else
(list->head).next = cur->next;
list->len--;
return BH_LIST_SUCCESS;
}
prev = cur;
cur = cur->next;
}
return BH_LIST_ERROR;
}
uint32 bh_list_length(bh_list *list)
{
return (list ? list->len : 0);
}
void* bh_list_first_elem(bh_list *list)
{
return (list ? (list->head).next : NULL);
}
void* bh_list_elem_next(void *node)
{
return (node ? ((bh_list_link *) node)->next : NULL);
}
#ifdef BH_DEBUG
BH_STATIC bool bh_list_is_elem_exist(bh_list *list, void *elem)
{
bh_list_link *p = NULL;
if (!list || !elem) return false;
p = (list->head).next;
while (p && p != elem) p = p->next;
return (p != NULL);
}
#endif

View File

@ -0,0 +1,213 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file bh_log.c
* @date Tue Nov 8 18:20:06 2011
*
* @brief Implementation of Beihai's log system.
*/
#include "bh_assert.h"
#include "bh_time.h"
#include "bh_thread.h"
#include "bh_log.h"
#include "bh_platform_log.h"
/**
* The verbose level of the log system. Only those verbose logs whose
* levels are less than or equal to this value are outputed.
*/
static int log_verbose_level;
/**
* The lock for protecting the global output stream of logs.
*/
static korp_mutex log_stream_lock;
/**
* The current logging thread that owns the log_stream_lock.
*/
static korp_tid cur_logging_thread = INVALID_THREAD_ID;
/**
* Whether the currently being printed log is ennabled.
*/
static bool cur_log_enabled;
int _bh_log_init()
{
log_verbose_level = 3;
return vm_mutex_init(&log_stream_lock);
}
void _bh_log_set_verbose_level(int level)
{
log_verbose_level = level;
}
void _bh_log_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_bh_log_vprintf(fmt, ap);
va_end(ap);
}
/**
* Return true if the given tag is enabled by the configuration.
*
* @param tag the tag (or prefix) of the log message.
*
* @return true if the log should be enabled.
*/
static bool is_log_enabled(const char *tag)
{
/* Print all non-verbose or verbose logs whose levels are less than
or equal to the configured verbose level. */
return tag[0] != 'V' || tag[1] - '0' <= log_verbose_level;
}
/**
* Helper function for converting "..." to va_list.
*/
static void bh_log_emit_helper(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
bh_log_emit(fmt, ap);
va_end(ap);
}
extern size_t _bh_time_strftime(char *s, size_t max, const char *format,
int64 time);
void _bh_log_vprintf(const char *fmt, va_list ap)
{
korp_tid self = vm_self_thread();
/* Try to own the log stream and start the log output. */
if (self != cur_logging_thread) {
vm_mutex_lock(&log_stream_lock);
cur_logging_thread = self;
if (fmt && (cur_log_enabled = is_log_enabled(fmt))) {
char buf[32];
bh_time_strftime(buf, 32, "%Y-%m-%d %H:%M:%S",
bh_time_get_millisecond_from_1970());
bh_log_emit_helper("\n[%s - %X]: ", buf, (int) self);
/* Strip the "Vn." prefix. */
if (fmt && strlen(fmt) >= 3 && fmt[0] == 'V' && fmt[1] && fmt[2])
fmt += 3;
}
}
if (cur_log_enabled && fmt)
bh_log_emit(fmt, ap);
}
void _bh_log_commit()
{
if (vm_self_thread() != cur_logging_thread)
/* Ignore the single commit without printing anything. */
return;
cur_logging_thread = INVALID_THREAD_ID;
vm_mutex_unlock(&log_stream_lock);
}
void _bh_log(const char *tag, const char *file, int line, const char *fmt, ...)
{
va_list ap;
if (tag)
_bh_log_printf(tag);
if (file)
_bh_log_printf("%s:%d", file, line);
va_start(ap, fmt);
_bh_log_vprintf(fmt, ap);
va_end(ap);
_bh_log_commit();
}
#if defined(BH_DEBUG)
BH_STATIC char com_switchs[LOG_COM_MAX]; /* 0: off; 1: on */
BH_STATIC char *com_names[LOG_COM_MAX] = {"app_manager", "gc", "hmc", "utils",
"verifier_jeff", "vmcore_jeff"};
BH_STATIC int com_find_name(const char **com)
{
int i;
const char *c, *name;
for (i = 0; i < LOG_COM_MAX; i++) {
c = *com;
name = com_names[i];
while (*name != '\0') {
if (*c != *name)
break;
c++;
name++;
}
if (*name == '\0') {
*com = c;
return i;
}
}
return LOG_COM_MAX;
}
void log_parse_coms(const char *coms)
{
int i;
for (i = LOG_COM_MAX; i--; )
com_switchs[i] = 0;
com_switchs[LOG_COM_UTILS] = 1; /* utils is a common part */
if (coms == NULL)
return;
while (*coms != '\0') {
i = com_find_name(&coms);
if (i == LOG_COM_MAX)
break;
com_switchs[i] = 1;
if (*coms == '\0')
return;
if (*coms != ';')
break;
/* *com == ';' */
coms++;
}
/* Log the message without aborting. */
LOG_DEBUG(LOG_COM_UTILS, "The component names for logging are not right: %s.", coms);
}
int bh_log_dcom_is_enabled(int component)
{
return com_switchs[component];
}
#endif /* defined(BH_DEBUG) */

View File

@ -0,0 +1,258 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bh_queue.h"
#include "bh_thread.h"
#include "bh_memory.h"
#include "bh_time.h"
#include "bh_common.h"
typedef struct _bh_queue_node {
struct _bh_queue_node * next;
struct _bh_queue_node * prev;
unsigned short tag;
unsigned long len;
void * body;
bh_msg_cleaner msg_cleaner;
} bh_queue_node;
struct bh_queue {
bh_queue_mutex queue_lock;
bh_queue_cond queue_wait_cond;
unsigned int cnt;
unsigned int max;
unsigned int drops;
bh_queue_node * head;
bh_queue_node * tail;
bool exit_loop_run;
};
char * bh_message_payload(bh_message_t message)
{
return message->body;
}
int bh_message_payload_len(bh_message_t message)
{
return message->len;
}
int bh_message_type(bh_message_t message)
{
return message->tag;
}
bh_queue *
bh_queue_create()
{
int ret;
bh_queue *queue = bh_queue_malloc(sizeof(bh_queue));
if (queue) {
memset(queue, 0, sizeof(bh_queue));
queue->max = DEFAULT_QUEUE_LENGTH;
ret = bh_queue_mutex_init(&queue->queue_lock);
if (ret != 0) {
bh_queue_free(queue);
return NULL;
}
ret = bh_queue_cond_init(&queue->queue_wait_cond);
if (ret != 0) {
bh_queue_mutex_destroy(&queue->queue_lock);
bh_queue_free(queue);
return NULL;
}
}
return queue;
}
void bh_queue_destroy(bh_queue *queue)
{
bh_queue_node *node;
if (!queue)
return;
bh_queue_mutex_lock(&queue->queue_lock);
while (queue->head) {
node = queue->head;
queue->head = node->next;
bh_free_msg(node);
}
bh_queue_mutex_unlock(&queue->queue_lock);
bh_queue_cond_destroy(&queue->queue_wait_cond);
bh_queue_mutex_destroy(&queue->queue_lock);
bh_queue_free(queue);
}
bool bh_post_msg2(bh_queue *queue, bh_queue_node *msg)
{
if (queue->cnt >= queue->max) {
queue->drops++;
bh_free_msg(msg);
return false;
}
bh_queue_mutex_lock(&queue->queue_lock);
if (queue->cnt == 0) {
bh_assert(queue->head == NULL);
bh_assert(queue->tail == NULL);
queue->head = queue->tail = msg;
msg->next = msg->prev = NULL;
queue->cnt = 1;
bh_queue_cond_signal(&queue->queue_wait_cond);
} else {
msg->next = NULL;
msg->prev = queue->tail;
queue->tail->next = msg;
queue->tail = msg;
queue->cnt++;
}
bh_queue_mutex_unlock(&queue->queue_lock);
return true;
}
bool bh_post_msg(bh_queue *queue, unsigned short tag, void *body,
unsigned int len)
{
bh_queue_node *msg = bh_new_msg(tag, body, len, NULL);
if (msg == NULL) {
queue->drops++;
if (len != 0 && body)
bh_free(body);
return false;
}
if (!bh_post_msg2(queue, msg)) {
// bh_post_msg2 already freed the msg for failure
return false;
}
return true;
}
bh_queue_node * bh_new_msg(unsigned short tag, void *body, unsigned int len,
void * handler)
{
bh_queue_node *msg = (bh_queue_node*) bh_queue_malloc(
sizeof(bh_queue_node));
if (msg == NULL)
return NULL;
memset(msg, 0, sizeof(bh_queue_node));
msg->len = len;
msg->body = body;
msg->tag = tag;
msg->msg_cleaner = (bh_msg_cleaner) handler;
return msg;
}
void bh_free_msg(bh_queue_node *msg)
{
if (msg->msg_cleaner) {
msg->msg_cleaner(msg->body);
bh_queue_free(msg);
return;
}
// note: sometime we just use the payload pointer for a integer value
// len!=0 is the only indicator about the body is an allocated buffer.
if (msg->body && msg->len)
bh_queue_free(msg->body);
bh_queue_free(msg);
}
bh_message_t bh_get_msg(bh_queue *queue, int timeout)
{
bh_queue_node *msg = NULL;
bh_queue_mutex_lock(&queue->queue_lock);
if (queue->cnt == 0) {
bh_assert(queue->head == NULL);
bh_assert(queue->tail == NULL);
if (timeout == 0) {
bh_queue_mutex_unlock(&queue->queue_lock);
return NULL;
}
bh_queue_cond_timedwait(&queue->queue_wait_cond, &queue->queue_lock,
timeout);
}
if (queue->cnt == 0) {
bh_assert(queue->head == NULL);
bh_assert(queue->tail == NULL);
} else if (queue->cnt == 1) {
bh_assert(queue->head == queue->tail);
msg = queue->head;
queue->head = queue->tail = NULL;
queue->cnt = 0;
} else {
msg = queue->head;
queue->head = queue->head->next;
queue->head->prev = NULL;
queue->cnt--;
}
bh_queue_mutex_unlock(&queue->queue_lock);
return msg;
}
unsigned bh_queue_get_message_count(bh_queue *queue)
{
if (!queue)
return 0;
return queue->cnt;
}
void bh_queue_enter_loop_run(bh_queue *queue,
bh_queue_handle_msg_callback handle_cb)
{
if (!queue)
return;
while (!queue->exit_loop_run) {
bh_queue_node * message = bh_get_msg(queue, BH_WAIT_FOREVER);
if (message) {
handle_cb(message);
bh_free_msg(message);
}
}
}
void bh_queue_exit_loop_run(bh_queue *queue)
{
if (queue) {
queue->exit_loop_run = true;
bh_queue_cond_signal(&queue->queue_wait_cond);
}
}

View File

@ -0,0 +1,478 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "runtime_timer.h"
#include "bh_thread.h"
#include "bh_time.h"
#define PRINT(...)
//#define PRINT printf
typedef struct _app_timer {
struct _app_timer * next;
uint32 id;
unsigned int interval;
uint64 expiry;
bool is_periodic;
} app_timer_t;
struct _timer_ctx {
app_timer_t * g_app_timers;
app_timer_t * idle_timers;
app_timer_t * free_timers;
unsigned int g_max_id;
int pre_allocated;
unsigned int owner;
//add mutext and conditions
korp_cond cond;
korp_mutex mutex;
timer_callback_f timer_callback;
check_timer_expiry_f refresh_checker;
};
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) {
elpased_ms = now + (0xFFFFFFFF - *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)
{
vm_mutex_lock(&ctx->mutex);
app_timer_t ** head;
if (active_list)
head = &ctx->g_app_timers;
else
head = &ctx->idle_timers;
app_timer_t * t = *head;
app_timer_t * 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);
}
vm_mutex_unlock(&ctx->mutex);
if (active_list && prev == NULL && ctx->refresh_checker)
ctx->refresh_checker(ctx);
return t;
} else {
prev = t;
t = t->next;
}
}
vm_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)
{
vm_mutex_lock(&ctx->mutex);
app_timer_t * t = ctx->g_app_timers;
app_timer_t * prev = NULL;
timer->next = NULL;
timer->expiry = bh_get_tick_ms() + timer->interval;
while (t) {
if (timer->expiry < t->expiry) {
if (prev == NULL) {
timer->next = ctx->g_app_timers;
ctx->g_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);
}
vm_mutex_unlock(&ctx->mutex);
// ensure the refresh_checker() is called out of the lock
if (prev == NULL && ctx->refresh_checker)
ctx->refresh_checker(ctx);
return;
} 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->g_app_timers == NULL);
ctx->g_app_timers = timer;
PRINT("rescheduled timer [%d] as first\n", timer->id);
}
vm_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) {
vm_mutex_lock(&ctx->mutex);
t->next = ctx->free_timers;
ctx->free_timers = t;
PRINT("recycle timer :%d\n", t->id);
vm_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--;
}
vm_cond_init(&ctx->cond);
vm_mutex_init(&ctx->mutex);
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);
}
printf("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);
vm_cond_destroy(&ctx->cond);
vm_mutex_destroy(&ctx->mutex);
bh_free(ctx);
}
void timer_ctx_set_lock(timer_ctx_t ctx, bool lock)
{
if (lock)
vm_mutex_lock(&ctx->mutex);
else
vm_mutex_unlock(&ctx->mutex);
}
void * timer_ctx_get_lock(timer_ctx_t ctx)
{
return &ctx->mutex;
}
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)
{
vm_mutex_lock(&ctx->mutex);
timer->next = ctx->idle_timers;
ctx->idle_timers = timer;
vm_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 -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 -1;
}
memset(timer, 0, sizeof(*timer));
ctx->g_max_id++;
if (ctx->g_max_id == -1)
ctx->g_max_id++;
timer->id = ctx->g_max_id;
timer->interval = 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_destory(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_destory 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;
if (interval > 0)
t->interval = 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);
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);
}
}
}
int get_expiry_ms(timer_ctx_t ctx)
{
int ms_to_next_expiry;
uint64 now = bh_get_tick_ms();
vm_mutex_lock(&ctx->mutex);
if (ctx->g_app_timers == NULL)
ms_to_next_expiry = 7 * 24 * 60 * 60 * 1000; // 1 week
else if (ctx->g_app_timers->expiry >= now)
ms_to_next_expiry = ctx->g_app_timers->expiry - now;
else
ms_to_next_expiry = 0;
vm_mutex_unlock(&ctx->mutex);
return ms_to_next_expiry;
}
int check_app_timers(timer_ctx_t ctx)
{
vm_mutex_lock(&ctx->mutex);
app_timer_t * t = ctx->g_app_timers;
app_timer_t * prev = NULL;
app_timer_t * expired = NULL;
uint64 now = bh_get_tick_ms();
while (t) {
if (now >= t->expiry) {
ctx->g_app_timers = t->next;
t->next = expired;
expired = t;
t = ctx->g_app_timers;
} else {
break;
}
}
vm_mutex_unlock(&ctx->mutex);
handle_expired_timers(ctx, expired);
return get_expiry_ms(ctx);
}
void cleanup_app_timers(timer_ctx_t ctx)
{
app_timer_t *t;
vm_mutex_lock(&ctx->mutex);
release_timer_list(&ctx->g_app_timers);
release_timer_list(&ctx->idle_timers);
vm_mutex_unlock(&ctx->mutex);
}
/*
*
* One reference implementation for timer manager
*
*
*/
void * thread_timer_check(void * arg)
{
timer_ctx_t ctx = (timer_ctx_t) arg;
while (1) {
int ms_to_expiry = check_app_timers(ctx);
vm_mutex_lock(&ctx->mutex);
vm_cond_reltimedwait(&ctx->cond, &ctx->mutex, ms_to_expiry);
vm_mutex_unlock(&ctx->mutex);
}
}
void wakeup_timer_thread(timer_ctx_t ctx)
{
vm_cond_signal(&ctx->cond);
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIB_BASE_RUNTIME_TIMER_H_
#define LIB_BASE_RUNTIME_TIMER_H_
#include "bh_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
uint32 bh_get_elpased_ms(uint32 * last_system_clock);
struct _timer_ctx;
typedef struct _timer_ctx * timer_ctx_t;
typedef void (*timer_callback_f)(uint32 id, unsigned int owner);
typedef void (*check_timer_expiry_f)(timer_ctx_t ctx);
timer_ctx_t create_timer_ctx(timer_callback_f timer_handler,
check_timer_expiry_f, int prealloc_num, unsigned int owner);
void destroy_timer_ctx(timer_ctx_t);
void timer_ctx_set_lock(timer_ctx_t ctx, bool lock);
void * timer_ctx_get_lock(timer_ctx_t ctx);
unsigned int timer_ctx_get_owner(timer_ctx_t ctx);
uint32 sys_create_timer(timer_ctx_t ctx, int interval, bool is_period,
bool auto_start);
bool sys_timer_destory(timer_ctx_t ctx, uint32 timer_id);
bool sys_timer_cancel(timer_ctx_t ctx, uint32 timer_id);
bool sys_timer_restart(timer_ctx_t ctx, uint32 timer_id, int interval);
void cleanup_app_timers(timer_ctx_t ctx);
int check_app_timers(timer_ctx_t ctx);
int get_expiry_ms(timer_ctx_t ctx);
void wakeup_timer_thread(timer_ctx_t ctx);
void * thread_timer_check(void * arg);
#ifdef __cplusplus
}
#endif
#endif /* LIB_BASE_RUNTIME_TIMER_H_ */

View File

@ -0,0 +1,24 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set (UTILS_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR})
include_directories(${UTILS_SHARED_DIR})
include_directories(${UTILS_SHARED_DIR}/../include)
file (GLOB_RECURSE source_all ${UTILS_SHARED_DIR}/*.c)
set (UTILS_SHARED_SOURCE ${source_all})