WebAssembly Micro Runtime first version
This commit is contained in:
21
core/shared-lib/utils/CMakeLists.txt
Normal file
21
core/shared-lib/utils/CMakeLists.txt
Normal 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})
|
||||
|
||||
16
core/shared-lib/utils/Makefile
Normal file
16
core/shared-lib/utils/Makefile
Normal 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/
|
||||
114
core/shared-lib/utils/bh_list.c
Normal file
114
core/shared-lib/utils/bh_list.c
Normal 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
|
||||
|
||||
213
core/shared-lib/utils/bh_log.c
Normal file
213
core/shared-lib/utils/bh_log.c
Normal 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) */
|
||||
|
||||
258
core/shared-lib/utils/bh_queue.c
Normal file
258
core/shared-lib/utils/bh_queue.c
Normal 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);
|
||||
}
|
||||
}
|
||||
478
core/shared-lib/utils/runtime_timer.c
Normal file
478
core/shared-lib/utils/runtime_timer.c
Normal 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);
|
||||
}
|
||||
|
||||
55
core/shared-lib/utils/runtime_timer.h
Normal file
55
core/shared-lib/utils/runtime_timer.h
Normal 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_ */
|
||||
24
core/shared-lib/utils/shared_utils.cmake
Normal file
24
core/shared-lib/utils/shared_utils.cmake
Normal 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})
|
||||
|
||||
Reference in New Issue
Block a user