diff --git a/core/iwasm/libraries/debug-engine/debug_engine.c b/core/iwasm/libraries/debug-engine/debug_engine.c index 1698153d..61b29da8 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.c +++ b/core/iwasm/libraries/debug-engine/debug_engine.c @@ -36,6 +36,23 @@ on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env) os_mutex_unlock(&debug_inst->wait_lock); } +void +on_thread_exit_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env) +{ + os_mutex_lock(&debug_inst->wait_lock); + + /* DBG_LAUNCHING: exit when debugger detached, + * DBG_ERROR: exit when debugger error */ + if (debug_inst->current_state != DBG_LAUNCHING + && debug_inst->current_state != DBG_ERROR) { + /* only when exit normally the debugger thread will participate in + * teardown phase */ + debug_inst->stopped_thread = exec_env; + } + + os_mutex_unlock(&debug_inst->wait_lock); +} + static WASMDebugEngine *g_debug_engine; static uint32 current_instance_id = 1; @@ -123,7 +140,7 @@ control_thread_routine(void *arg) if (!wasm_gdbserver_listen(control_thread->server)) { LOG_ERROR("Failed while listening for debugger\n"); - return NULL; + goto fail; } /* outer infinite loop: try to connect with the debugger */ @@ -131,10 +148,12 @@ control_thread_routine(void *arg) /* wait lldb client to connect */ if (!wasm_gdbserver_accept(control_thread->server)) { LOG_ERROR("Failed while accepting debugger connection\n"); - return NULL; + goto fail; } control_thread->status = RUNNING; + /* when reattached, send signal */ + wasm_cluster_send_signal_all(debug_inst->cluster, WAMR_SIG_SINGSTEP); /* inner infinite loop: keep serving until detach */ while (true) { @@ -187,9 +206,9 @@ control_thread_routine(void *arg) /* Processing incoming requests */ if (!wasm_gdbserver_handle_packet(control_thread->server)) { control_thread->status = STOPPED; - LOG_VERBOSE("control thread of debug object [%p] stopped\n", - debug_inst); - wasm_close_gdbserver(control_thread->server); + LOG_ERROR("An error occurs when handling a packet\n"); + os_mutex_unlock(&control_thread->wait_lock); + goto fail; } } else if (is_thread_detached(control_thread)) { @@ -203,6 +222,11 @@ control_thread_routine(void *arg) os_mutex_unlock(&control_thread->wait_lock); } } +fail: + wasm_debug_instance_on_failure(debug_inst); + LOG_VERBOSE("control thread of debug object [%p] stopped with failure\n", + debug_inst); + return NULL; } static WASMDebugControlThread * @@ -971,6 +995,44 @@ wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, return true; } +bool +wasm_debug_instance_on_failure(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + os_mutex_lock(&instance->wait_lock); + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) { + os_mutex_unlock(&instance->wait_lock); + return false; + } + + if (instance->stopped_thread == NULL + && instance->current_state == DBG_LAUNCHING) { + /* if fail in start stage: may need wait for main thread to notify it */ + os_cond_wait(&instance->wait_cond, &instance->wait_lock); + } + instance->current_state = DBG_ERROR; + instance->stopped_thread = NULL; + + /* terminate the wasm execution thread */ + while (exec_env) { + /* Resume all threads so they can receive the TERM signal */ + os_mutex_lock(&exec_env->wait_lock); + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); + exec_env->current_status->running_status = STATUS_RUNNING; + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); + exec_env = bh_list_elem_next(exec_env); + } + os_mutex_unlock(&instance->wait_lock); + + return true; +} + bool wasm_debug_instance_continue(WASMDebugInstance *instance) { @@ -1034,10 +1096,7 @@ wasm_debug_instance_detach(WASMDebugInstance *instance) while (exec_env) { if (instance->current_state == APP_STOPPED) { /* Resume all threads since remote debugger detached*/ - os_mutex_lock(&exec_env->wait_lock); - exec_env->current_status->running_status = STATUS_RUNNING; - os_cond_signal(&exec_env->wait_cond); - os_mutex_unlock(&exec_env->wait_lock); + wasm_cluster_thread_continue(exec_env); } exec_env = bh_list_elem_next(exec_env); } @@ -1045,6 +1104,7 @@ wasm_debug_instance_detach(WASMDebugInstance *instance) /* relaunch, accept new debug connection */ instance->current_state = DBG_LAUNCHING; instance->control_thread->status = DETACHED; + instance->stopped_thread = NULL; return true; } diff --git a/core/iwasm/libraries/debug-engine/debug_engine.h b/core/iwasm/libraries/debug-engine/debug_engine.h index bc1313c7..f7580a7b 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.h +++ b/core/iwasm/libraries/debug-engine/debug_engine.h @@ -42,7 +42,8 @@ typedef enum debug_state_t { */ DBG_LAUNCHING, APP_RUNNING, - APP_STOPPED + APP_STOPPED, + DBG_ERROR } debug_state_t; typedef struct WASMDebugExecutionMemory { @@ -108,6 +109,9 @@ typedef enum WasmAddressType { void on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env); +void +on_thread_exit_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env); + WASMDebugInstance * wasm_debug_instance_create(WASMCluster *cluster, int32 port); @@ -180,6 +184,9 @@ bool wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, uint64 length); +bool +wasm_debug_instance_on_failure(WASMDebugInstance *instance); + bool wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance); diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 2e15ac54..4408b013 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -293,8 +293,9 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) other threads can't fire stop events */ os_mutex_lock(&cluster->debug_inst->wait_lock); while (cluster->debug_inst->stopped_thread == exec_env) { - os_cond_wait(&cluster->debug_inst->wait_cond, - &cluster->debug_inst->wait_lock); + /* either wakes up by signal or by 1-second timeout */ + os_cond_reltimedwait(&cluster->debug_inst->wait_cond, + &cluster->debug_inst->wait_lock, 1000000); } os_mutex_unlock(&cluster->debug_inst->wait_lock); } @@ -593,6 +594,21 @@ notify_debug_instance(WASMExecEnv *exec_env) on_thread_stop_event(cluster->debug_inst, exec_env); } +static void +notify_debug_instance_exit(WASMExecEnv *exec_env) +{ + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + if (!cluster->debug_inst) { + return; + } + + on_thread_exit_event(cluster->debug_inst, exec_env); +} + void wasm_cluster_thread_stopped(WASMExecEnv *exec_env) { @@ -624,7 +640,7 @@ void wasm_cluster_thread_exited(WASMExecEnv *exec_env) { exec_env->current_status->running_status = STATUS_EXIT; - notify_debug_instance(exec_env); + notify_debug_instance_exit(exec_env); } void