diff --git a/core/iwasm/libraries/debug-engine/debug_engine.c b/core/iwasm/libraries/debug-engine/debug_engine.c index 10e39b57..4fd89930 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.c +++ b/core/iwasm/libraries/debug-engine/debug_engine.c @@ -55,9 +55,21 @@ allocate_instance_id() } static bool -should_stop(WASMDebugControlThread *control_thread) +is_thread_running(WASMDebugControlThread *control_thread) { - return control_thread->status != RUNNING; + return control_thread->status == RUNNING; +} + +static bool +is_thread_stopped(WASMDebugControlThread *control_thread) +{ + return control_thread->status == STOPPED; +} + +static bool +is_thread_detached(WASMDebugControlThread *control_thread) +{ + return control_thread->status == DETACHED; } static void * @@ -109,73 +121,88 @@ control_thread_routine(void *arg) os_cond_signal(&debug_inst->wait_cond); os_mutex_unlock(&debug_inst->wait_lock); - /* wait lldb client to connect */ if (!wasm_gdbserver_listen(control_thread->server)) { - LOG_ERROR("Failed while connecting debugger\n"); - wasm_runtime_free(control_thread->server); + LOG_ERROR("Failed while listening for debugger\n"); return NULL; } + /* outer infinite loop: try to connect with the debugger */ while (true) { - os_mutex_lock(&control_thread->wait_lock); - if (!should_stop(control_thread)) { - /* send thread stop reply */ - if (debug_inst->stopped_thread - && debug_inst->current_state == APP_RUNNING) { - uint32 status; - korp_tid tid; + /* wait lldb client to connect */ + if (!wasm_gdbserver_accept(control_thread->server)) { + LOG_ERROR("Failed while accepting debugger connection\n"); + return NULL; + } - status = - (uint32) - debug_inst->stopped_thread->current_status->signal_flag; - tid = debug_inst->stopped_thread->handle; + control_thread->status = RUNNING; - if (debug_inst->stopped_thread->current_status->running_status - == STATUS_EXIT) { - /* If the thread exits, report "W00" if it's the last thread - * in the cluster, otherwise ignore this event */ - status = 0; + /* inner infinite loop: keep serving until detach */ + while (true) { + os_mutex_lock(&control_thread->wait_lock); + if (is_thread_running(control_thread)) { + /* send thread stop reply */ + if (debug_inst->stopped_thread + && debug_inst->current_state == APP_RUNNING) { + uint32 status; + korp_tid tid; - /* By design, all the other threads should have been stopped - * at this moment, so it is safe to access the - * exec_env_list.len without lock */ - if (debug_inst->cluster->exec_env_list.len != 1) { - debug_inst->stopped_thread = NULL; + status = (uint32)debug_inst->stopped_thread->current_status + ->signal_flag; + tid = debug_inst->stopped_thread->handle; + + if (debug_inst->stopped_thread->current_status + ->running_status + == STATUS_EXIT) { + /* If the thread exits, report "W00" if it's the last + * thread in the cluster, otherwise ignore this event */ + status = 0; + + /* By design, all the other threads should have been + * stopped at this moment, so it is safe to access the + * exec_env_list.len without lock */ + if (debug_inst->cluster->exec_env_list.len != 1) { + debug_inst->stopped_thread = NULL; + /* The exiting thread may wait for the signal */ + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&control_thread->wait_lock); + continue; + } + } + + wasm_debug_instance_set_cur_thread( + debug_inst, debug_inst->stopped_thread->handle); + + send_thread_stop_status(control_thread->server, status, + tid); + + debug_inst->current_state = APP_STOPPED; + debug_inst->stopped_thread = NULL; + + if (status == 0) { /* The exiting thread may wait for the signal */ os_cond_signal(&debug_inst->wait_cond); - os_mutex_unlock(&control_thread->wait_lock); - continue; } } - wasm_debug_instance_set_cur_thread( - debug_inst, debug_inst->stopped_thread->handle); - - send_thread_stop_status(control_thread->server, status, tid); - - debug_inst->current_state = APP_STOPPED; - debug_inst->stopped_thread = NULL; - - if (status == 0) { - /* The exiting thread may wait for the signal */ - os_cond_signal(&debug_inst->wait_cond); + /* 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); } } - - /* Processing incoming requests */ - if (!wasm_gdbserver_handle_packet(control_thread->server)) { - control_thread->status = STOPPED; + else if (is_thread_detached(control_thread)) { + os_mutex_unlock(&control_thread->wait_lock); + break; + } + else if (is_thread_stopped(control_thread)) { + os_mutex_unlock(&control_thread->wait_lock); + return NULL; } - } - else { os_mutex_unlock(&control_thread->wait_lock); - break; } - os_mutex_unlock(&control_thread->wait_lock); } - - LOG_VERBOSE("control thread of debug object [%p] stopped\n", debug_inst); - return NULL; } static WASMDebugControlThread * @@ -987,6 +1014,38 @@ wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance) return true; } +bool +wasm_debug_instance_detach(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + wasm_gdbserver_detach(instance->control_thread->server); + + 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); + } + exec_env = bh_list_elem_next(exec_env); + } + + /* relaunch, accept new debug connection */ + instance->current_state = DBG_LAUNCHING; + instance->control_thread->status = DETACHED; + + return true; +} + bool wasm_debug_instance_kill(WASMDebugInstance *instance) { diff --git a/core/iwasm/libraries/debug-engine/debug_engine.h b/core/iwasm/libraries/debug-engine/debug_engine.h index 70901551..bc1313c7 100644 --- a/core/iwasm/libraries/debug-engine/debug_engine.h +++ b/core/iwasm/libraries/debug-engine/debug_engine.h @@ -12,6 +12,7 @@ typedef enum WASMDebugControlThreadStatus { RUNNING, + DETACHED, STOPPED, } WASMDebugControlThreadStatus; @@ -185,6 +186,9 @@ wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance); bool wasm_debug_instance_continue(WASMDebugInstance *instance); +bool +wasm_debug_instance_detach(WASMDebugInstance *instance); + bool wasm_debug_instance_kill(WASMDebugInstance *instance); diff --git a/core/iwasm/libraries/debug-engine/gdbserver.c b/core/iwasm/libraries/debug-engine/gdbserver.c index e347cc34..fbd876ac 100644 --- a/core/iwasm/libraries/debug-engine/gdbserver.c +++ b/core/iwasm/libraries/debug-engine/gdbserver.c @@ -34,6 +34,7 @@ static const struct packet_handler_elem packet_handler_table[255] = { DEL_HANDLER('c', handle_continue_request), DEL_HANDLER('k', handle_kill_request), DEL_HANDLER('_', handle____request), + DEL_HANDLER('D', handle_detach_request), }; WASMGDBServer * @@ -89,7 +90,6 @@ fail: bool wasm_gdbserver_listen(WASMGDBServer *server) { - bh_socket_t sockt_fd = (bh_socket_t)-1; int32 ret; ret = os_socket_listen(server->listen_fd, 1); @@ -98,6 +98,23 @@ wasm_gdbserver_listen(WASMGDBServer *server) goto fail; } + LOG_VERBOSE("listen for gdb client"); + return true; + +fail: + os_socket_shutdown(server->listen_fd); + os_socket_close(server->listen_fd); + return false; +} + +bool +wasm_gdbserver_accept(WASMGDBServer *server) +{ + + bh_socket_t sockt_fd = (bh_socket_t)-1; + + LOG_VERBOSE("waiting for gdb client to connect..."); + os_socket_accept(server->listen_fd, &sockt_fd, NULL, NULL); if (sockt_fd < 0) { LOG_ERROR("wasm gdb server error: socket accept failed"); @@ -115,6 +132,15 @@ fail: return false; } +void +wasm_gdbserver_detach(WASMGDBServer *server) +{ + if (server->socket_fd > 0) { + os_socket_shutdown(server->socket_fd); + os_socket_close(server->socket_fd); + } +} + void wasm_close_gdbserver(WASMGDBServer *server) { @@ -263,8 +289,9 @@ wasm_gdbserver_handle_packet(WASMGDBServer *server) n = os_socket_recv(server->socket_fd, buf, sizeof(buf)); if (n == 0) { - LOG_VERBOSE("Debugger disconnected"); - return false; + handle_detach_request(server, NULL); + LOG_VERBOSE("Debugger disconnected, waiting for debugger reconnection"); + return true; } else if (n < 0) { #if defined(BH_PLATFORM_WINDOWS) diff --git a/core/iwasm/libraries/debug-engine/gdbserver.h b/core/iwasm/libraries/debug-engine/gdbserver.h index 98ff8343..9e279a2e 100644 --- a/core/iwasm/libraries/debug-engine/gdbserver.h +++ b/core/iwasm/libraries/debug-engine/gdbserver.h @@ -56,6 +56,12 @@ wasm_create_gdbserver(const char *host, int32 *port); bool wasm_gdbserver_listen(WASMGDBServer *server); +bool +wasm_gdbserver_accept(WASMGDBServer *server); + +void +wasm_gdbserver_detach(WASMGDBServer *server); + void wasm_close_gdbserver(WASMGDBServer *server); diff --git a/core/iwasm/libraries/debug-engine/handler.c b/core/iwasm/libraries/debug-engine/handler.c index da07f80d..701dd0c0 100644 --- a/core/iwasm/libraries/debug-engine/handler.c +++ b/core/iwasm/libraries/debug-engine/handler.c @@ -777,3 +777,13 @@ handle____request(WASMGDBServer *server, char *payload) handle_free(server, args); } } + +void +handle_detach_request(WASMGDBServer *server, char *payload) +{ + if (payload != NULL) { + write_packet(server, "OK"); + } + wasm_debug_instance_detach( + (WASMDebugInstance *)server->thread->debug_instance); +} diff --git a/core/iwasm/libraries/debug-engine/handler.h b/core/iwasm/libraries/debug-engine/handler.h index 47422fdd..af2566da 100644 --- a/core/iwasm/libraries/debug-engine/handler.h +++ b/core/iwasm/libraries/debug-engine/handler.h @@ -62,6 +62,9 @@ handle_kill_request(WASMGDBServer *server, char *payload); void handle____request(WASMGDBServer *server, char *payload); +void +handle_detach_request(WASMGDBServer *server, char *payload); + void send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid); #endif