|
|
@@ -37,6 +37,7 @@ typedef struct AtomicWaitAddressArgs {
|
|
|
|
|
|
/* Atomic wait map */
|
|
|
static HashMap *wait_map;
|
|
|
+static korp_mutex wait_map_lock;
|
|
|
|
|
|
static uint32
|
|
|
wait_address_hash(void *address);
|
|
|
@@ -52,11 +53,18 @@ wasm_shared_memory_init()
|
|
|
{
|
|
|
if (os_mutex_init(&shared_memory_list_lock) != 0)
|
|
|
return false;
|
|
|
+
|
|
|
+ if (os_mutex_init(&wait_map_lock) != 0) {
|
|
|
+ os_mutex_destroy(&shared_memory_list_lock);
|
|
|
+ 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);
|
|
|
+ os_mutex_destroy(&wait_map_lock);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
@@ -67,6 +75,7 @@ void
|
|
|
wasm_shared_memory_destroy()
|
|
|
{
|
|
|
os_mutex_destroy(&shared_memory_list_lock);
|
|
|
+ os_mutex_destroy(&wait_map_lock);
|
|
|
if (wait_map) {
|
|
|
bh_hash_map_destroy(wait_map);
|
|
|
}
|
|
|
@@ -113,14 +122,14 @@ notify_stale_threads_on_exception(WASMModuleInstanceCommon *module_inst)
|
|
|
uint32 i = 0, total_elem_count = 0;
|
|
|
uint64 total_elem_count_size = 0;
|
|
|
|
|
|
- os_mutex_lock(&shared_memory_list_lock);
|
|
|
+ os_mutex_lock(&wait_map_lock); /* Make the two traversals atomic */
|
|
|
|
|
|
/* count number of addresses in wait_map */
|
|
|
bh_hash_map_traverse(wait_map, wait_map_address_count_callback,
|
|
|
(void *)&total_elem_count);
|
|
|
|
|
|
if (!total_elem_count) {
|
|
|
- os_mutex_unlock(&shared_memory_list_lock);
|
|
|
+ os_mutex_unlock(&wait_map_lock);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -130,13 +139,13 @@ notify_stale_threads_on_exception(WASMModuleInstanceCommon *module_inst)
|
|
|
|| !(args.addr = wasm_runtime_malloc((uint32)total_elem_count_size))) {
|
|
|
LOG_ERROR(
|
|
|
"failed to allocate memory for list of atomic wait addresses");
|
|
|
- os_mutex_unlock(&shared_memory_list_lock);
|
|
|
+ os_mutex_unlock(&wait_map_lock);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/* set values in list of addresses */
|
|
|
bh_hash_map_traverse(wait_map, create_list_of_waiter_addresses, &args);
|
|
|
- os_mutex_unlock(&shared_memory_list_lock);
|
|
|
+ os_mutex_unlock(&wait_map_lock);
|
|
|
|
|
|
/* notify */
|
|
|
for (i = 0; i < args.index; i++) {
|
|
|
@@ -276,9 +285,11 @@ notify_wait_list(bh_list *wait_list, uint32 count)
|
|
|
bh_assert(node);
|
|
|
next = bh_list_elem_next(node);
|
|
|
|
|
|
+ os_mutex_lock(&node->wait_lock);
|
|
|
node->status = S_NOTIFIED;
|
|
|
/* wakeup */
|
|
|
os_cond_signal(&node->wait_cond);
|
|
|
+ os_mutex_unlock(&node->wait_lock);
|
|
|
|
|
|
node = next;
|
|
|
}
|
|
|
@@ -292,13 +303,13 @@ acquire_wait_info(void *address, bool create)
|
|
|
AtomicWaitInfo *wait_info = NULL;
|
|
|
bh_list_status ret;
|
|
|
|
|
|
- os_mutex_lock(&shared_memory_list_lock);
|
|
|
+ os_mutex_lock(&wait_map_lock); /* Make find + insert atomic */
|
|
|
|
|
|
if (address)
|
|
|
wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address);
|
|
|
|
|
|
if (!create) {
|
|
|
- os_mutex_unlock(&shared_memory_list_lock);
|
|
|
+ os_mutex_unlock(&wait_map_lock);
|
|
|
return wait_info;
|
|
|
}
|
|
|
|
|
|
@@ -325,7 +336,7 @@ acquire_wait_info(void *address, bool create)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- os_mutex_unlock(&shared_memory_list_lock);
|
|
|
+ os_mutex_unlock(&wait_map_lock);
|
|
|
|
|
|
bh_assert(wait_info);
|
|
|
(void)ret;
|
|
|
@@ -338,7 +349,7 @@ fail2:
|
|
|
wasm_runtime_free(wait_info);
|
|
|
|
|
|
fail1:
|
|
|
- os_mutex_unlock(&shared_memory_list_lock);
|
|
|
+ os_mutex_unlock(&wait_map_lock);
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
@@ -365,17 +376,16 @@ destroy_wait_info(void *wait_info)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-release_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info, void *address)
|
|
|
+static bool
|
|
|
+map_remove_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info,
|
|
|
+ void *address)
|
|
|
{
|
|
|
- os_mutex_lock(&shared_memory_list_lock);
|
|
|
-
|
|
|
- if (wait_info->wait_list->len == 0) {
|
|
|
- bh_hash_map_remove(wait_map_, address, NULL, NULL);
|
|
|
- destroy_wait_info(wait_info);
|
|
|
+ if (wait_info->wait_list->len > 0) {
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- os_mutex_unlock(&shared_memory_list_lock);
|
|
|
+ bh_hash_map_remove(wait_map_, address, NULL, NULL);
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
uint32
|
|
|
@@ -386,12 +396,12 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|
|
AtomicWaitInfo *wait_info;
|
|
|
AtomicWaitNode *wait_node;
|
|
|
WASMSharedMemNode *node;
|
|
|
- bool check_ret, is_timeout, no_wait;
|
|
|
+ bool check_ret, is_timeout, no_wait, removed_from_map;
|
|
|
|
|
|
bh_assert(module->module_type == Wasm_Module_Bytecode
|
|
|
|| module->module_type == Wasm_Module_AoT);
|
|
|
|
|
|
- if (wasm_get_exception(module_inst)) {
|
|
|
+ if (wasm_copy_exception(module_inst, NULL)) {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
@@ -416,8 +426,6 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- os_mutex_lock(&wait_info->wait_list_lock);
|
|
|
-
|
|
|
node = search_module((WASMModuleCommon *)module_inst->module);
|
|
|
os_mutex_lock(&node->shared_mem_lock);
|
|
|
no_wait = (!wait64 && *(uint32 *)address != (uint32)expect)
|
|
|
@@ -425,7 +433,6 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|
|
os_mutex_unlock(&node->shared_mem_lock);
|
|
|
|
|
|
if (no_wait) {
|
|
|
- os_mutex_unlock(&wait_info->wait_list_lock);
|
|
|
return 1;
|
|
|
}
|
|
|
else {
|
|
|
@@ -433,33 +440,29 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|
|
|
|
|
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;
|
|
|
-
|
|
|
+ os_mutex_lock(&wait_info->wait_list_lock);
|
|
|
ret = bh_list_insert(wait_info->wait_list, wait_node);
|
|
|
+ os_mutex_unlock(&wait_info->wait_list_lock);
|
|
|
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);
|
|
|
|
|
|
@@ -467,23 +470,26 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address,
|
|
|
timeout < 0 ? BHT_WAIT_FOREVER
|
|
|
: (uint64)timeout / 1000);
|
|
|
|
|
|
+ is_timeout = wait_node->status == S_WAITING ? true : false;
|
|
|
os_mutex_unlock(&wait_node->wait_lock);
|
|
|
|
|
|
- /* Check the wait node status */
|
|
|
+ os_mutex_lock(&node->shared_mem_lock);
|
|
|
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;
|
|
|
-
|
|
|
+ /* Remove wait node */
|
|
|
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);
|
|
|
|
|
|
- os_mutex_lock(&node->shared_mem_lock);
|
|
|
- release_wait_info(wait_map, wait_info, address);
|
|
|
+ /* Release wait info if no wait nodes attached */
|
|
|
+ removed_from_map = map_remove_wait_info(wait_map, wait_info, address);
|
|
|
+ os_mutex_unlock(&wait_info->wait_list_lock);
|
|
|
+ if (removed_from_map)
|
|
|
+ destroy_wait_info(wait_info);
|
|
|
os_mutex_unlock(&node->shared_mem_lock);
|
|
|
|
|
|
(void)check_ret;
|
|
|
@@ -518,16 +524,20 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address,
|
|
|
}
|
|
|
|
|
|
wait_info = acquire_wait_info(address, false);
|
|
|
- if (node)
|
|
|
- os_mutex_unlock(&node->shared_mem_lock);
|
|
|
|
|
|
/* Nobody wait on this address */
|
|
|
- if (!wait_info)
|
|
|
+ if (!wait_info) {
|
|
|
+ if (node)
|
|
|
+ os_mutex_unlock(&node->shared_mem_lock);
|
|
|
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);
|
|
|
|
|
|
+ if (node)
|
|
|
+ os_mutex_unlock(&node->shared_mem_lock);
|
|
|
+
|
|
|
return notify_result;
|
|
|
}
|