Enable shared memory && add pthread support (#282)
This commit is contained in:
13
core/iwasm/libraries/lib-pthread/lib_pthread.cmake
Normal file
13
core/iwasm/libraries/lib-pthread/lib_pthread.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
set (LIB_PTHREAD_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_definitions (-DWASM_ENABLE_LIB_PTHREAD=1)
|
||||
|
||||
include_directories(${LIB_PTHREAD_DIR})
|
||||
|
||||
file (GLOB source_all ${LIB_PTHREAD_DIR}/*.c)
|
||||
|
||||
set (LIB_PTHREAD_SOURCE ${source_all})
|
||||
|
||||
731
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c
Normal file
731
core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c
Normal file
@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "bh_common.h"
|
||||
#include "bh_log.h"
|
||||
#include "wasm_export.h"
|
||||
#include "../interpreter/wasm.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
#include "thread_manager.h"
|
||||
|
||||
#define get_module(exec_env) \
|
||||
wasm_exec_env_get_module(exec_env)
|
||||
|
||||
#define get_module_inst(exec_env) \
|
||||
wasm_runtime_get_module_inst(exec_env)
|
||||
|
||||
#define get_thread_arg(exec_env) \
|
||||
wasm_exec_env_get_thread_arg(exec_env)
|
||||
|
||||
#define get_wasi_ctx(module_inst) \
|
||||
wasm_runtime_get_wasi_ctx(module_inst)
|
||||
|
||||
#define validate_app_addr(offset, size) \
|
||||
wasm_runtime_validate_app_addr(module_inst, offset, size)
|
||||
|
||||
#define validate_native_addr(addr, size) \
|
||||
wasm_runtime_validate_native_addr(module_inst, addr, size)
|
||||
|
||||
#define addr_app_to_native(offset) \
|
||||
wasm_runtime_addr_app_to_native(module_inst, offset)
|
||||
|
||||
#define addr_native_to_app(ptr) \
|
||||
wasm_runtime_addr_native_to_app(module_inst, ptr)
|
||||
|
||||
extern bool
|
||||
wasm_runtime_call_indirect(wasm_exec_env_t exec_env,
|
||||
uint32 element_indices,
|
||||
uint32 argc, uint32 argv[]);
|
||||
|
||||
enum {
|
||||
T_THREAD,
|
||||
T_MUTEX,
|
||||
T_COND,
|
||||
};
|
||||
|
||||
enum thread_status_t {
|
||||
THREAD_INIT,
|
||||
THREAD_RUNNING,
|
||||
THREAD_CANCELLED,
|
||||
THREAD_EXIT,
|
||||
};
|
||||
|
||||
enum mutex_status_t {
|
||||
MUTEX_CREATED,
|
||||
MUTEX_DESTROYED,
|
||||
};
|
||||
|
||||
enum cond_status_t {
|
||||
COND_CREATED,
|
||||
COND_DESTROYED,
|
||||
};
|
||||
|
||||
typedef struct ClusterInfoNode {
|
||||
bh_list_link l;
|
||||
WASMCluster *cluster;
|
||||
HashMap *thread_info_map;
|
||||
} ClusterInfoNode;
|
||||
|
||||
typedef struct ThreadInfoNode {
|
||||
wasm_exec_env_t parent_exec_env;
|
||||
wasm_exec_env_t exec_env;
|
||||
/* the id returned to app */
|
||||
uint32 handle;
|
||||
/* type can be [THREAD | MUTEX | CONDITION] */
|
||||
uint32 type;
|
||||
/* Thread status, this variable should be volatile
|
||||
as its value may be changed in different threads */
|
||||
volatile uint32 status;
|
||||
union {
|
||||
korp_tid thread;
|
||||
korp_mutex *mutex;
|
||||
korp_cond *cond;
|
||||
} u;
|
||||
} ThreadInfoNode;
|
||||
|
||||
typedef struct {
|
||||
ThreadInfoNode *info_node;
|
||||
/* table elem index of the app's entry function */
|
||||
uint32 elem_index;
|
||||
/* arg of the app's entry function */
|
||||
void *arg;
|
||||
wasm_module_inst_t module_inst;
|
||||
} ThreadRoutineArgs;
|
||||
|
||||
static bh_list cluster_info_list;
|
||||
static korp_mutex pthread_global_lock;
|
||||
static uint32 handle_id = 1;
|
||||
|
||||
static void
|
||||
lib_pthread_destroy_callback(WASMCluster *cluster);
|
||||
|
||||
static uint32
|
||||
thread_handle_hash(void *handle)
|
||||
{
|
||||
return (uint32)(uintptr_t)handle;
|
||||
}
|
||||
|
||||
static bool
|
||||
thread_handle_equal(void *h1, void *h2)
|
||||
{
|
||||
return (uint32)(uintptr_t)h1 == (uint32)(uintptr_t)h2 ? true : false;
|
||||
}
|
||||
|
||||
static void
|
||||
thread_info_destroy(void *node)
|
||||
{
|
||||
ThreadInfoNode *info_node = (ThreadInfoNode *)node;
|
||||
ThreadRoutineArgs *args;
|
||||
|
||||
pthread_mutex_lock(&pthread_global_lock);
|
||||
if (info_node->type == T_THREAD) {
|
||||
args = get_thread_arg(info_node->exec_env);
|
||||
if (args) {
|
||||
wasm_runtime_free(args);
|
||||
}
|
||||
}
|
||||
else if (info_node->type == T_MUTEX) {
|
||||
if (info_node->status != MUTEX_DESTROYED)
|
||||
os_mutex_destroy(info_node->u.mutex);
|
||||
wasm_runtime_free(info_node->u.mutex);
|
||||
}
|
||||
else if (info_node->type == T_COND) {
|
||||
if (info_node->status != COND_DESTROYED)
|
||||
os_cond_destroy(info_node->u.cond);
|
||||
wasm_runtime_free(info_node->u.cond);
|
||||
}
|
||||
wasm_runtime_free(info_node);
|
||||
pthread_mutex_unlock(&pthread_global_lock);
|
||||
}
|
||||
|
||||
bool
|
||||
lib_pthread_init()
|
||||
{
|
||||
if (0 != os_mutex_init(&pthread_global_lock))
|
||||
return false;
|
||||
bh_list_init(&cluster_info_list);
|
||||
if (!wasm_cluster_register_destroy_callback(
|
||||
lib_pthread_destroy_callback)) {
|
||||
os_mutex_destroy(&pthread_global_lock);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
lib_pthread_destroy()
|
||||
{
|
||||
os_mutex_destroy(&pthread_global_lock);
|
||||
}
|
||||
|
||||
static ClusterInfoNode*
|
||||
get_cluster_info(WASMCluster *cluster)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
node = bh_list_first_elem(&cluster_info_list);
|
||||
|
||||
while (node) {
|
||||
if (cluster == node->cluster) {
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
return node;
|
||||
}
|
||||
node = bh_list_elem_next(node);
|
||||
}
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ClusterInfoNode*
|
||||
create_cluster_info(WASMCluster *cluster)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
bh_list_status ret;
|
||||
|
||||
if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->cluster = cluster;
|
||||
if (!(node->thread_info_map =
|
||||
bh_hash_map_create(32, true,
|
||||
(HashFunc)thread_handle_hash,
|
||||
(KeyEqualFunc)thread_handle_equal,
|
||||
NULL,
|
||||
thread_info_destroy))) {
|
||||
wasm_runtime_free(node);
|
||||
return NULL;
|
||||
}
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
ret = bh_list_insert(&cluster_info_list, node);
|
||||
bh_assert(ret == 0);
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
|
||||
(void)ret;
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool
|
||||
destroy_cluster_info(WASMCluster *cluster)
|
||||
{
|
||||
ClusterInfoNode *node = get_cluster_info(cluster);
|
||||
if (node) {
|
||||
bh_hash_map_destroy(node->thread_info_map);
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
bh_list_remove(&cluster_info_list, node);
|
||||
wasm_runtime_free(node);
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
lib_pthread_destroy_callback(WASMCluster *cluster)
|
||||
{
|
||||
destroy_cluster_info(cluster);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_thread_info_node(ThreadInfoNode *thread_info)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
bool ret;
|
||||
WASMCluster *cluster =
|
||||
wasm_exec_env_get_cluster(thread_info->exec_env);
|
||||
|
||||
if ((node = get_cluster_info(cluster))) {
|
||||
ret = bh_hash_map_remove(node->thread_info_map,
|
||||
(void *)(uintptr_t)thread_info->handle,
|
||||
NULL, NULL);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
thread_info_destroy(thread_info);
|
||||
}
|
||||
|
||||
static bool
|
||||
append_thread_info_node(ThreadInfoNode *thread_info)
|
||||
{
|
||||
ClusterInfoNode *node;
|
||||
WASMCluster *cluster =
|
||||
wasm_exec_env_get_cluster(thread_info->exec_env);
|
||||
|
||||
if (!(node = get_cluster_info(cluster))) {
|
||||
if (!(node = create_cluster_info(cluster))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bh_hash_map_insert(node->thread_info_map,
|
||||
(void *)(uintptr_t)thread_info->handle,
|
||||
thread_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ThreadInfoNode*
|
||||
get_thread_info(wasm_exec_env_t exec_env, uint32 handle)
|
||||
{
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
ClusterInfoNode *info = get_cluster_info(cluster);
|
||||
return bh_hash_map_find(info->thread_info_map, (void *)(uintptr_t)handle);
|
||||
}
|
||||
|
||||
static uint32
|
||||
allocate_handle()
|
||||
{
|
||||
uint32 id;
|
||||
os_mutex_lock(&pthread_global_lock);
|
||||
id = handle_id++;
|
||||
os_mutex_unlock(&pthread_global_lock);
|
||||
return id;
|
||||
}
|
||||
|
||||
static void*
|
||||
pthread_start_routine(void *arg)
|
||||
{
|
||||
wasm_exec_env_t exec_env = (wasm_exec_env_t)arg;
|
||||
wasm_exec_env_t parent_exec_env;
|
||||
wasm_module_inst_t module_inst = get_module_inst(exec_env);
|
||||
ThreadRoutineArgs *routine_args = exec_env->thread_arg;
|
||||
ThreadInfoNode *info_node = routine_args->info_node;
|
||||
uint32 argv[1];
|
||||
|
||||
parent_exec_env = info_node->parent_exec_env;
|
||||
os_mutex_lock(&parent_exec_env->wait_lock);
|
||||
info_node->exec_env = exec_env;
|
||||
info_node->u.thread = exec_env->handle;
|
||||
if (!append_thread_info_node(info_node)) {
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
delete_thread_info_node(info_node);
|
||||
os_cond_signal(&parent_exec_env->wait_cond);
|
||||
os_mutex_unlock(&parent_exec_env->wait_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info_node->status = THREAD_RUNNING;
|
||||
os_cond_signal(&parent_exec_env->wait_cond);
|
||||
os_mutex_unlock(&parent_exec_env->wait_lock);
|
||||
|
||||
if (!validate_native_addr(routine_args->arg, sizeof(uint32))) {
|
||||
/* If there are exceptions, copy the exception to
|
||||
all other instance in this cluster */
|
||||
wasm_cluster_spread_exception(exec_env);
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
delete_thread_info_node(info_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
argv[0] = addr_native_to_app(routine_args->arg);
|
||||
|
||||
if(!wasm_runtime_call_indirect(exec_env,
|
||||
routine_args->elem_index,
|
||||
1, argv)) {
|
||||
wasm_cluster_spread_exception(exec_env);
|
||||
}
|
||||
|
||||
/* routine exit, destroy instance */
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
|
||||
info_node->status = THREAD_EXIT;
|
||||
|
||||
delete_thread_info_node(info_node);
|
||||
|
||||
return (void *)(uintptr_t)argv[0];
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_create_wrapper(wasm_exec_env_t exec_env,
|
||||
uint32 *thread, /* thread_handle */
|
||||
const void *attr, /* not supported */
|
||||
uint32 elem_index, /* entry function */
|
||||
void *arg) /* arguments buffer */
|
||||
{
|
||||
wasm_module_t module = get_module(exec_env);
|
||||
wasm_module_inst_t new_module_inst = NULL;
|
||||
ThreadInfoNode *info_node = NULL;
|
||||
ThreadRoutineArgs *routine_args = NULL;
|
||||
uint32 thread_handle;
|
||||
int32 ret = -1;
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
wasm_module_inst_t module_inst = get_module_inst(exec_env);
|
||||
WASIContext *wasi_ctx = get_wasi_ctx(module_inst);
|
||||
#endif
|
||||
|
||||
if (!(new_module_inst =
|
||||
wasm_runtime_instantiate_internal(module, true, 8192, 0,
|
||||
NULL, 0)))
|
||||
return -1;
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
if (wasi_ctx)
|
||||
wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx);
|
||||
#endif
|
||||
|
||||
if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
|
||||
goto fail;
|
||||
|
||||
memset(info_node, 0, sizeof(ThreadInfoNode));
|
||||
thread_handle = allocate_handle();
|
||||
info_node->parent_exec_env = exec_env;
|
||||
info_node->handle = thread_handle;
|
||||
info_node->type = T_THREAD;
|
||||
info_node->status = THREAD_INIT;
|
||||
|
||||
if (!(routine_args = wasm_runtime_malloc(sizeof(ThreadRoutineArgs))))
|
||||
goto fail;
|
||||
|
||||
routine_args->arg = arg;
|
||||
routine_args->elem_index = elem_index;
|
||||
routine_args->info_node = info_node;
|
||||
routine_args->module_inst = new_module_inst;
|
||||
|
||||
os_mutex_lock(&exec_env->wait_lock);
|
||||
ret = wasm_cluster_create_thread(exec_env, new_module_inst,
|
||||
pthread_start_routine,
|
||||
(void *)routine_args);
|
||||
if (ret != 0) {
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Wait for the thread routine to assign the exec_env to
|
||||
thread_info_node, otherwise the exec_env in the thread
|
||||
info node may be NULL in the next pthread API call */
|
||||
os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock);
|
||||
os_mutex_unlock(&exec_env->wait_lock);
|
||||
|
||||
if (thread)
|
||||
*thread = thread_handle;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (new_module_inst)
|
||||
wasm_runtime_deinstantiate_internal(new_module_inst, true);
|
||||
if (info_node)
|
||||
wasm_runtime_free(info_node);
|
||||
if (routine_args)
|
||||
wasm_runtime_free(routine_args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread,
|
||||
int32 retval_offset) /* void **retval */
|
||||
{
|
||||
uint32 *ret;
|
||||
int32 join_ret;
|
||||
void **retval;
|
||||
ThreadInfoNode *node;
|
||||
wasm_module_inst_t module_inst;
|
||||
wasm_exec_env_t target_exec_env;
|
||||
|
||||
node = get_thread_info(exec_env, thread);
|
||||
if (!node) {
|
||||
/* The thread has exited, return 0 to app */
|
||||
return 0;
|
||||
}
|
||||
|
||||
target_exec_env = node->exec_env;
|
||||
bh_assert(target_exec_env != NULL);
|
||||
module_inst = get_module_inst(target_exec_env);
|
||||
|
||||
/* validate addr before join thread, otherwise
|
||||
the module_inst may be freed */
|
||||
if (!validate_app_addr(retval_offset, sizeof(uint32))) {
|
||||
/* Join failed, but we don't want to terminate all threads,
|
||||
do not spread exception here */
|
||||
wasm_runtime_set_exception(module_inst, NULL);
|
||||
return -1;
|
||||
}
|
||||
retval = (void **)addr_app_to_native(retval_offset);
|
||||
|
||||
join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret);
|
||||
|
||||
if (retval_offset != 0)
|
||||
*retval = (void*)ret;
|
||||
|
||||
return join_ret;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_detach_wrapper(wasm_exec_env_t exec_env, uint32 thread)
|
||||
{
|
||||
ThreadInfoNode *node;
|
||||
wasm_exec_env_t target_exec_env;
|
||||
|
||||
node = get_thread_info(exec_env, thread);
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
target_exec_env = node->exec_env;
|
||||
bh_assert(target_exec_env != NULL);
|
||||
|
||||
return wasm_cluster_detach_thread(target_exec_env);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cancel_wrapper(wasm_exec_env_t exec_env, uint32 thread)
|
||||
{
|
||||
ThreadInfoNode *node;
|
||||
wasm_exec_env_t target_exec_env;
|
||||
|
||||
node = get_thread_info(exec_env, thread);
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
target_exec_env = node->exec_env;
|
||||
bh_assert(target_exec_env != NULL);
|
||||
|
||||
return wasm_cluster_cancel_thread(target_exec_env);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_self_wrapper(wasm_exec_env_t exec_env)
|
||||
{
|
||||
ThreadRoutineArgs *args = get_thread_arg(exec_env);
|
||||
/* If thread_arg is NULL, it's the exec_env of the main thread,
|
||||
return id 0 to app */
|
||||
if (!args)
|
||||
return 0;
|
||||
|
||||
return args->info_node->handle;
|
||||
}
|
||||
|
||||
static void
|
||||
pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset)
|
||||
{
|
||||
wasm_module_inst_t module_inst = get_module_inst(exec_env);
|
||||
ThreadRoutineArgs *args = get_thread_arg(exec_env);
|
||||
/* Currently exit main thread is not allowed */
|
||||
if (!args)
|
||||
return;
|
||||
|
||||
/* routine exit, destroy instance */
|
||||
wasm_runtime_deinstantiate_internal(module_inst, true);
|
||||
|
||||
delete_thread_info_node(args->info_node);
|
||||
|
||||
wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_init_wrapper(wasm_exec_env_t exec_env, uint32 *mutex, void *attr)
|
||||
{
|
||||
korp_mutex *pmutex;
|
||||
ThreadInfoNode *info_node;
|
||||
|
||||
if (!(pmutex = wasm_runtime_malloc(sizeof(korp_mutex)))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_mutex_init(pmutex) != 0) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
|
||||
goto fail2;
|
||||
|
||||
memset(info_node, 0, sizeof(ThreadInfoNode));
|
||||
info_node->exec_env = exec_env;
|
||||
info_node->handle = allocate_handle();
|
||||
info_node->type = T_MUTEX;
|
||||
info_node->u.mutex = pmutex;
|
||||
info_node->status = MUTEX_CREATED;
|
||||
|
||||
if (!append_thread_info_node(info_node))
|
||||
goto fail3;
|
||||
|
||||
/* Return the mutex handle to app */
|
||||
if (mutex)
|
||||
*(uint32*)mutex = info_node->handle;
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
delete_thread_info_node(info_node);
|
||||
fail2:
|
||||
os_mutex_destroy(pmutex);
|
||||
fail1:
|
||||
wasm_runtime_free(pmutex);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_lock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
|
||||
{
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!info_node || info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_mutex_lock(info_node->u.mutex);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_unlock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
|
||||
{
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!info_node || info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_mutex_unlock(info_node->u.mutex);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_mutex_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *mutex)
|
||||
{
|
||||
int32 ret_val;
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!info_node || info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
ret_val = os_mutex_destroy(info_node->u.mutex);
|
||||
|
||||
info_node->status = MUTEX_DESTROYED;
|
||||
delete_thread_info_node(info_node);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_init_wrapper(wasm_exec_env_t exec_env, uint32 *cond, void *attr)
|
||||
{
|
||||
korp_cond *pcond;
|
||||
ThreadInfoNode *info_node;
|
||||
|
||||
if (!(pcond = wasm_runtime_malloc(sizeof(korp_cond)))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_cond_init(pcond) != 0) {
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode))))
|
||||
goto fail2;
|
||||
|
||||
memset(info_node, 0, sizeof(ThreadInfoNode));
|
||||
info_node->exec_env = exec_env;
|
||||
info_node->handle = allocate_handle();
|
||||
info_node->type = T_COND;
|
||||
info_node->u.cond = pcond;
|
||||
info_node->status = COND_CREATED;
|
||||
|
||||
if (!append_thread_info_node(info_node))
|
||||
goto fail3;
|
||||
|
||||
/* Return the cond handle to app */
|
||||
if (cond)
|
||||
*(uint32*)cond = info_node->handle;
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
delete_thread_info_node(info_node);
|
||||
fail2:
|
||||
os_cond_destroy(pcond);
|
||||
fail1:
|
||||
wasm_runtime_free(pcond);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_wait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, uint32 *mutex)
|
||||
{
|
||||
ThreadInfoNode *cond_info_node, *mutex_info_node;
|
||||
|
||||
cond_info_node = get_thread_info(exec_env, *cond);
|
||||
if (!cond_info_node || cond_info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
mutex_info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_cond_wait(cond_info_node->u.cond, mutex_info_node->u.mutex);
|
||||
}
|
||||
|
||||
/* Currently we don't support struct timespec in built-in libc,
|
||||
so the pthread_cond_timedwait use useconds instead
|
||||
*/
|
||||
static int32
|
||||
pthread_cond_timedwait_wrapper(wasm_exec_env_t exec_env, uint32 *cond,
|
||||
uint32 *mutex, uint32 useconds)
|
||||
{
|
||||
ThreadInfoNode *cond_info_node, *mutex_info_node;
|
||||
|
||||
cond_info_node = get_thread_info(exec_env, *cond);
|
||||
if (!cond_info_node || cond_info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
mutex_info_node = get_thread_info(exec_env, *mutex);
|
||||
if (!mutex_info_node || mutex_info_node->type != T_MUTEX)
|
||||
return -1;
|
||||
|
||||
return os_cond_reltimedwait(cond_info_node->u.cond,
|
||||
mutex_info_node->u.mutex, useconds);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
|
||||
{
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *cond);
|
||||
if (!info_node || info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
return os_cond_signal(info_node->u.cond);
|
||||
}
|
||||
|
||||
static int32
|
||||
pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond)
|
||||
{
|
||||
int32 ret_val;
|
||||
ThreadInfoNode* info_node = get_thread_info(exec_env, *cond);
|
||||
if (!info_node || info_node->type != T_COND)
|
||||
return -1;
|
||||
|
||||
ret_val = os_cond_destroy(info_node->u.cond);
|
||||
|
||||
info_node->status = COND_DESTROYED;
|
||||
delete_thread_info_node(info_node);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#define REG_NATIVE_FUNC(func_name, signature) \
|
||||
{ #func_name, func_name##_wrapper, signature, NULL }
|
||||
|
||||
static NativeSymbol native_symbols_lib_pthread[] = {
|
||||
REG_NATIVE_FUNC(pthread_create, "(**i*)i"),
|
||||
REG_NATIVE_FUNC(pthread_join, "(ii)i"),
|
||||
REG_NATIVE_FUNC(pthread_detach, "(i)i"),
|
||||
REG_NATIVE_FUNC(pthread_cancel, "(i)i"),
|
||||
REG_NATIVE_FUNC(pthread_self, "()i"),
|
||||
REG_NATIVE_FUNC(pthread_exit, "(i)"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_init, "(**)i"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_lock, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_unlock, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_mutex_destroy, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_init, "(**)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_timedwait, "(**i)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"),
|
||||
REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"),
|
||||
};
|
||||
|
||||
uint32
|
||||
get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis)
|
||||
{
|
||||
*p_lib_pthread_apis = native_symbols_lib_pthread;
|
||||
return sizeof(native_symbols_lib_pthread) / sizeof(NativeSymbol);
|
||||
}
|
||||
@ -1131,9 +1131,11 @@ typedef struct WASMNativeGlobalDef {
|
||||
} WASMNativeGlobalDef;
|
||||
|
||||
static WASMNativeGlobalDef native_global_defs[] = {
|
||||
#if WASM_ENABLE_SPEC_TEST != 0
|
||||
{ "spectest", "global_i32", .global_data.i32 = 666 },
|
||||
{ "spectest", "global_f32", .global_data.f32 = 666.6 },
|
||||
{ "spectest", "global_f64", .global_data.f64 = 666.6 },
|
||||
#endif
|
||||
{ "test", "global-i32", .global_data.i32 = 0 },
|
||||
{ "test", "global-f32", .global_data.f32 = 0 },
|
||||
{ "env", "STACKTOP", .global_data.u32 = 0 },
|
||||
|
||||
@ -58,6 +58,8 @@ static struct fd_table *
|
||||
wasi_ctx_get_curfds(wasm_module_inst_t module_inst,
|
||||
wasi_ctx_t wasi_ctx)
|
||||
{
|
||||
if (!wasi_ctx)
|
||||
return NULL;
|
||||
return (struct fd_table *)
|
||||
wasm_runtime_addr_app_to_native(module_inst,
|
||||
wasi_ctx->curfds_offset);
|
||||
@ -67,6 +69,8 @@ static struct argv_environ_values *
|
||||
wasi_ctx_get_argv_environ(wasm_module_inst_t module_inst,
|
||||
wasi_ctx_t wasi_ctx)
|
||||
{
|
||||
if (!wasi_ctx)
|
||||
return NULL;
|
||||
return (struct argv_environ_values *)
|
||||
wasm_runtime_addr_app_to_native(module_inst,
|
||||
wasi_ctx->argv_environ_offset);
|
||||
@ -76,6 +80,8 @@ static struct fd_prestats *
|
||||
wasi_ctx_get_prestats(wasm_module_inst_t module_inst,
|
||||
wasi_ctx_t wasi_ctx)
|
||||
{
|
||||
if (!wasi_ctx)
|
||||
return NULL;
|
||||
return (struct fd_prestats *)
|
||||
wasm_runtime_addr_app_to_native(module_inst,
|
||||
wasi_ctx->prestats_offset);
|
||||
@ -93,6 +99,9 @@ wasi_args_get(wasm_exec_env_t exec_env, int32 *argv_offsets, char *argv_buf)
|
||||
uint64 total_size;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
err = wasmtime_ssp_args_sizes_get(argv_environ, &argc, &argv_buf_size);
|
||||
if (err)
|
||||
return err;
|
||||
@ -133,6 +142,9 @@ wasi_args_sizes_get(wasm_exec_env_t exec_env,
|
||||
size_t argc, argv_buf_size;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(argc_app, sizeof(uint32))
|
||||
|| !validate_native_addr(argv_buf_size_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
@ -191,6 +203,9 @@ wasi_environ_get(wasm_exec_env_t exec_env,
|
||||
char **environs;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
err = wasmtime_ssp_environ_sizes_get(argv_environ,
|
||||
&environ_count, &environ_buf_size);
|
||||
if (err)
|
||||
@ -234,6 +249,9 @@ wasi_environ_sizes_get(wasm_exec_env_t exec_env,
|
||||
size_t environ_count, environ_buf_size;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(environ_count_app, sizeof(uint32))
|
||||
|| !validate_native_addr(environ_buf_size_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
@ -259,6 +277,9 @@ wasi_fd_prestat_get(wasm_exec_env_t exec_env,
|
||||
wasi_prestat_t prestat;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(prestat_app, sizeof(wasi_prestat_app_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -279,6 +300,9 @@ wasi_fd_prestat_dir_name(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_prestat_dir_name(prestats,
|
||||
fd, path, path_len);
|
||||
}
|
||||
@ -291,6 +315,9 @@ wasi_fd_close(wasm_exec_env_t exec_env, wasi_fd_t fd)
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_close(curfds, prestats, fd);
|
||||
}
|
||||
|
||||
@ -301,6 +328,9 @@ wasi_fd_datasync(wasm_exec_env_t exec_env, wasi_fd_t fd)
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_datasync(curfds, fd);
|
||||
}
|
||||
|
||||
@ -319,6 +349,9 @@ wasi_fd_pread(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nread_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -371,6 +404,9 @@ wasi_fd_pwrite(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -423,6 +459,9 @@ wasi_fd_read(wasm_exec_env_t exec_env,
|
||||
int32 mem;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nread_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -468,6 +507,9 @@ wasi_fd_renumber(wasm_exec_env_t exec_env, wasi_fd_t from, wasi_fd_t to)
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_renumber(curfds, prestats, from, to);
|
||||
}
|
||||
|
||||
@ -480,6 +522,9 @@ wasi_fd_seek(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -494,6 +539,9 @@ wasi_fd_tell(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -510,6 +558,9 @@ wasi_fd_fdstat_get(wasm_exec_env_t exec_env,
|
||||
wasi_fdstat_t fdstat;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(fdstat_app, sizeof(wasi_fdstat_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -529,6 +580,9 @@ wasi_fd_fdstat_set_flags(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_fdstat_set_flags(curfds, fd, flags);
|
||||
}
|
||||
|
||||
@ -542,6 +596,9 @@ wasi_fd_fdstat_set_rights(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_fdstat_set_rights(curfds, fd,
|
||||
fs_rights_base, fs_rights_inheriting);
|
||||
}
|
||||
@ -553,6 +610,9 @@ wasi_fd_sync(wasm_exec_env_t exec_env, wasi_fd_t fd)
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_sync(curfds, fd);
|
||||
}
|
||||
|
||||
@ -571,6 +631,9 @@ wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)iovs_len;
|
||||
if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -619,6 +682,9 @@ wasi_fd_advise(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_advise(curfds, fd, offset, len, advice);
|
||||
}
|
||||
|
||||
@ -632,6 +698,9 @@ wasi_fd_allocate(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_allocate(curfds, fd, offset, len);
|
||||
}
|
||||
|
||||
@ -643,6 +712,9 @@ wasi_path_create_directory(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_create_directory(curfds, fd,
|
||||
path, path_len);
|
||||
}
|
||||
@ -660,6 +732,9 @@ wasi_path_link(wasm_exec_env_t exec_env,
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_link(curfds, prestats,
|
||||
old_fd, old_flags, old_path, old_path_len,
|
||||
new_fd, new_path, new_path_len);
|
||||
@ -682,6 +757,9 @@ wasi_path_open(wasm_exec_env_t exec_env,
|
||||
wasi_fd_t fd = -1; /* set fd_app -1 if path open failed */
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(fd_app, sizeof(wasi_fd_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -711,6 +789,9 @@ wasi_fd_readdir(wasm_exec_env_t exec_env,
|
||||
size_t bufused;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(bufused_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -736,6 +817,9 @@ wasi_path_readlink(wasm_exec_env_t exec_env,
|
||||
size_t bufused;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(bufused_app, sizeof(uint32)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -758,6 +842,9 @@ wasi_path_rename(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_rename(curfds,
|
||||
old_fd, old_path, old_path_len,
|
||||
new_fd, new_path, new_path_len);
|
||||
@ -771,6 +858,9 @@ wasi_fd_filestat_get(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(filestat, sizeof(wasi_filestat_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -788,6 +878,9 @@ wasi_fd_filestat_set_times(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_filestat_set_times(curfds, fd,
|
||||
st_atim, st_mtim, fstflags);
|
||||
}
|
||||
@ -801,6 +894,9 @@ wasi_fd_filestat_set_size(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_fd_filestat_set_size(curfds, fd, st_size);
|
||||
}
|
||||
|
||||
@ -815,6 +911,9 @@ wasi_path_filestat_get(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr(filestat, sizeof(wasi_filestat_t)))
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
@ -835,6 +934,9 @@ wasi_path_filestat_set_times(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_filestat_set_times(curfds, fd,
|
||||
flags, path, path_len,
|
||||
st_atim, st_mtim, fstflags);
|
||||
@ -850,6 +952,9 @@ wasi_path_symlink(wasm_exec_env_t exec_env,
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_symlink(curfds, prestats,
|
||||
old_path, old_path_len, fd,
|
||||
new_path, new_path_len);
|
||||
@ -863,6 +968,9 @@ wasi_path_unlink_file(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_unlink_file(curfds, fd, path, path_len);
|
||||
}
|
||||
|
||||
@ -874,6 +982,9 @@ wasi_path_remove_directory(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len);
|
||||
}
|
||||
|
||||
@ -888,6 +999,9 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env,
|
||||
size_t nevents;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
if (!validate_native_addr((void*)in, sizeof(wasi_subscription_t))
|
||||
|| !validate_native_addr(out, sizeof(wasi_event_t))
|
||||
|| !validate_native_addr(nevents_app, sizeof(uint32)))
|
||||
@ -943,6 +1057,9 @@ wasi_sock_recv(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)ri_data_len;
|
||||
if (!validate_native_addr(ro_datalen_app, (uint32)sizeof(uint32))
|
||||
|| !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t))
|
||||
@ -1000,6 +1117,9 @@ wasi_sock_send(wasm_exec_env_t exec_env,
|
||||
uint32 i;
|
||||
wasi_errno_t err;
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
total_size = sizeof(iovec_app_t) * (uint64)si_data_len;
|
||||
if (!validate_native_addr(so_datalen_app, sizeof(uint32))
|
||||
|| total_size >= UINT32_MAX
|
||||
@ -1046,6 +1166,9 @@ wasi_sock_shutdown(wasm_exec_env_t exec_env,
|
||||
wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst);
|
||||
struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx);
|
||||
|
||||
if (!wasi_ctx)
|
||||
return (wasi_errno_t)-1;
|
||||
|
||||
return wasmtime_ssp_sock_shutdown(curfds, sock, how);
|
||||
}
|
||||
|
||||
|
||||
523
core/iwasm/libraries/thread-mgr/thread_manager.c
Normal file
523
core/iwasm/libraries/thread-mgr/thread_manager.c
Normal file
@ -0,0 +1,523 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "thread_manager.h"
|
||||
|
||||
typedef struct {
|
||||
bh_list_link l;
|
||||
|
||||
void (*destroy_cb)(WASMCluster *);
|
||||
} DestroyCallBackNode;
|
||||
|
||||
static bh_list destroy_callback_list_head;
|
||||
static bh_list *const destroy_callback_list = &destroy_callback_list_head;
|
||||
|
||||
static bh_list cluster_list_head;
|
||||
static bh_list *const cluster_list = &cluster_list_head;
|
||||
static korp_mutex cluster_list_lock;
|
||||
|
||||
typedef void (*list_visitor)(void *, void *);
|
||||
|
||||
static uint32 cluster_max_thread_num = CLUSTER_MAX_THREAD_NUM;
|
||||
|
||||
/* Set the maximum thread number, if this function is not called,
|
||||
the max thread num is defined by CLUSTER_MAX_THREAD_NUM */
|
||||
void
|
||||
wasm_cluster_set_max_thread_num(uint32 num)
|
||||
{
|
||||
cluster_max_thread_num = num;
|
||||
}
|
||||
|
||||
bool
|
||||
thread_manager_init()
|
||||
{
|
||||
if (bh_list_init(cluster_list) != 0)
|
||||
return false;
|
||||
if (os_mutex_init(&cluster_list_lock) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
thread_manager_destroy()
|
||||
{
|
||||
WASMCluster *cluster = bh_list_first_elem(cluster_list);
|
||||
WASMCluster *next;
|
||||
while (cluster) {
|
||||
next = bh_list_elem_next(cluster);
|
||||
wasm_cluster_destroy(cluster);
|
||||
cluster = next;
|
||||
}
|
||||
wasm_cluster_cancel_all_callbacks();
|
||||
os_mutex_destroy(&cluster_list_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_list(bh_list *l, list_visitor visitor, void *user_data)
|
||||
{
|
||||
void *next, *node = bh_list_first_elem(l);
|
||||
while (node) {
|
||||
next = bh_list_elem_next(node);
|
||||
visitor(node, user_data);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
/* If the module doesn't have aux stack info,
|
||||
it can't create any threads */
|
||||
if (!cluster->stack_segment_occupied)
|
||||
return false;
|
||||
|
||||
os_mutex_lock(&cluster->lock);
|
||||
for (i = 0; i < cluster_max_thread_num; i++) {
|
||||
if (!cluster->stack_segment_occupied[i]) {
|
||||
if (start)
|
||||
*start = cluster->stack_tops[i];
|
||||
if (size)
|
||||
*size = cluster->stack_size;
|
||||
cluster->stack_segment_occupied[i] = true;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
free_aux_stack(WASMCluster *cluster, uint32 start)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < cluster_max_thread_num; i++) {
|
||||
if (start == cluster->stack_tops[i]) {
|
||||
os_mutex_lock(&cluster->lock);
|
||||
cluster->stack_segment_occupied[i] = false;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WASMCluster *
|
||||
wasm_cluster_create(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
uint64 total_size;
|
||||
uint32 aux_stack_start, aux_stack_size, i;
|
||||
|
||||
bh_assert(exec_env->cluster == NULL);
|
||||
if (!(cluster = wasm_runtime_malloc(sizeof(WASMCluster)))) {
|
||||
LOG_ERROR("thread manager error: failed to allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
memset(cluster, 0, sizeof(WASMCluster));
|
||||
|
||||
exec_env->cluster = cluster;
|
||||
|
||||
bh_list_init(&cluster->exec_env_list);
|
||||
bh_list_insert(&cluster->exec_env_list, exec_env);
|
||||
if (os_mutex_init(&cluster->lock) != 0) {
|
||||
wasm_runtime_free(cluster);
|
||||
LOG_ERROR("thread manager error: failed to init mutex");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Prepare the aux stack top and size for every thread */
|
||||
if (!wasm_exec_env_get_aux_stack(exec_env,
|
||||
&aux_stack_start,
|
||||
&aux_stack_size)) {
|
||||
LOG_VERBOSE("No aux stack info for this module, can't create thread");
|
||||
|
||||
/* If the module don't have aux stack info, don't throw error here,
|
||||
but remain stack_tops and stack_segment_occupied as NULL */
|
||||
os_mutex_lock(&cluster_list_lock);
|
||||
if (bh_list_insert(cluster_list, cluster) != 0) {
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
goto fail;
|
||||
}
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
cluster->stack_size = aux_stack_size / (cluster_max_thread_num + 1);
|
||||
if (cluster->stack_size == 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set initial aux stack top to the instance and
|
||||
aux stack boundary to the main exec_env */
|
||||
if (!wasm_exec_env_set_aux_stack(exec_env, aux_stack_start,
|
||||
cluster->stack_size))
|
||||
goto fail;
|
||||
|
||||
if (cluster_max_thread_num != 0) {
|
||||
total_size = cluster_max_thread_num * sizeof(uint32);
|
||||
if (total_size >= UINT32_MAX
|
||||
|| !(cluster->stack_tops =
|
||||
wasm_runtime_malloc((uint32)total_size))) {
|
||||
goto fail;
|
||||
}
|
||||
memset(cluster->stack_tops, 0, (uint32)total_size);
|
||||
|
||||
if (!(cluster->stack_segment_occupied =
|
||||
wasm_runtime_malloc(cluster_max_thread_num * sizeof(bool)))) {
|
||||
goto fail;
|
||||
}
|
||||
memset(cluster->stack_segment_occupied, 0,
|
||||
cluster_max_thread_num * sizeof(bool));
|
||||
|
||||
/* Reserve space for main instance */
|
||||
aux_stack_start -= cluster->stack_size;
|
||||
|
||||
for (i = 0; i < cluster_max_thread_num; i++) {
|
||||
cluster->stack_tops[i] = aux_stack_start - cluster->stack_size * i;
|
||||
}
|
||||
}
|
||||
|
||||
os_mutex_lock(&cluster_list_lock);
|
||||
if (bh_list_insert(cluster_list, cluster) != 0) {
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
goto fail;
|
||||
}
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
|
||||
return cluster;
|
||||
|
||||
fail:
|
||||
if (cluster)
|
||||
wasm_cluster_destroy(cluster);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_cluster_visitor(void *node, void *user_data)
|
||||
{
|
||||
DestroyCallBackNode *destroy_node = (DestroyCallBackNode *)node;
|
||||
WASMCluster *cluster = (WASMCluster *)user_data;
|
||||
|
||||
destroy_node->destroy_cb(cluster);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_destroy(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(destroy_callback_list,
|
||||
destroy_cluster_visitor, (void *)cluster);
|
||||
|
||||
/* Remove the cluster from the cluster list */
|
||||
os_mutex_lock(&cluster_list_lock);
|
||||
bh_list_remove(cluster_list, cluster);
|
||||
os_mutex_unlock(&cluster_list_lock);
|
||||
|
||||
os_mutex_destroy(&cluster->lock);
|
||||
|
||||
if (cluster->stack_tops)
|
||||
wasm_runtime_free(cluster->stack_tops);
|
||||
if (cluster->stack_segment_occupied)
|
||||
wasm_runtime_free(cluster->stack_segment_occupied);
|
||||
wasm_runtime_free(cluster);
|
||||
}
|
||||
|
||||
static void
|
||||
free_node_visitor(void *node, void *user_data)
|
||||
{
|
||||
wasm_runtime_free(node);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_cancel_all_callbacks()
|
||||
{
|
||||
traverse_list(destroy_callback_list, free_node_visitor, NULL);
|
||||
}
|
||||
|
||||
WASMCluster *
|
||||
wasm_exec_env_get_cluster(WASMExecEnv *exec_env)
|
||||
{
|
||||
return exec_env->cluster;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
exec_env->cluster = cluster;
|
||||
|
||||
os_mutex_lock(&cluster->lock);
|
||||
if (bh_list_insert(&cluster->exec_env_list, exec_env) != 0)
|
||||
ret = false;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
|
||||
{
|
||||
bool ret = true;
|
||||
bh_assert(exec_env->cluster == cluster);
|
||||
os_mutex_lock(&cluster->lock);
|
||||
if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0)
|
||||
ret = false;
|
||||
os_mutex_unlock(&cluster->lock);
|
||||
|
||||
if (cluster->exec_env_list.len == 0) {
|
||||
/* exec_env_list empty, destroy the cluster */
|
||||
wasm_cluster_destroy(cluster);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* start routine of thread manager */
|
||||
static void*
|
||||
thread_manager_start_routine(void *arg)
|
||||
{
|
||||
void *ret;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)arg;
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster != NULL);
|
||||
|
||||
exec_env->handle = os_self_thread();
|
||||
ret = exec_env->thread_start_routine(exec_env);
|
||||
|
||||
/* Routine exit */
|
||||
/* Free aux stack space */
|
||||
free_aux_stack(cluster,
|
||||
exec_env->aux_stack_boundary + cluster->stack_size);
|
||||
/* Detach the native thread here to ensure the resources are freed */
|
||||
wasm_cluster_detach_thread(exec_env);
|
||||
/* Remove and destroy exec_env */
|
||||
wasm_cluster_del_exec_env(cluster, exec_env);
|
||||
wasm_exec_env_destroy_internal(exec_env);
|
||||
|
||||
os_thread_exit(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_create_thread(WASMExecEnv *exec_env,
|
||||
wasm_module_inst_t module_inst,
|
||||
void* (*thread_routine)(void *),
|
||||
void *arg)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
WASMExecEnv *new_exec_env;
|
||||
uint32 aux_stack_start, aux_stack_size;
|
||||
korp_tid tid;
|
||||
|
||||
cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
new_exec_env = wasm_exec_env_create_internal(
|
||||
module_inst, exec_env->wasm_stack_size);
|
||||
if (!new_exec_env)
|
||||
return -1;
|
||||
|
||||
if (!allocate_aux_stack(cluster, &aux_stack_start, &aux_stack_size)) {
|
||||
LOG_ERROR("thread manager error: "
|
||||
"failed to allocate aux stack space for new thread");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* Set aux stack for current thread */
|
||||
if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start,
|
||||
aux_stack_size)) {
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (!wasm_cluster_add_exec_env(cluster, new_exec_env))
|
||||
goto fail2;
|
||||
|
||||
new_exec_env->thread_start_routine = thread_routine;
|
||||
new_exec_env->thread_arg = arg;
|
||||
|
||||
if (0 != os_thread_create(&tid, thread_manager_start_routine,
|
||||
(void *)new_exec_env,
|
||||
APP_THREAD_STACK_SIZE_DEFAULT)) {
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
wasm_cluster_del_exec_env(cluster, new_exec_env);
|
||||
fail2:
|
||||
/* free the allocated aux stack space */
|
||||
free_aux_stack(cluster, aux_stack_start);
|
||||
fail1:
|
||||
wasm_exec_env_destroy(new_exec_env);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
|
||||
{
|
||||
return os_thread_join(exec_env->handle, ret_val);
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_detach_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
return os_thread_detach(exec_env->handle);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
|
||||
{
|
||||
WASMCluster *cluster;
|
||||
|
||||
cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
bh_assert(cluster);
|
||||
|
||||
/* App exit the thread, free the resources before exit native thread */
|
||||
/* Free aux stack space */
|
||||
free_aux_stack(cluster,
|
||||
exec_env->aux_stack_boundary + cluster->stack_size);
|
||||
/* Detach the native thread here to ensure the resources are freed */
|
||||
wasm_cluster_detach_thread(exec_env);
|
||||
/* Remove and destroy exec_env */
|
||||
wasm_cluster_del_exec_env(cluster, exec_env);
|
||||
wasm_exec_env_destroy_internal(exec_env);
|
||||
|
||||
os_thread_exit(retval);
|
||||
}
|
||||
|
||||
int32
|
||||
wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
/* Set the termination flag */
|
||||
exec_env->suspend_flags |= 0x01;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
terminate_thread_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
|
||||
|
||||
if (curr_exec_env == exec_env)
|
||||
return;
|
||||
|
||||
wasm_cluster_cancel_thread(curr_exec_env);
|
||||
wasm_cluster_join_thread(curr_exec_env, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
terminate_thread_visitor, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
terminate_thread_visitor, (void *)exec_env);
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *))
|
||||
{
|
||||
DestroyCallBackNode *node;
|
||||
|
||||
if (!(node = wasm_runtime_malloc(sizeof(DestroyCallBackNode)))) {
|
||||
LOG_ERROR("thread manager error: failed to allocate memory");
|
||||
return false;
|
||||
}
|
||||
node->destroy_cb = callback;
|
||||
bh_list_insert(destroy_callback_list, node);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
/* Set the suspend flag */
|
||||
exec_env->suspend_flags |= 0x02;
|
||||
}
|
||||
|
||||
static void
|
||||
suspend_thread_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
|
||||
|
||||
if (curr_exec_env == exec_env)
|
||||
return;
|
||||
|
||||
wasm_cluster_suspend_thread(curr_exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
suspend_thread_visitor, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list,
|
||||
suspend_thread_visitor, (void *)exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_resume_thread(WASMExecEnv *exec_env)
|
||||
{
|
||||
exec_env->suspend_flags &= ~0x02;
|
||||
}
|
||||
|
||||
static void
|
||||
resume_thread_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
|
||||
wasm_cluster_resume_thread(curr_exec_env);
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_resume_all(WASMCluster *cluster)
|
||||
{
|
||||
traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
set_exception_visitor(void *node, void *user_data)
|
||||
{
|
||||
WASMExecEnv *curr_exec_env = (WASMExecEnv *)node;
|
||||
WASMExecEnv *exec_env = (WASMExecEnv *)user_data;
|
||||
WASMModuleInstanceCommon *module_inst = get_module_inst(exec_env);
|
||||
WASMModuleInstanceCommon *curr_module_inst =
|
||||
get_module_inst(curr_exec_env);
|
||||
const char *exception = wasm_runtime_get_exception(module_inst);
|
||||
/* skip "Exception: " */
|
||||
exception += 11;
|
||||
|
||||
if (curr_exec_env != exec_env) {
|
||||
curr_module_inst = get_module_inst(curr_exec_env);
|
||||
wasm_runtime_set_exception(curr_module_inst, exception);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wasm_cluster_spread_exception(WASMExecEnv *exec_env)
|
||||
{
|
||||
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
|
||||
|
||||
traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env);
|
||||
}
|
||||
116
core/iwasm/libraries/thread-mgr/thread_manager.h
Normal file
116
core/iwasm/libraries/thread-mgr/thread_manager.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _THREAD_MANAGER_H
|
||||
#define _THREAD_MANAGER_H
|
||||
|
||||
#include "bh_common.h"
|
||||
#include "bh_log.h"
|
||||
#include "wasm_export.h"
|
||||
#include "../interpreter/wasm.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct WASMCluster
|
||||
{
|
||||
struct WASMCluster *next;
|
||||
|
||||
korp_mutex lock;
|
||||
bh_list exec_env_list;
|
||||
|
||||
/* The aux stack of a module with shared memory will be
|
||||
divided into several segments. This array store the
|
||||
stack top of different segments */
|
||||
uint32 *stack_tops;
|
||||
/* Size of every stack segment */
|
||||
uint32 stack_size;
|
||||
/* Record which segments are occupied */
|
||||
bool *stack_segment_occupied;
|
||||
} WASMCluster;
|
||||
|
||||
void wasm_cluster_set_max_thread_num(uint32 num);
|
||||
|
||||
bool
|
||||
thread_manager_init();
|
||||
|
||||
void
|
||||
thread_manager_destroy();
|
||||
|
||||
/* Create cluster */
|
||||
WASMCluster *
|
||||
wasm_cluster_create(WASMExecEnv *exec_env);
|
||||
|
||||
/* Destroy cluster */
|
||||
void
|
||||
wasm_cluster_destroy(WASMCluster *cluster);
|
||||
|
||||
/* Get the cluster of the current exec_env */
|
||||
WASMCluster*
|
||||
wasm_exec_env_get_cluster(WASMExecEnv *exec_env);
|
||||
|
||||
int32
|
||||
wasm_cluster_create_thread(WASMExecEnv *exec_env,
|
||||
wasm_module_inst_t module_inst,
|
||||
void* (*thread_routine)(void *),
|
||||
void *arg);
|
||||
|
||||
int32
|
||||
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val);
|
||||
|
||||
int32
|
||||
wasm_cluster_detach_thread(WASMExecEnv *exec_env);
|
||||
|
||||
int32
|
||||
wasm_cluster_cancel_thread(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval);
|
||||
|
||||
bool
|
||||
wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *));
|
||||
|
||||
void
|
||||
wasm_cluster_cancel_all_callbacks();
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all(WASMCluster *cluster);
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_suspend_thread(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_resume_thread(WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_resume_all(WASMCluster *cluster);
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all(WASMCluster *cluster);
|
||||
|
||||
void
|
||||
wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
|
||||
WASMExecEnv *exec_env);
|
||||
|
||||
bool
|
||||
wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env);
|
||||
|
||||
bool
|
||||
wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env);
|
||||
|
||||
void
|
||||
wasm_cluster_spread_exception(WASMExecEnv *exec_env);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* end of _THREAD_MANAGER_H */
|
||||
13
core/iwasm/libraries/thread-mgr/thread_mgr.cmake
Normal file
13
core/iwasm/libraries/thread-mgr/thread_mgr.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
set (THREAD_MGR_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_definitions (-DWASM_ENABLE_THREAD_MGR=1)
|
||||
|
||||
include_directories(${THREAD_MGR_DIR})
|
||||
|
||||
file (GLOB source_all ${THREAD_MGR_DIR}/*.c)
|
||||
|
||||
set (THREAD_MGR_SOURCE ${source_all})
|
||||
|
||||
Reference in New Issue
Block a user