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:
wenyongh
2020-01-21 13:26:14 +08:00
committed by Wang Xin
parent 2a4528c749
commit 46b93b9d22
464 changed files with 25137 additions and 7911 deletions

View 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})

View 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/

View 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
View 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
View 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) */

View 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);
}
}

View 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;
}

View 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);
}

View 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_ */

View 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")