summaryrefslogtreecommitdiff
path: root/src/core/debugger/debugger.cpp
diff options
context:
space:
mode:
authorGravatar Liam2022-06-13 18:36:30 -0400
committerGravatar Liam2022-06-14 10:04:11 -0400
commit888f499188cb869dc8f8f1597c46add65c005324 (patch)
tree2abcaaf69fcb2c15352c99add7a97c9eea567486 /src/core/debugger/debugger.cpp
parentMerge pull request #8461 from Morph1984/msvc-narrow-conv (diff)
downloadyuzu-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.cpp94
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;