-
Notifications
You must be signed in to change notification settings - Fork 812
Fix wait_info data race for deletion + fix atomic_wait logic #2016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
c0f13de
8fdbc12
b30a14c
962e46f
327c1a3
2f69b0d
3e1a974
bc9fa8b
388684d
8bf4aab
1efcb64
bcd639d
6c21413
e81fa95
2970e7d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,9 @@ | |
|
|
||
| #include "bh_log.h" | ||
| #include "wasm_shared_memory.h" | ||
| #if WASM_ENABLE_THREAD_MGR != 0 | ||
| #include "../libraries/thread-mgr/thread_manager.h" | ||
| #endif | ||
|
|
||
| static bh_list shared_memory_list_head; | ||
| static bh_list *const shared_memory_list = &shared_memory_list_head; | ||
|
|
@@ -21,6 +24,8 @@ typedef struct AtomicWaitInfo { | |
| korp_mutex wait_list_lock; | ||
| bh_list wait_list_head; | ||
| bh_list *wait_list; | ||
| // WARNING: insert to the list allowed only in acquire_wait_info | ||
| // otherwise there will be data race as described in PR #2016 | ||
| } AtomicWaitInfo; | ||
|
|
||
| typedef struct AtomicWaitNode { | ||
|
|
@@ -298,7 +303,7 @@ notify_wait_list(bh_list *wait_list, uint32 count) | |
| } | ||
|
|
||
| static AtomicWaitInfo * | ||
| acquire_wait_info(void *address, bool create) | ||
| acquire_wait_info(void *address, AtomicWaitNode *wait_node) | ||
| { | ||
| AtomicWaitInfo *wait_info = NULL; | ||
| bh_list_status ret; | ||
|
|
@@ -308,7 +313,7 @@ acquire_wait_info(void *address, bool create) | |
| if (address) | ||
| wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address); | ||
|
|
||
| if (!create) { | ||
| if (!wait_node && !wait_info) { | ||
|
wenyongh marked this conversation as resolved.
Outdated
|
||
| os_mutex_unlock(&wait_map_lock); | ||
| return wait_info; | ||
| } | ||
|
|
@@ -335,6 +340,13 @@ acquire_wait_info(void *address, bool create) | |
| goto fail3; | ||
| } | ||
| } | ||
| if (wait_node) { | ||
| 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_map_lock); | ||
|
|
||
|
|
@@ -376,16 +388,22 @@ destroy_wait_info(void *wait_info) | |
| } | ||
| } | ||
|
|
||
| static bool | ||
| map_remove_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info, | ||
| void *address) | ||
| static void | ||
| map_try_release_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info, | ||
| void *address) | ||
| { | ||
| os_mutex_lock(&wait_map_lock); | ||
|
g0djan marked this conversation as resolved.
|
||
| os_mutex_lock(&wait_info->wait_list_lock); | ||
| if (wait_info->wait_list->len > 0) { | ||
|
g0djan marked this conversation as resolved.
|
||
| return false; | ||
| os_mutex_unlock(&wait_info->wait_list_lock); | ||
| os_mutex_unlock(&wait_map_lock); | ||
| return; | ||
| } | ||
| os_mutex_unlock(&wait_info->wait_list_lock); | ||
|
wenyongh marked this conversation as resolved.
|
||
|
|
||
| bh_hash_map_remove(wait_map_, address, NULL, NULL); | ||
| return true; | ||
| os_mutex_unlock(&wait_map_lock); | ||
| destroy_wait_info(wait_info); | ||
| } | ||
|
|
||
| uint32 | ||
|
|
@@ -396,7 +414,8 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, | |
| AtomicWaitInfo *wait_info; | ||
| AtomicWaitNode *wait_node; | ||
| WASMSharedMemNode *node; | ||
| bool check_ret, is_timeout, no_wait, removed_from_map; | ||
| WASMExecEnv *exec_env; | ||
| bool check_ret, is_timeout, no_wait; | ||
|
|
||
| bh_assert(module->module_type == Wasm_Module_Bytecode | ||
| || module->module_type == Wasm_Module_AoT); | ||
|
|
@@ -418,14 +437,6 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, | |
| return -1; | ||
| } | ||
|
|
||
| /* 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; | ||
| } | ||
|
|
||
| node = search_module((WASMModuleCommon *)module_inst->module); | ||
| os_mutex_lock(&node->shared_mem_lock); | ||
| no_wait = (!wait64 && *(uint32 *)address != (uint32)expect) | ||
|
|
@@ -435,40 +446,53 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, | |
| if (no_wait) { | ||
| 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"); | ||
| return -1; | ||
| } | ||
| memset(wait_node, 0, sizeof(AtomicWaitNode)); | ||
| if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) { | ||
| wasm_runtime_set_exception(module, "failed to create wait node"); | ||
| return -1; | ||
| } | ||
| memset(wait_node, 0, sizeof(AtomicWaitNode)); | ||
|
|
||
| if (0 != os_mutex_init(&wait_node->wait_lock)) { | ||
| wasm_runtime_free(wait_node); | ||
| return -1; | ||
| } | ||
| if (0 != os_mutex_init(&wait_node->wait_lock)) { | ||
| wasm_runtime_free(wait_node); | ||
| return -1; | ||
| } | ||
|
|
||
| if (0 != os_cond_init(&wait_node->wait_cond)) { | ||
| os_mutex_destroy(&wait_node->wait_lock); | ||
| wasm_runtime_free(wait_node); | ||
| return -1; | ||
| } | ||
| if (0 != os_cond_init(&wait_node->wait_cond)) { | ||
| os_mutex_destroy(&wait_node->wait_lock); | ||
| wasm_runtime_free(wait_node); | ||
| 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; | ||
| wait_node->status = S_WAITING; | ||
|
|
||
| /* acquire the wait info, create new one if not exists */ | ||
| wait_info = acquire_wait_info(address, wait_node); | ||
|
|
||
| if (!wait_info) { | ||
| os_mutex_destroy(&wait_node->wait_lock); | ||
| wasm_runtime_free(wait_node); | ||
| wasm_runtime_set_exception(module, "failed to acquire wait_info"); | ||
| return -1; | ||
| } | ||
|
|
||
| #if WASM_ENABLE_THREAD_MGR != 0 | ||
| exec_env = | ||
| wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst); | ||
|
wenyongh marked this conversation as resolved.
|
||
| #endif | ||
|
|
||
| /* condition wait start */ | ||
| os_mutex_lock(&wait_node->wait_lock); | ||
|
|
||
| os_cond_reltimedwait(&wait_node->wait_cond, &wait_node->wait_lock, | ||
| timeout < 0 ? BHT_WAIT_FOREVER | ||
| : (uint64)timeout / 1000); | ||
| #if WASM_ENABLE_THREAD_MGR != 0 | ||
| if (!wasm_cluster_is_thread_terminated(exec_env)) { | ||
|
wenyongh marked this conversation as resolved.
Outdated
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Concerned about
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean the flag being set between the call to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the problem you talking about I solved with your idea with condition variable(I just found a way to do it with the existing one):
thread 2
To check I ran the tests and it never hangs any more, no tsan warnings as well(besides unrelated LOAD-STORE one)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here I'm concerned about
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then I presume we want to add a |
||
| #endif | ||
| os_cond_reltimedwait(&wait_node->wait_cond, &wait_node->wait_lock, | ||
| timeout < 0 ? BHT_WAIT_FOREVER | ||
| : (uint64)timeout / 1000); | ||
| #if WASM_ENABLE_THREAD_MGR != 0 | ||
| } | ||
| #endif | ||
|
|
||
| is_timeout = wait_node->status == S_WAITING ? true : false; | ||
| os_mutex_unlock(&wait_node->wait_lock); | ||
|
|
@@ -486,10 +510,8 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, | |
| wasm_runtime_free(wait_node); | ||
|
|
||
| /* 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); | ||
| map_try_release_wait_info(wait_map, wait_info, address); | ||
| os_mutex_unlock(&node->shared_mem_lock); | ||
|
|
||
| (void)check_ret; | ||
|
|
@@ -523,7 +545,7 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, | |
| return -1; | ||
| } | ||
|
|
||
| wait_info = acquire_wait_info(address, false); | ||
| wait_info = acquire_wait_info(address, NULL); | ||
|
|
||
| /* Nobody wait on this address */ | ||
| if (!wait_info) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.