From 4da97b3f9e999bd12d531b4f3dcba50c0d099e3b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 22 Apr 2018 08:33:22 -0700 Subject: [PATCH] Debugger: Lock during startup/shutdown. Otherwise things can get freed while we're trying to inspect them. --- Core/Debugger/WebSocket.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Core/Debugger/WebSocket.cpp b/Core/Debugger/WebSocket.cpp index e99253b813..5b323bce4b 100644 --- a/Core/Debugger/WebSocket.cpp +++ b/Core/Debugger/WebSocket.cpp @@ -68,12 +68,43 @@ static volatile bool stopRequested = false; static std::mutex stopLock; static std::condition_variable stopCond; +// Prevent threading surprises and obscure crashes by locking startup/shutdown. +static bool lifecycleLockSetup = false; +static std::mutex lifecycleLock; + static void UpdateConnected(int delta) { std::lock_guard guard(stopLock); debuggersConnected += delta; stopCond.notify_all(); } +static void WebSocketNotifyLifecycle(CoreLifecycle stage) { + switch (stage) { + case CoreLifecycle::STARTING: + case CoreLifecycle::STOPPING: + if (debuggersConnected > 0) { + DEBUG_LOG(SYSTEM, "Waiting for debugger to complete on shutdown"); + } + lifecycleLock.lock(); + break; + + case CoreLifecycle::START_COMPLETE: + case CoreLifecycle::STOPPED: + lifecycleLock.unlock(); + if (debuggersConnected > 0) { + DEBUG_LOG(SYSTEM, "Debugger ready for shutdown"); + } + break; + } +} + +static void SetupDebuggerLock() { + if (!lifecycleLockSetup) { + Core_ListenLifecycle(&WebSocketNotifyLifecycle); + lifecycleLockSetup = true; + } +} + void HandleDebuggerRequest(const http::Request &request) { net::WebSocketServer *ws = net::WebSocketServer::CreateAsUpgrade(request, "debugger.ppsspp.org"); if (!ws) @@ -81,6 +112,7 @@ void HandleDebuggerRequest(const http::Request &request) { setCurrentThreadName("Debugger"); UpdateConnected(1); + SetupDebuggerLock(); LogBroadcaster logger; GameBroadcaster game; @@ -89,6 +121,7 @@ void HandleDebuggerRequest(const http::Request &request) { std::unordered_map eventHandlers; std::vector subscriberData; for (auto info : subscribers) { + std::lock_guard guard(lifecycleLock); subscriberData.push_back(info.init(eventHandlers)); } @@ -109,6 +142,7 @@ void HandleDebuggerRequest(const http::Request &request) { DebuggerRequest req(event, ws, root); auto eventFunc = eventHandlers.find(event); if (eventFunc != eventHandlers.end()) { + std::lock_guard guard(lifecycleLock); eventFunc->second(req); req.Finish(); } else { @@ -120,6 +154,7 @@ void HandleDebuggerRequest(const http::Request &request) { }); while (ws->Process(1.0f / 60.0f)) { + std::lock_guard guard(lifecycleLock); // These send events that aren't just responses to requests. logger.Broadcast(ws); game.Broadcast(ws); @@ -130,6 +165,7 @@ void HandleDebuggerRequest(const http::Request &request) { } } + std::lock_guard guard(lifecycleLock); for (size_t i = 0; i < subscribers.size(); ++i) { if (subscribers[i].shutdown) { subscribers[i].shutdown(subscriberData[i]);