diff --git a/src/xenia/debug/debug_server.cc b/src/xenia/debug/debug_server.cc index 138787c71..811e679fd 100644 --- a/src/xenia/debug/debug_server.cc +++ b/src/xenia/debug/debug_server.cc @@ -30,8 +30,10 @@ DebugServer::DebugServer(Emulator* emulator) : emulator_(emulator), lock_(0) { lock_ = xe_mutex_alloc(10000); - //protocols_.push_back( - // new protocols::gdb::GDBProtocol(this)); + client_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); + + protocols_.push_back( + new protocols::gdb::GDBProtocol(this)); protocols_.push_back( new protocols::ws::WSProtocol(this)); } @@ -39,10 +41,19 @@ DebugServer::DebugServer(Emulator* emulator) : DebugServer::~DebugServer() { Shutdown(); + CloseHandle(client_event_); + xe_free(lock_); lock_ = 0; } +bool DebugServer::has_clients() { + xe_mutex_lock(lock_); + bool has_clients = clients_.size() > 0; + xe_mutex_unlock(lock_); + return has_clients; +} + int DebugServer::Startup() { return 0; } @@ -66,7 +77,7 @@ int DebugServer::BeforeEntry() { // If desired, wait until the first client connects. //if (FLAGS_wait_for_debugger) { XELOGI("Waiting for debugger..."); - if (protocols_[0]->WaitForClient()) { + if (WaitForClient()) { return 1; } XELOGI("Debugger attached, continuing..."); @@ -95,6 +106,13 @@ void DebugServer::Shutdown() { xe_mutex_unlock(lock_); } +int DebugServer::WaitForClient() { + while (!has_clients()) { + WaitForSingleObject(client_event_, INFINITE); + } + return 0; +} + void DebugServer::AddClient(DebugClient* debug_client) { xe_mutex_lock(lock_); @@ -108,6 +126,8 @@ void DebugServer::AddClient(DebugClient* debug_client) { clients_.push_back(debug_client); xe_mutex_unlock(lock_); + + SetEvent(client_event_); } void DebugServer::RemoveClient(DebugClient* debug_client) { diff --git a/src/xenia/debug/debug_server.h b/src/xenia/debug/debug_server.h index 995c4406f..a1c272a53 100644 --- a/src/xenia/debug/debug_server.h +++ b/src/xenia/debug/debug_server.h @@ -32,10 +32,14 @@ public: Emulator* emulator() const { return emulator_; } + bool has_clients(); + int Startup(); int BeforeEntry(); void Shutdown(); + int WaitForClient(); + private: void AddClient(DebugClient* debug_client); void RemoveClient(DebugClient* debug_client); @@ -48,6 +52,7 @@ private: xe_mutex_t* lock_; std::vector clients_; + HANDLE client_event_; }; diff --git a/src/xenia/debug/protocol.h b/src/xenia/debug/protocol.h index d09d53c5f..5a0524317 100644 --- a/src/xenia/debug/protocol.h +++ b/src/xenia/debug/protocol.h @@ -27,7 +27,6 @@ public: virtual ~Protocol(); virtual int Setup() = 0; - virtual int WaitForClient() = 0; protected: DebugServer* debug_server_; diff --git a/src/xenia/debug/protocols/gdb/gdb_protocol.cc b/src/xenia/debug/protocols/gdb/gdb_protocol.cc index 1446aa1f7..dbf227cc7 100644 --- a/src/xenia/debug/protocols/gdb/gdb_protocol.cc +++ b/src/xenia/debug/protocols/gdb/gdb_protocol.cc @@ -24,11 +24,18 @@ using namespace xe::debug::protocols::gdb; GDBProtocol::GDBProtocol(DebugServer* debug_server) : + port_(0), socket_id_(0), thread_(0), running_(false), Protocol(debug_server) { port_ = FLAGS_gdb_debug_port; } GDBProtocol::~GDBProtocol() { + if (thread_) { + // Join thread. + running_ = false; + xe_thread_release(thread_); + thread_ = 0; + } if (socket_id_) { xe_socket_close(socket_id_); } @@ -60,29 +67,39 @@ int GDBProtocol::Setup() { return 1; } - return 0; -} - -int GDBProtocol::WaitForClient() { - if (!socket_id_) { - return 1; - } - - // Accept the first connection we get. - xe_socket_connection_t client_info; - if (xe_socket_accept(socket_id_, &client_info)) { - return 1; - } - - XELOGI("GDB debugger connected from %s", client_info.addr); - - // Create the client object. - // Note that the client will delete itself when done. - GDBClient* client = new GDBClient(debug_server_, client_info.socket); - if (client->Setup()) { - // Client failed to setup - abort. - return 1; - } + thread_ = xe_thread_create("GDB Debugger Listener", StartCallback, this); + running_ = true; + return xe_thread_start(thread_); return 0; } + +void GDBProtocol::StartCallback(void* param) { + GDBProtocol* protocol = reinterpret_cast(param); + protocol->AcceptThread(); +} + +void GDBProtocol::AcceptThread() { + while (running_) { + if (!socket_id_) { + break; + } + + // Accept the first connection we get. + xe_socket_connection_t client_info; + if (xe_socket_accept(socket_id_, &client_info)) { + XELOGE("WS debugger failed to accept connection"); + break; + } + + XELOGI("WS debugger connected from %s", client_info.addr); + + // Create the client object. + // Note that the client will delete itself when done. + GDBClient* client = new GDBClient(debug_server_, client_info.socket); + if (client->Setup()) { + // Client failed to setup - abort. + continue; + } + } +} diff --git a/src/xenia/debug/protocols/gdb/gdb_protocol.h b/src/xenia/debug/protocols/gdb/gdb_protocol.h index 94a63bd58..8152ba21c 100644 --- a/src/xenia/debug/protocols/gdb/gdb_protocol.h +++ b/src/xenia/debug/protocols/gdb/gdb_protocol.h @@ -31,12 +31,18 @@ public: virtual ~GDBProtocol(); virtual int Setup(); - virtual int WaitForClient(); + +private: + static void StartCallback(void* param); + void AcceptThread(); protected: uint32_t port_; socket_t socket_id_; + + xe_thread_ref thread_; + bool running_; }; diff --git a/src/xenia/debug/protocols/ws/ws_protocol.cc b/src/xenia/debug/protocols/ws/ws_protocol.cc index 3e45b2c46..668eb5c8c 100644 --- a/src/xenia/debug/protocols/ws/ws_protocol.cc +++ b/src/xenia/debug/protocols/ws/ws_protocol.cc @@ -9,6 +9,7 @@ #include +#include #include #include @@ -25,7 +26,6 @@ DEFINE_int32(ws_debug_port, 6200, WSProtocol::WSProtocol(DebugServer* debug_server) : port_(0), socket_id_(0), thread_(0), running_(false), - accepted_event_(INVALID_HANDLE_VALUE), Protocol(debug_server) { port_ = FLAGS_ws_debug_port; } @@ -37,9 +37,6 @@ WSProtocol::~WSProtocol() { xe_thread_release(thread_); thread_ = 0; } - if (accepted_event_ != INVALID_HANDLE_VALUE) { - CloseHandle(accepted_event_); - } if (socket_id_) { xe_socket_close(socket_id_); } @@ -71,8 +68,6 @@ int WSProtocol::Setup() { return 1; } - accepted_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); - thread_ = xe_thread_create("WS Debugger Listener", StartCallback, this); running_ = true; return xe_thread_start(thread_); @@ -105,12 +100,5 @@ void WSProtocol::AcceptThread() { // Client failed to setup - abort. continue; } - - SetEvent(accepted_event_); } } - -int WSProtocol::WaitForClient() { - WaitForSingleObject(accepted_event_, INFINITE); - return 0; -} diff --git a/src/xenia/debug/protocols/ws/ws_protocol.h b/src/xenia/debug/protocols/ws/ws_protocol.h index f1d6510df..b5cce87be 100644 --- a/src/xenia/debug/protocols/ws/ws_protocol.h +++ b/src/xenia/debug/protocols/ws/ws_protocol.h @@ -31,7 +31,6 @@ public: virtual ~WSProtocol(); virtual int Setup(); - virtual int WaitForClient(); private: static void StartCallback(void* param); @@ -44,7 +43,6 @@ protected: xe_thread_ref thread_; bool running_; - HANDLE accepted_event_; };