diff options
| author | 2022-06-10 09:17:12 -0400 | |
|---|---|---|
| committer | 2022-06-10 09:17:12 -0400 | |
| commit | 1f0fee33edf06bb237a952b78b6e117ba81cbdbb (patch) | |
| tree | 01ce352e9ffbc07cb2b7dc0fd1e1c4ea50298bee /src | |
| parent | core/debugger: support operation in yuzu-cmd (diff) | |
| download | yuzu-1f0fee33edf06bb237a952b78b6e117ba81cbdbb.tar.gz yuzu-1f0fee33edf06bb237a952b78b6e117ba81cbdbb.tar.xz yuzu-1f0fee33edf06bb237a952b78b6e117ba81cbdbb.zip | |
core/debugger: fix a number of shutdown deadlocks
Diffstat (limited to '')
| -rw-r--r-- | src/core/core.cpp | 6 | ||||
| -rw-r--r-- | src/core/core.h | 3 | ||||
| -rw-r--r-- | src/core/debugger/debugger.cpp | 55 | ||||
| -rw-r--r-- | src/core/debugger/debugger.h | 5 | ||||
| -rw-r--r-- | src/core/debugger/debugger_interface.h | 5 | ||||
| -rw-r--r-- | src/core/debugger/gdbstub.cpp | 2 | ||||
| -rw-r--r-- | src/core/debugger/gdbstub.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 1 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 1 |
9 files changed, 72 insertions, 7 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 7d974ba65..954136adb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -493,6 +493,12 @@ void System::Shutdown() { | |||
| 493 | impl->Shutdown(); | 493 | impl->Shutdown(); |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | void System::DetachDebugger() { | ||
| 497 | if (impl->debugger) { | ||
| 498 | impl->debugger->NotifyShutdown(); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 496 | std::unique_lock<std::mutex> System::StallCPU() { | 502 | std::unique_lock<std::mutex> System::StallCPU() { |
| 497 | return impl->StallCPU(); | 503 | return impl->StallCPU(); |
| 498 | } | 504 | } |
diff --git a/src/core/core.h b/src/core/core.h index 94477206e..5c367349e 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -160,6 +160,9 @@ public: | |||
| 160 | /// Shutdown the emulated system. | 160 | /// Shutdown the emulated system. |
| 161 | void Shutdown(); | 161 | void Shutdown(); |
| 162 | 162 | ||
| 163 | /// Forcibly detach the debugger if it is running. | ||
| 164 | void DetachDebugger(); | ||
| 165 | |||
| 163 | std::unique_lock<std::mutex> StallCPU(); | 166 | std::unique_lock<std::mutex> StallCPU(); |
| 164 | void UnstallCPU(); | 167 | void UnstallCPU(); |
| 165 | 168 | ||
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 8d64990ed..1d7f9a775 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -42,6 +42,16 @@ static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) { | |||
| 42 | return received_data; | 42 | return received_data; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | enum class SignalType { | ||
| 46 | Stopped, | ||
| 47 | ShuttingDown, | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct SignalInfo { | ||
| 51 | SignalType type; | ||
| 52 | Kernel::KThread* thread; | ||
| 53 | }; | ||
| 54 | |||
| 45 | namespace Core { | 55 | namespace Core { |
| 46 | 56 | ||
| 47 | class DebuggerImpl : public DebuggerBackend { | 57 | class DebuggerImpl : public DebuggerBackend { |
| @@ -56,7 +66,7 @@ public: | |||
| 56 | ShutdownServer(); | 66 | ShutdownServer(); |
| 57 | } | 67 | } |
| 58 | 68 | ||
| 59 | bool NotifyThreadStopped(Kernel::KThread* thread) { | 69 | bool SignalDebugger(SignalInfo signal_info) { |
| 60 | std::scoped_lock lk{connection_lock}; | 70 | std::scoped_lock lk{connection_lock}; |
| 61 | 71 | ||
| 62 | if (stopped) { | 72 | if (stopped) { |
| @@ -64,9 +74,13 @@ public: | |||
| 64 | // It should be ignored. | 74 | // It should be ignored. |
| 65 | return false; | 75 | return false; |
| 66 | } | 76 | } |
| 77 | |||
| 78 | // Set up the state. | ||
| 67 | stopped = true; | 79 | stopped = true; |
| 80 | info = signal_info; | ||
| 68 | 81 | ||
| 69 | boost::asio::write(signal_pipe, boost::asio::buffer(&thread, sizeof(thread))); | 82 | // Write a single byte into the pipe to wake up the debug interface. |
| 83 | boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); | ||
| 70 | return true; | 84 | return true; |
| 71 | } | 85 | } |
| 72 | 86 | ||
| @@ -124,7 +138,7 @@ private: | |||
| 124 | Common::SetCurrentThreadName("yuzu:Debugger"); | 138 | Common::SetCurrentThreadName("yuzu:Debugger"); |
| 125 | 139 | ||
| 126 | // Set up the client signals for new data. | 140 | // Set up the client signals for new data. |
| 127 | AsyncReceiveInto(signal_pipe, active_thread, [&](auto d) { PipeData(d); }); | 141 | AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); |
| 128 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); | 142 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); |
| 129 | 143 | ||
| 130 | // Stop the emulated CPU. | 144 | // Stop the emulated CPU. |
| @@ -142,9 +156,28 @@ private: | |||
| 142 | } | 156 | } |
| 143 | 157 | ||
| 144 | void PipeData(std::span<const u8> data) { | 158 | void PipeData(std::span<const u8> data) { |
| 145 | AllCoreStop(); | 159 | switch (info.type) { |
| 146 | UpdateActiveThread(); | 160 | case SignalType::Stopped: |
| 147 | frontend->Stopped(active_thread); | 161 | // Stop emulation. |
| 162 | AllCoreStop(); | ||
| 163 | |||
| 164 | // Notify the client. | ||
| 165 | active_thread = info.thread; | ||
| 166 | UpdateActiveThread(); | ||
| 167 | frontend->Stopped(active_thread); | ||
| 168 | |||
| 169 | break; | ||
| 170 | case SignalType::ShuttingDown: | ||
| 171 | frontend->ShuttingDown(); | ||
| 172 | |||
| 173 | // Wait for emulation to shut down gracefully now. | ||
| 174 | suspend.reset(); | ||
| 175 | signal_pipe.close(); | ||
| 176 | client_socket.shutdown(boost::asio::socket_base::shutdown_both); | ||
| 177 | LOG_INFO(Debug_GDBStub, "Shut down server"); | ||
| 178 | |||
| 179 | break; | ||
| 180 | } | ||
| 148 | } | 181 | } |
| 149 | 182 | ||
| 150 | void ClientData(std::span<const u8> data) { | 183 | void ClientData(std::span<const u8> data) { |
| @@ -246,7 +279,9 @@ private: | |||
| 246 | boost::asio::ip::tcp::socket client_socket; | 279 | boost::asio::ip::tcp::socket client_socket; |
| 247 | std::optional<std::unique_lock<std::mutex>> suspend; | 280 | std::optional<std::unique_lock<std::mutex>> suspend; |
| 248 | 281 | ||
| 282 | SignalInfo info; | ||
| 249 | Kernel::KThread* active_thread; | 283 | Kernel::KThread* active_thread; |
| 284 | bool pipe_data; | ||
| 250 | bool stopped; | 285 | bool stopped; |
| 251 | 286 | ||
| 252 | std::array<u8, 4096> client_data; | 287 | std::array<u8, 4096> client_data; |
| @@ -263,7 +298,13 @@ Debugger::Debugger(Core::System& system, u16 port) { | |||
| 263 | Debugger::~Debugger() = default; | 298 | Debugger::~Debugger() = default; |
| 264 | 299 | ||
| 265 | bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { | 300 | bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { |
| 266 | return impl && impl->NotifyThreadStopped(thread); | 301 | return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread}); |
| 302 | } | ||
| 303 | |||
| 304 | void Debugger::NotifyShutdown() { | ||
| 305 | if (impl) { | ||
| 306 | impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr}); | ||
| 307 | } | ||
| 267 | } | 308 | } |
| 268 | 309 | ||
| 269 | } // namespace Core | 310 | } // namespace Core |
diff --git a/src/core/debugger/debugger.h b/src/core/debugger/debugger.h index ea36c6ab2..f9738ca3d 100644 --- a/src/core/debugger/debugger.h +++ b/src/core/debugger/debugger.h | |||
| @@ -35,6 +35,11 @@ public: | |||
| 35 | */ | 35 | */ |
| 36 | bool NotifyThreadStopped(Kernel::KThread* thread); | 36 | bool NotifyThreadStopped(Kernel::KThread* thread); |
| 37 | 37 | ||
| 38 | /** | ||
| 39 | * Notify the debugger that a shutdown is being performed now and disconnect. | ||
| 40 | */ | ||
| 41 | void NotifyShutdown(); | ||
| 42 | |||
| 38 | private: | 43 | private: |
| 39 | std::unique_ptr<DebuggerImpl> impl; | 44 | std::unique_ptr<DebuggerImpl> impl; |
| 40 | }; | 45 | }; |
diff --git a/src/core/debugger/debugger_interface.h b/src/core/debugger/debugger_interface.h index 35ba0bc61..c0bb4ecaf 100644 --- a/src/core/debugger/debugger_interface.h +++ b/src/core/debugger/debugger_interface.h | |||
| @@ -67,6 +67,11 @@ public: | |||
| 67 | virtual void Stopped(Kernel::KThread* thread) = 0; | 67 | virtual void Stopped(Kernel::KThread* thread) = 0; |
| 68 | 68 | ||
| 69 | /** | 69 | /** |
| 70 | * Called when emulation is shutting down. | ||
| 71 | */ | ||
| 72 | virtual void ShuttingDown() = 0; | ||
| 73 | |||
| 74 | /** | ||
| 70 | * Called when new data is asynchronously received on the client socket. | 75 | * Called when new data is asynchronously received on the client socket. |
| 71 | * A list of actions to perform is returned. | 76 | * A list of actions to perform is returned. |
| 72 | */ | 77 | */ |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index f52d78829..52e76f659 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -106,6 +106,8 @@ GDBStub::~GDBStub() = default; | |||
| 106 | 106 | ||
| 107 | void GDBStub::Connected() {} | 107 | void GDBStub::Connected() {} |
| 108 | 108 | ||
| 109 | void GDBStub::ShuttingDown() {} | ||
| 110 | |||
| 109 | void GDBStub::Stopped(Kernel::KThread* thread) { | 111 | void GDBStub::Stopped(Kernel::KThread* thread) { |
| 110 | SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)); | 112 | SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)); |
| 111 | } | 113 | } |
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 1bb638187..ec934c77e 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h | |||
| @@ -23,6 +23,7 @@ public: | |||
| 23 | 23 | ||
| 24 | void Connected() override; | 24 | void Connected() override; |
| 25 | void Stopped(Kernel::KThread* thread) override; | 25 | void Stopped(Kernel::KThread* thread) override; |
| 26 | void ShuttingDown() override; | ||
| 26 | std::vector<DebuggerAction> ClientData(std::span<const u8> data) override; | 27 | std::vector<DebuggerAction> ClientData(std::span<const u8> data) override; |
| 27 | 28 | ||
| 28 | private: | 29 | private: |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 80e6d23a5..c9288b4fe 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1545,6 +1545,7 @@ void GMainWindow::ShutdownGame() { | |||
| 1545 | 1545 | ||
| 1546 | AllowOSSleep(); | 1546 | AllowOSSleep(); |
| 1547 | 1547 | ||
| 1548 | system->DetachDebugger(); | ||
| 1548 | discord_rpc->Pause(); | 1549 | discord_rpc->Pause(); |
| 1549 | emu_thread->RequestStop(); | 1550 | emu_thread->RequestStop(); |
| 1550 | 1551 | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index a0d619c48..0dce5e274 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -229,6 +229,7 @@ int main(int argc, char** argv) { | |||
| 229 | while (emu_window->IsOpen()) { | 229 | while (emu_window->IsOpen()) { |
| 230 | emu_window->WaitEvent(); | 230 | emu_window->WaitEvent(); |
| 231 | } | 231 | } |
| 232 | system.DetachDebugger(); | ||
| 232 | void(system.Pause()); | 233 | void(system.Pause()); |
| 233 | system.Shutdown(); | 234 | system.Shutdown(); |
| 234 | 235 | ||