diff options
| author | 2022-06-13 18:36:30 -0400 | |
|---|---|---|
| committer | 2022-06-14 10:04:11 -0400 | |
| commit | 888f499188cb869dc8f8f1597c46add65c005324 (patch) | |
| tree | 2abcaaf69fcb2c15352c99add7a97c9eea567486 /src/core/debugger/debugger.cpp | |
| parent | Merge pull request #8461 from Morph1984/msvc-narrow-conv (diff) | |
| download | yuzu-888f499188cb869dc8f8f1597c46add65c005324.tar.gz yuzu-888f499188cb869dc8f8f1597c46add65c005324.tar.xz yuzu-888f499188cb869dc8f8f1597c46add65c005324.zip | |
kernel: implement KProcess suspension
Diffstat (limited to 'src/core/debugger/debugger.cpp')
| -rw-r--r-- | src/core/debugger/debugger.cpp | 94 |
1 files changed, 43 insertions, 51 deletions
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index edf991d71..ab3940922 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -67,17 +67,19 @@ public: | |||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | bool SignalDebugger(SignalInfo signal_info) { | 69 | bool SignalDebugger(SignalInfo signal_info) { |
| 70 | std::scoped_lock lk{connection_lock}; | 70 | { |
| 71 | std::scoped_lock lk{connection_lock}; | ||
| 71 | 72 | ||
| 72 | if (stopped) { | 73 | if (stopped) { |
| 73 | // Do not notify the debugger about another event. | 74 | // Do not notify the debugger about another event. |
| 74 | // It should be ignored. | 75 | // It should be ignored. |
| 75 | return false; | 76 | return false; |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | // Set up the state. | 79 | // Set up the state. |
| 79 | stopped = true; | 80 | stopped = true; |
| 80 | info = signal_info; | 81 | info = signal_info; |
| 82 | } | ||
| 81 | 83 | ||
| 82 | // Write a single byte into the pipe to wake up the debug interface. | 84 | // 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))); | 85 | boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); |
| @@ -141,9 +143,6 @@ private: | |||
| 141 | AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); | 143 | AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); |
| 142 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); | 144 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); |
| 143 | 145 | ||
| 144 | // Stop the emulated CPU. | ||
| 145 | AllCoreStop(); | ||
| 146 | |||
| 147 | // Set the active thread. | 146 | // Set the active thread. |
| 148 | UpdateActiveThread(); | 147 | UpdateActiveThread(); |
| 149 | 148 | ||
| @@ -159,7 +158,7 @@ private: | |||
| 159 | switch (info.type) { | 158 | switch (info.type) { |
| 160 | case SignalType::Stopped: | 159 | case SignalType::Stopped: |
| 161 | // Stop emulation. | 160 | // Stop emulation. |
| 162 | AllCoreStop(); | 161 | PauseEmulation(); |
| 163 | 162 | ||
| 164 | // Notify the client. | 163 | // Notify the client. |
| 165 | active_thread = info.thread; | 164 | active_thread = info.thread; |
| @@ -171,7 +170,6 @@ private: | |||
| 171 | frontend->ShuttingDown(); | 170 | frontend->ShuttingDown(); |
| 172 | 171 | ||
| 173 | // Wait for emulation to shut down gracefully now. | 172 | // Wait for emulation to shut down gracefully now. |
| 174 | suspend.reset(); | ||
| 175 | signal_pipe.close(); | 173 | signal_pipe.close(); |
| 176 | client_socket.shutdown(boost::asio::socket_base::shutdown_both); | 174 | client_socket.shutdown(boost::asio::socket_base::shutdown_both); |
| 177 | LOG_INFO(Debug_GDBStub, "Shut down server"); | 175 | LOG_INFO(Debug_GDBStub, "Shut down server"); |
| @@ -189,32 +187,29 @@ private: | |||
| 189 | std::scoped_lock lk{connection_lock}; | 187 | std::scoped_lock lk{connection_lock}; |
| 190 | stopped = true; | 188 | stopped = true; |
| 191 | } | 189 | } |
| 192 | AllCoreStop(); | 190 | PauseEmulation(); |
| 193 | UpdateActiveThread(); | 191 | UpdateActiveThread(); |
| 194 | frontend->Stopped(active_thread); | 192 | frontend->Stopped(active_thread); |
| 195 | break; | 193 | break; |
| 196 | } | 194 | } |
| 197 | case DebuggerAction::Continue: | 195 | case DebuggerAction::Continue: |
| 198 | active_thread->SetStepState(Kernel::StepState::NotStepping); | 196 | MarkResumed([&] { ResumeEmulation(); }); |
| 199 | ResumeInactiveThreads(); | ||
| 200 | AllCoreResume(); | ||
| 201 | break; | 197 | break; |
| 202 | case DebuggerAction::StepThreadUnlocked: | 198 | case DebuggerAction::StepThreadUnlocked: |
| 203 | active_thread->SetStepState(Kernel::StepState::StepPending); | 199 | MarkResumed([&] { |
| 204 | ResumeInactiveThreads(); | 200 | active_thread->SetStepState(Kernel::StepState::StepPending); |
| 205 | AllCoreResume(); | 201 | active_thread->Resume(Kernel::SuspendType::Debug); |
| 202 | ResumeEmulation(active_thread); | ||
| 203 | }); | ||
| 206 | break; | 204 | break; |
| 207 | case DebuggerAction::StepThreadLocked: | 205 | case DebuggerAction::StepThreadLocked: { |
| 208 | active_thread->SetStepState(Kernel::StepState::StepPending); | 206 | MarkResumed([&] { |
| 209 | SuspendInactiveThreads(); | 207 | active_thread->SetStepState(Kernel::StepState::StepPending); |
| 210 | AllCoreResume(); | 208 | active_thread->Resume(Kernel::SuspendType::Debug); |
| 209 | }); | ||
| 211 | break; | 210 | break; |
| 211 | } | ||
| 212 | case DebuggerAction::ShutdownEmulation: { | 212 | case DebuggerAction::ShutdownEmulation: { |
| 213 | // Suspend all threads and release any locks held | ||
| 214 | active_thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 215 | SuspendInactiveThreads(); | ||
| 216 | AllCoreResume(); | ||
| 217 | |||
| 218 | // Spawn another thread that will exit after shutdown, | 213 | // Spawn another thread that will exit after shutdown, |
| 219 | // to avoid a deadlock | 214 | // to avoid a deadlock |
| 220 | Core::System* system_ref{&system}; | 215 | Core::System* system_ref{&system}; |
| @@ -226,33 +221,33 @@ private: | |||
| 226 | } | 221 | } |
| 227 | } | 222 | } |
| 228 | 223 | ||
| 229 | void AllCoreStop() { | 224 | void PauseEmulation() { |
| 230 | if (!suspend) { | 225 | // Put all threads to sleep on next scheduler round. |
| 231 | suspend = system.StallCPU(); | 226 | for (auto* thread : ThreadList()) { |
| 227 | thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 232 | } | 228 | } |
| 233 | } | ||
| 234 | 229 | ||
| 235 | void AllCoreResume() { | 230 | // Signal an interrupt so that scheduler will fire. |
| 236 | stopped = false; | 231 | system.Kernel().InterruptAllPhysicalCores(); |
| 237 | system.UnstallCPU(); | ||
| 238 | suspend.reset(); | ||
| 239 | } | 232 | } |
| 240 | 233 | ||
| 241 | void SuspendInactiveThreads() { | 234 | void ResumeEmulation(Kernel::KThread* except = nullptr) { |
| 235 | // Wake up all threads. | ||
| 242 | for (auto* thread : ThreadList()) { | 236 | for (auto* thread : ThreadList()) { |
| 243 | if (thread != active_thread) { | 237 | if (thread == except) { |
| 244 | thread->RequestSuspend(Kernel::SuspendType::Debug); | 238 | continue; |
| 245 | } | 239 | } |
| 240 | |||
| 241 | thread->SetStepState(Kernel::StepState::NotStepping); | ||
| 242 | thread->Resume(Kernel::SuspendType::Debug); | ||
| 246 | } | 243 | } |
| 247 | } | 244 | } |
| 248 | 245 | ||
| 249 | void ResumeInactiveThreads() { | 246 | template <typename Callback> |
| 250 | for (auto* thread : ThreadList()) { | 247 | void MarkResumed(Callback&& cb) { |
| 251 | if (thread != active_thread) { | 248 | std::scoped_lock lk{connection_lock}; |
| 252 | thread->Resume(Kernel::SuspendType::Debug); | 249 | stopped = false; |
| 253 | thread->SetStepState(Kernel::StepState::NotStepping); | 250 | cb(); |
| 254 | } | ||
| 255 | } | ||
| 256 | } | 251 | } |
| 257 | 252 | ||
| 258 | void UpdateActiveThread() { | 253 | void UpdateActiveThread() { |
| @@ -260,8 +255,6 @@ private: | |||
| 260 | if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { | 255 | if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { |
| 261 | active_thread = threads[0]; | 256 | active_thread = threads[0]; |
| 262 | } | 257 | } |
| 263 | active_thread->Resume(Kernel::SuspendType::Debug); | ||
| 264 | active_thread->SetStepState(Kernel::StepState::NotStepping); | ||
| 265 | } | 258 | } |
| 266 | 259 | ||
| 267 | const std::vector<Kernel::KThread*>& ThreadList() { | 260 | const std::vector<Kernel::KThread*>& ThreadList() { |
| @@ -277,7 +270,6 @@ private: | |||
| 277 | boost::asio::io_context io_context; | 270 | boost::asio::io_context io_context; |
| 278 | boost::process::async_pipe signal_pipe; | 271 | boost::process::async_pipe signal_pipe; |
| 279 | boost::asio::ip::tcp::socket client_socket; | 272 | boost::asio::ip::tcp::socket client_socket; |
| 280 | std::optional<std::unique_lock<std::mutex>> suspend; | ||
| 281 | 273 | ||
| 282 | SignalInfo info; | 274 | SignalInfo info; |
| 283 | Kernel::KThread* active_thread; | 275 | Kernel::KThread* active_thread; |