Enable AoT and wamr-sdk, and change arguments of call wasm API (#157)
* Implement memory profiler, optimize memory usage, modify code indent * Implement memory.grow and limit heap space base offset to 1G; modify iwasm build type to Release and 64 bit by default * Add a new extension library: connection * Fix bug of reading magic number and version in big endian platform * Re-org platform APIs: move most platform APIs from iwasm to shared-lib * Enhance wasm loader to fix some security issues * Fix issue about illegal load of EXC_RETURN into PC on stm32 board * Updates that let a restricted version of the interpreter run in SGX * Enable native/app address validation and conversion for wasm app * Remove wasm_application_exectue_* APIs from wasm_export.h which makes confused * Refine binary size and fix several minor issues Optimize interpreter LOAD/STORE opcodes to decrease the binary size Fix issues when using iwasm library: _bh_log undefined, bh_memory.h not found Remove unused _stdin/_stdout/_stderr global variables resolve in libc wrapper Add macros of global heap size, stack size, heap size for Zephyr main.c Clear compile warning of wasm_application.c * Add more strict security checks for libc wrapper API's * Use one libc wrapper copy for sgx and other platforms; remove bh_printf macro for other platform header files * Enhance security of libc strcpy/sprintf wrapper function * Fix issue of call native for x86_64/arm/mips, add module inst parameter for native wrapper functions * Remove get_module_inst() and fix issue of call native * Refine wgl lib: remove module_inst parameter from widget functions; move function index check to runtime instantiate * Refine interpreter call native process, refine memory boudary check * Fix issues of invokeNative function of arm/mips/general version * Add a switch to build simple sample without gui support * Add BUILD_TARGET setting in makefile to replace cpu compiler flags in source code * Re-org shared lib header files, remove unused info; fix compile issues of vxworks * Add build target general * Remove unused files * Update license header * test push * Restore file * Sync up with internal/feature * Sync up with internal/feature * Rename build_wamr_app to build_wasm_app * Fix small issues of README * Enhance malformed wasm file checking Fix issue of print hex int and implement utf8 string check Fix wasi file read/write right issue Fix minor issue of build wasm app doc * Sync up with internal/feature * Sync up with internal/feature: fix interpreter arm issue, fix read leb issue * Sync up with internal/feature * Fix bug of config.h and rename wasi config.h to ssp_config.h * Sync up with internal/feature * Import wamr aot * update document * update document * Update document, disable WASI in 32bit * update document * remove files * update document * Update document * update document * update document * update samples * Sync up with internal repo
This commit is contained in:
10
core/shared/utils/CMakeLists.txt
Normal file
10
core/shared/utils/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
include_directories (. ../include ../platform/include ../platform/${WAMR_BUILD_PLATFORM} coap/er-coap coap/extension)
|
||||
|
||||
|
||||
file (GLOB_RECURSE source_all *.c )
|
||||
|
||||
add_library (vmutilslib ${source_all})
|
||||
|
||||
5
core/shared/utils/Makefile
Normal file
5
core/shared/utils/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
obj-y += bh_list.o bh_log.o attr-container.o bh_queue.o
|
||||
obj-y += coap/
|
||||
292
core/shared/utils/bh_hashmap.c
Normal file
292
core/shared/utils/bh_hashmap.c
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "bh_hashmap.h"
|
||||
#include "bh_log.h"
|
||||
#include "bh_thread.h"
|
||||
#include "bh_memory.h"
|
||||
|
||||
|
||||
typedef struct HashMapElem {
|
||||
void *key;
|
||||
void *value;
|
||||
struct HashMapElem *next;
|
||||
} HashMapElem;
|
||||
|
||||
struct HashMap {
|
||||
/* size of element array */
|
||||
uint32 size;
|
||||
/* lock for elements */
|
||||
korp_mutex *lock;
|
||||
/* hash function of key */
|
||||
HashFunc hash_func;
|
||||
/* key equal function */
|
||||
KeyEqualFunc key_equal_func;
|
||||
KeyDestroyFunc key_destroy_func;
|
||||
ValueDestroyFunc value_destroy_func;
|
||||
HashMapElem *elements[1];
|
||||
};
|
||||
|
||||
HashMap*
|
||||
bh_hash_map_create(uint32 size, bool use_lock,
|
||||
HashFunc hash_func,
|
||||
KeyEqualFunc key_equal_func,
|
||||
KeyDestroyFunc key_destroy_func,
|
||||
ValueDestroyFunc value_destroy_func)
|
||||
{
|
||||
HashMap *map;
|
||||
uint64 total_size;
|
||||
|
||||
if (size > HASH_MAP_MAX_SIZE) {
|
||||
LOG_ERROR("HashMap create failed: size is too large.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!hash_func || !key_equal_func) {
|
||||
LOG_ERROR("HashMap create failed: hash function or key equal function "
|
||||
" is NULL.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
total_size = offsetof(HashMap, elements) +
|
||||
sizeof(HashMapElem) * (uint64)size +
|
||||
(use_lock ? sizeof(korp_mutex) : 0);
|
||||
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(map = bh_malloc((uint32)total_size))) {
|
||||
LOG_ERROR("HashMap create failed: alloc memory failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(map, 0, (uint32)total_size);
|
||||
|
||||
if (use_lock) {
|
||||
map->lock = (korp_mutex*)
|
||||
((uint8*)map + offsetof(HashMap, elements)
|
||||
+ sizeof(HashMapElem) * size);
|
||||
if (vm_mutex_init(map->lock)) {
|
||||
LOG_ERROR("HashMap create failed: init map lock failed.\n");
|
||||
bh_free(map);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
map->size = size;
|
||||
map->hash_func = hash_func;
|
||||
map->key_equal_func = key_equal_func;
|
||||
map->key_destroy_func = key_destroy_func;
|
||||
map->value_destroy_func = value_destroy_func;
|
||||
return map;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_hash_map_insert(HashMap *map, void *key, void *value)
|
||||
{
|
||||
uint32 index;
|
||||
HashMapElem *elem;
|
||||
|
||||
if (!map || !key) {
|
||||
LOG_ERROR("HashMap insert elem failed: map or key is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_lock(map->lock);
|
||||
}
|
||||
|
||||
index = map->hash_func(key) % map->size;
|
||||
elem = map->elements[index];
|
||||
while (elem) {
|
||||
if (map->key_equal_func(elem->key, key)) {
|
||||
LOG_ERROR("HashMap insert elem failed: duplicated key found.\n");
|
||||
goto fail;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
|
||||
if (!(elem = bh_malloc(sizeof(HashMapElem)))) {
|
||||
LOG_ERROR("HashMap insert elem failed: alloc memory failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
elem->key = key;
|
||||
elem->value = value;
|
||||
elem->next = map->elements[index];
|
||||
map->elements[index] = elem;
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void*
|
||||
bh_hash_map_find(HashMap *map, void *key)
|
||||
{
|
||||
uint32 index;
|
||||
HashMapElem *elem;
|
||||
void *value;
|
||||
|
||||
if (!map || !key) {
|
||||
LOG_ERROR("HashMap find elem failed: map or key is NULL.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_lock(map->lock);
|
||||
}
|
||||
|
||||
index = map->hash_func(key) % map->size;
|
||||
elem = map->elements[index];
|
||||
|
||||
while (elem) {
|
||||
if (map->key_equal_func(elem->key, key)) {
|
||||
value = elem->value;
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_hash_map_update(HashMap *map, void *key, void *value,
|
||||
void **p_old_value)
|
||||
{
|
||||
uint32 index;
|
||||
HashMapElem *elem;
|
||||
|
||||
if (!map || !key) {
|
||||
LOG_ERROR("HashMap update elem failed: map or key is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_lock(map->lock);
|
||||
}
|
||||
|
||||
index = map->hash_func(key) % map->size;
|
||||
elem = map->elements[index];
|
||||
|
||||
while (elem) {
|
||||
if (map->key_equal_func(elem->key, key)) {
|
||||
if (p_old_value)
|
||||
*p_old_value = elem->value;
|
||||
elem->value = value;
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_hash_map_remove(HashMap *map, void *key,
|
||||
void **p_old_key, void **p_old_value)
|
||||
{
|
||||
uint32 index;
|
||||
HashMapElem *elem, *prev;
|
||||
|
||||
if (!map || !key) {
|
||||
LOG_ERROR("HashMap remove elem failed: map or key is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_lock(map->lock);
|
||||
}
|
||||
|
||||
index = map->hash_func(key) % map->size;
|
||||
prev = elem = map->elements[index];
|
||||
|
||||
while (elem) {
|
||||
if (map->key_equal_func(elem->key, key)) {
|
||||
if (p_old_key)
|
||||
*p_old_key = elem->key;
|
||||
if (p_old_value)
|
||||
*p_old_value = elem->value;
|
||||
|
||||
if (elem == map->elements[index])
|
||||
map->elements[index] = elem->next;
|
||||
else
|
||||
prev->next = elem->next;
|
||||
|
||||
bh_free(elem);
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
prev = elem;
|
||||
elem = elem->next;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_hash_map_destroy(HashMap *map)
|
||||
{
|
||||
uint32 index;
|
||||
HashMapElem *elem, *next;
|
||||
|
||||
if (!map) {
|
||||
LOG_ERROR("HashMap destroy failed: map is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_lock(map->lock);
|
||||
}
|
||||
|
||||
for (index = 0; index < map->size; index++) {
|
||||
elem = map->elements[index];
|
||||
while (elem) {
|
||||
next = elem->next;
|
||||
|
||||
if (map->key_destroy_func) {
|
||||
map->key_destroy_func(elem->key);
|
||||
}
|
||||
if (map->value_destroy_func) {
|
||||
map->value_destroy_func(elem->value);
|
||||
}
|
||||
bh_free(elem);
|
||||
|
||||
elem = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (map->lock) {
|
||||
vm_mutex_unlock(map->lock);
|
||||
vm_mutex_destroy(map->lock);
|
||||
}
|
||||
bh_free(map);
|
||||
return true;
|
||||
}
|
||||
103
core/shared/utils/bh_list.c
Normal file
103
core/shared/utils/bh_list.c
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
202
core/shared/utils/bh_log.c
Normal file
202
core/shared/utils/bh_log.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
/**
|
||||
* @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",
|
||||
(int64)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) */
|
||||
|
||||
248
core/shared/utils/bh_queue.c
Normal file
248
core/shared/utils/bh_queue.c
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#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 int 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;
|
||||
}
|
||||
|
||||
uint32 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,
|
||||
void *arg)
|
||||
{
|
||||
if (!queue)
|
||||
return;
|
||||
|
||||
while (!queue->exit_loop_run) {
|
||||
bh_queue_node * message = bh_get_msg(queue, (int)BH_WAIT_FOREVER);
|
||||
|
||||
if (message) {
|
||||
handle_cb(message, arg);
|
||||
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);
|
||||
}
|
||||
}
|
||||
206
core/shared/utils/bh_vector.c
Normal file
206
core/shared/utils/bh_vector.c
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "bh_log.h"
|
||||
#include "bh_vector.h"
|
||||
#include "bh_memory.h"
|
||||
|
||||
|
||||
static uint8*
|
||||
alloc_vector_data(uint32 length, uint32 size_elem)
|
||||
{
|
||||
uint64 total_size = ((uint64)size_elem) * length;
|
||||
uint8 *data;
|
||||
|
||||
if (total_size > UINT32_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((data = bh_malloc((uint32)total_size))) {
|
||||
memset(data, 0, (uint32)total_size);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool
|
||||
extend_vector(Vector *vector, uint32 length)
|
||||
{
|
||||
uint8 *data;
|
||||
|
||||
if (length <= vector->max_elements)
|
||||
return true;
|
||||
|
||||
if (length < vector->size_elem * 3 / 2)
|
||||
length = vector->size_elem * 3 / 2;
|
||||
|
||||
if (!(data = alloc_vector_data(length, vector->size_elem))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(data, vector->data, vector->size_elem * vector->max_elements);
|
||||
bh_free(vector->data);
|
||||
vector->data = data;
|
||||
vector->max_elements = length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_vector_init(Vector *vector, uint32 init_length, uint32 size_elem)
|
||||
{
|
||||
if (!vector) {
|
||||
LOG_ERROR("Init vector failed: vector is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (init_length == 0) {
|
||||
init_length = 4;
|
||||
}
|
||||
|
||||
if (!(vector->data = alloc_vector_data(init_length, size_elem))) {
|
||||
LOG_ERROR("Init vector failed: alloc memory failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
vector->size_elem = size_elem;
|
||||
vector->max_elements = init_length;
|
||||
vector->num_elements = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_vector_set(Vector *vector, uint32 index, const void *elem_buf)
|
||||
{
|
||||
if (!vector || !elem_buf) {
|
||||
LOG_ERROR("Set vector elem failed: vector or elem buf is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= vector->num_elements) {
|
||||
LOG_ERROR("Set vector elem failed: invalid elem index.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(vector->data + vector->size_elem * index,
|
||||
elem_buf, vector->size_elem);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bh_vector_get(const Vector *vector, uint32 index, void *elem_buf)
|
||||
{
|
||||
if (!vector || !elem_buf) {
|
||||
LOG_ERROR("Get vector elem failed: vector or elem buf is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= vector->num_elements) {
|
||||
LOG_ERROR("Get vector elem failed: invalid elem index.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(elem_buf, vector->data + vector->size_elem * index,
|
||||
vector->size_elem);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *p;
|
||||
|
||||
if (!vector || !elem_buf) {
|
||||
LOG_ERROR("Insert vector elem failed: vector or elem buf is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= vector->num_elements) {
|
||||
LOG_ERROR("Insert vector elem failed: invalid elem index.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!extend_vector(vector, vector->num_elements + 1)) {
|
||||
LOG_ERROR("Insert vector elem failed: extend vector failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
p = vector->data + vector->size_elem * vector->num_elements;
|
||||
for (i = vector->num_elements - 1; i > index; i--) {
|
||||
memcpy(p, p - vector->size_elem, vector->size_elem);
|
||||
p -= vector->size_elem;
|
||||
}
|
||||
|
||||
memcpy(p, elem_buf, vector->size_elem);
|
||||
vector->num_elements++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bh_vector_append(Vector *vector, const void *elem_buf)
|
||||
{
|
||||
if (!vector || !elem_buf) {
|
||||
LOG_ERROR("Append vector elem failed: vector or elem buf is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!extend_vector(vector, vector->num_elements + 1)) {
|
||||
LOG_ERROR("Append ector elem failed: extend vector failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(vector->data + vector->size_elem * vector->num_elements,
|
||||
elem_buf, vector->size_elem);
|
||||
vector->num_elements++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 *p;
|
||||
|
||||
if (!vector) {
|
||||
LOG_ERROR("Remove vector elem failed: vector is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= vector->num_elements) {
|
||||
LOG_ERROR("Remove vector elem failed: invalid elem index.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
p = vector->data + vector->size_elem * index;
|
||||
|
||||
if (old_elem_buf) {
|
||||
memcpy(old_elem_buf, p, vector->size_elem);
|
||||
}
|
||||
|
||||
for (i = index; i < vector->num_elements - 1; i++) {
|
||||
memcpy(p, p + vector->size_elem, vector->size_elem);
|
||||
p += vector->size_elem;
|
||||
}
|
||||
|
||||
vector->num_elements--;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32
|
||||
bh_vector_size(const Vector *vector)
|
||||
{
|
||||
return vector ? vector->num_elements : 0;
|
||||
}
|
||||
|
||||
bool
|
||||
bh_vector_destroy(Vector *vector)
|
||||
{
|
||||
if (!vector) {
|
||||
LOG_ERROR("Destroy vector elem failed: vector is NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vector->data)
|
||||
bh_free(vector->data);
|
||||
memset(vector, 0, sizeof(Vector));
|
||||
return true;
|
||||
}
|
||||
428
core/shared/utils/runtime_timer.c
Normal file
428
core/shared/utils/runtime_timer.c
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
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);
|
||||
|
||||
vm_cond_destroy(&ctx->cond);
|
||||
vm_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)
|
||||
{
|
||||
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 (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->g_max_id++;
|
||||
if (ctx->g_max_id == (uint32)-1)
|
||||
ctx->g_max_id++;
|
||||
timer->id = ctx->g_max_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;
|
||||
|
||||
if (interval > 0)
|
||||
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);
|
||||
|
||||
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 = (int)(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 * 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)
|
||||
{
|
||||
vm_mutex_lock(&ctx->mutex);
|
||||
|
||||
release_timer_list(&ctx->g_app_timers);
|
||||
release_timer_list(&ctx->idle_timers);
|
||||
|
||||
vm_mutex_unlock(&ctx->mutex);
|
||||
}
|
||||
|
||||
39
core/shared/utils/runtime_timer.h
Normal file
39
core/shared/utils/runtime_timer.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#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);
|
||||
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_destroy(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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* LIB_BASE_RUNTIME_TIMER_H_ */
|
||||
14
core/shared/utils/shared_utils.cmake
Normal file
14
core/shared/utils/shared_utils.cmake
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
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})
|
||||
|
||||
LIST (APPEND RUNTIME_LIB_HEADER_LIST "${UTILS_SHARED_DIR}/runtime_timer.h")
|
||||
Reference in New Issue
Block a user