Fix thread manager issues (#962)

Fix the issue that joining a detached thread might result in joining hang,
resolve the issue by adding wait_count for a thread's exec_env to indicate
whether a thread needs to detach itself or not when it exits.

And add checks for the input exec_env for cluster's join/detach/cancel thread.
This commit is contained in:
Wenyong Huang 2022-01-17 17:09:04 +08:00 committed by GitHub
parent ee97e30a1a
commit 092efbfe21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 2 deletions

View File

@ -98,6 +98,8 @@ typedef struct WASMExecEnv {
/* used to support debugger */ /* used to support debugger */
korp_mutex wait_lock; korp_mutex wait_lock;
korp_cond wait_cond; korp_cond wait_cond;
/* the count of threads which are joining current thread */
uint32 wait_count;
#endif #endif
#if WASM_ENABLE_DEBUG_INTERP != 0 #if WASM_ENABLE_DEBUG_INTERP != 0

View File

@ -625,16 +625,69 @@ wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst)
#endif /* end of WASM_ENABLE_DEBUG_INTERP */ #endif /* end of WASM_ENABLE_DEBUG_INTERP */
/* Check whether the exec_env is in one of all clusters, the caller
should add lock to the cluster list before calling us */
static bool
clusters_have_exec_env(WASMExecEnv *exec_env)
{
WASMCluster *cluster = bh_list_first_elem(cluster_list);
WASMExecEnv *node;
while (cluster) {
node = bh_list_first_elem(&cluster->exec_env_list);
while (node) {
if (node == exec_env) {
bh_assert(exec_env->cluster == cluster);
return true;
}
node = bh_list_elem_next(node);
}
cluster = bh_list_elem_next(cluster);
}
return false;
}
int32 int32
wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
{ {
return os_thread_join(exec_env->handle, ret_val); korp_tid handle;
os_mutex_lock(&cluster_list_lock);
if (!clusters_have_exec_env(exec_env)) {
/* Invalid thread or the thread has exited */
if (ret_val)
*ret_val = NULL;
os_mutex_unlock(&cluster_list_lock);
return 0;
}
exec_env->wait_count++;
handle = exec_env->handle;
os_mutex_unlock(&cluster_list_lock);
return os_thread_join(handle, ret_val);
} }
int32 int32
wasm_cluster_detach_thread(WASMExecEnv *exec_env) wasm_cluster_detach_thread(WASMExecEnv *exec_env)
{ {
return os_thread_detach(exec_env->handle); int32 ret = 0;
os_mutex_lock(&cluster_list_lock);
if (!clusters_have_exec_env(exec_env)) {
/* Invalid thread or the thread has exited */
os_mutex_unlock(&cluster_list_lock);
return 0;
}
if (exec_env->wait_count == 0) {
/* Only detach current thread when there is no other thread
joining it, otherwise let the system resources for the
thread be released after joining */
ret = os_thread_detach(exec_env->handle);
}
os_mutex_unlock(&cluster_list_lock);
return ret;
} }
void void
@ -680,6 +733,14 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval)
int32 int32
wasm_cluster_cancel_thread(WASMExecEnv *exec_env) wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
{ {
os_mutex_lock(&cluster_list_lock);
if (!clusters_have_exec_env(exec_env)) {
/* Invalid thread or the thread has exited */
os_mutex_unlock(&cluster_list_lock);
return 0;
}
os_mutex_unlock(&cluster_list_lock);
/* Set the termination flag */ /* Set the termination flag */
#if WASM_ENABLE_DEBUG_INTERP != 0 #if WASM_ENABLE_DEBUG_INTERP != 0
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM);

View File

@ -19,6 +19,7 @@ extern "C" {
#if WASM_ENABLE_DEBUG_INTERP != 0 #if WASM_ENABLE_DEBUG_INTERP != 0
typedef struct WASMDebugInstance WASMDebugInstance; typedef struct WASMDebugInstance WASMDebugInstance;
#endif #endif
typedef struct WASMCluster { typedef struct WASMCluster {
struct WASMCluster *next; struct WASMCluster *next;