implement atomic opcode in AOT/JIT (#329)

This commit is contained in:
Xu Jun
2020-08-03 11:30:26 +08:00
committed by GitHub
parent cc05f8fb1c
commit 29e45e1527
20 changed files with 1447 additions and 158 deletions

View File

@ -7,7 +7,12 @@
#include "wasm_runtime_common.h"
#include "bh_log.h"
#if !defined(BH_PLATFORM_ZEPHYR) && !defined(BH_PLATFORM_ALIOS_THINGS)
#define ENABLE_QUICKSORT 1
#else
#define ENABLE_QUICKSORT 0
#endif
#define ENABLE_SORT_DEBUG 0
#if ENABLE_SORT_DEBUG != 0

View File

@ -10,11 +10,50 @@ static bh_list shared_memory_list_head;
static bh_list *const shared_memory_list = &shared_memory_list_head;
static korp_mutex shared_memory_list_lock;
enum {
S_WAITING, S_NOTIFIED
};
typedef struct AtomicWaitInfo {
korp_mutex wait_list_lock;
bh_list wait_list_head;
bh_list *wait_list;
} AtomicWaitInfo;
typedef struct AtomicWaitNode {
bh_list_link l;
uint8 status;
korp_mutex wait_lock;
korp_cond wait_cond;
} AtomicWaitNode;
/* Atomic wait map */
static HashMap *wait_map;
static uint32
wait_address_hash(void *address);
static bool
wait_address_equal(void *h1, void *h2);
static void
destroy_wait_info(void *wait_info);
bool
wasm_shared_memory_init()
{
if (os_mutex_init(&shared_memory_list_lock) != 0)
return false;
/* wait map not exists, create new map */
if (!(wait_map =
bh_hash_map_create(32, true,
(HashFunc)wait_address_hash,
(KeyEqualFunc)wait_address_equal,
NULL, destroy_wait_info))) {
os_mutex_destroy(&shared_memory_list_lock);
return false;
}
return true;
}
@ -22,6 +61,9 @@ void
wasm_shared_memory_destroy()
{
os_mutex_destroy(&shared_memory_list_lock);
if (wait_map) {
bh_hash_map_destroy(wait_map);
}
}
static WASMSharedMemNode*
@ -118,3 +160,260 @@ shared_memory_set_memory_inst(WASMModuleCommon *module,
(void)ret;
return node;
}
/* Atomics wait && notify APIs */
static uint32
wait_address_hash(void *address)
{
return (uint32)(uintptr_t)address;
}
static bool
wait_address_equal(void *h1, void *h2)
{
return h1 == h2 ? true : false;
}
static bool
is_wait_node_exists(bh_list *wait_list, AtomicWaitNode *node)
{
AtomicWaitNode *curr;
curr = bh_list_first_elem(wait_list);
while (curr) {
if (curr == node) {
return true;
}
curr = bh_list_elem_next(curr);
}
return false;
}
static uint32
notify_wait_list(bh_list *wait_list, uint32 count)
{
AtomicWaitNode *node, *next;
uint32 i, notify_count = count;
if ((count == UINT32_MAX) || (count > wait_list->len))
notify_count = wait_list->len;
node = bh_list_first_elem(wait_list);
for (i = 0; i < count; i++) {
bh_assert(node);
next = bh_list_elem_next(node);
node->status = S_NOTIFIED;
/* wakeup */
os_cond_signal(&node->wait_cond);
node = next;
}
return notify_count;
}
static AtomicWaitInfo *
acquire_wait_info(void *address, bool create)
{
AtomicWaitInfo *wait_info = NULL;
bh_list_status ret;
wait_info = (AtomicWaitInfo *)
bh_hash_map_find(wait_map, address);
if (!create)
return wait_info;
/* No wait info on this address, create new info */
if (!wait_info) {
if (!(wait_info =
(AtomicWaitInfo *)wasm_runtime_malloc(sizeof(AtomicWaitInfo))))
return NULL;
memset(wait_info, 0, sizeof(AtomicWaitInfo));
/* init wait list */
wait_info->wait_list = &wait_info->wait_list_head;
ret = bh_list_init(wait_info->wait_list);
bh_assert(ret == BH_LIST_SUCCESS);
/* init wait list lock */
if (0 != os_mutex_init(&wait_info->wait_list_lock)) {
wasm_runtime_free(wait_info);
return NULL;
}
if (!bh_hash_map_insert(wait_map, address,
(void *)wait_info)) {
os_mutex_destroy(&wait_info->wait_list_lock);
wasm_runtime_free(wait_info);
return NULL;
}
}
bh_assert(wait_info);
(void)ret;
return wait_info;
}
static void
destroy_wait_info(void *wait_info)
{
AtomicWaitNode *node, *next;
if (wait_info) {
node = bh_list_first_elem(((AtomicWaitInfo *)wait_info)->wait_list);
while (node) {
next = bh_list_elem_next(node);
os_mutex_destroy(&node->wait_lock);
os_cond_destroy(&node->wait_cond);
wasm_runtime_free(node);
node = next;
}
os_mutex_destroy(&((AtomicWaitInfo *)wait_info)->wait_list_lock);
wasm_runtime_free(wait_info);
}
}
static void
release_wait_info(HashMap *wait_map,
AtomicWaitInfo *wait_info, void *address)
{
if (wait_info->wait_list->len == 0) {
bh_hash_map_remove(wait_map, address, NULL, NULL);
destroy_wait_info(wait_info);
}
}
uint32
wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
uint64 expect, int64 timeout, bool wait64)
{
AtomicWaitInfo *wait_info;
AtomicWaitNode *wait_node;
bool check_ret, is_timeout;
#if WASM_ENABLE_INTERP != 0
if (module->module_type == Wasm_Module_Bytecode) {
WASMModuleInstance *module_inst = (WASMModuleInstance *)module;
/* Currently we have only one memory instance */
if (!module_inst->memories[0]->is_shared) {
wasm_runtime_set_exception(module, "wait on unshared memory");
return -1;
}
}
#endif
#if WASM_ENABLE_AOT != 0
if (module->module_type == Wasm_Module_AoT) {
AOTModuleInstance *aot_inst = (AOTModuleInstance *)module;
AOTMemoryInstance *aot_memory =
((AOTMemoryInstance **)aot_inst->memories.ptr)[0];
/* Currently we have only one memory instance */
if (!aot_memory->is_shared) {
wasm_runtime_set_exception(module, "wait on unshared memory");
return -1;
}
}
#endif
/* acquire the wait info, create new one if not exists */
wait_info = acquire_wait_info(address, true);
if (!wait_info) {
wasm_runtime_set_exception(module, "failed to acquire wait_info");
return -1;
}
os_mutex_lock(&wait_info->wait_list_lock);
if ((!wait64 && *(uint32*)address != (uint32)expect)
|| (wait64 && *(uint64*)address != expect)) {
os_mutex_unlock(&wait_info->wait_list_lock);
return 1;
}
else {
bh_list_status ret;
if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) {
wasm_runtime_set_exception(module, "failed to create wait node");
os_mutex_unlock(&wait_info->wait_list_lock);
return -1;
}
memset(wait_node, 0, sizeof(AtomicWaitNode));
if (0 != os_mutex_init(&wait_node->wait_lock)) {
wasm_runtime_free(wait_node);
os_mutex_unlock(&wait_info->wait_list_lock);
return -1;
}
if (0 != os_cond_init(&wait_node->wait_cond)) {
os_mutex_destroy(&wait_node->wait_lock);
wasm_runtime_free(wait_node);
os_mutex_unlock(&wait_info->wait_list_lock);
return -1;
}
wait_node->status = S_WAITING;
ret = bh_list_insert(wait_info->wait_list, wait_node);
bh_assert(ret == BH_LIST_SUCCESS);
(void)ret;
}
os_mutex_unlock(&wait_info->wait_list_lock);
/* condition wait start */
os_mutex_lock(&wait_node->wait_lock);
if (timeout < 0)
timeout = BHT_WAIT_FOREVER;
os_cond_reltimedwait(&wait_node->wait_cond,
&wait_node->wait_lock, timeout);
os_mutex_unlock(&wait_node->wait_lock);
/* Check the wait node status */
os_mutex_lock(&wait_info->wait_list_lock);
check_ret = is_wait_node_exists(wait_info->wait_list, wait_node);
bh_assert(check_ret);
is_timeout = wait_node->status == S_WAITING ? true : false;
bh_list_remove(wait_info->wait_list, wait_node);
os_mutex_destroy(&wait_node->wait_lock);
os_cond_destroy(&wait_node->wait_cond);
wasm_runtime_free(wait_node);
os_mutex_unlock(&wait_info->wait_list_lock);
release_wait_info(wait_map, wait_info, address);
(void)check_ret;
return is_timeout ? 2 : 0;
}
uint8
wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module,
void *address, uint32 count)
{
uint32 notify_result;
AtomicWaitInfo *wait_info;
/* Nobody wait on this address */
wait_info = acquire_wait_info(address, false);
if (!wait_info)
return 0;
os_mutex_lock(&wait_info->wait_list_lock);
notify_result = notify_wait_list(wait_info->wait_list, count);
os_mutex_unlock(&wait_info->wait_list_lock);
release_wait_info(wait_map, wait_info, address);
return notify_result;
}

View File

@ -53,6 +53,13 @@ WASMSharedMemNode*
shared_memory_set_memory_inst(WASMModuleCommon *module,
WASMMemoryInstanceCommon *memory);
uint32
wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
uint64 expect, int64 timeout, bool wait64);
uint8
wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module,
void *address, uint32 count);
#ifdef __cplusplus
}