summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/core.cpp18
-rw-r--r--src/core/core.h4
-rw-r--r--src/core/cpu_manager.cpp127
-rw-r--r--src/core/cpu_manager.h19
-rw-r--r--src/core/debugger/debugger.cpp94
-rw-r--r--src/core/hle/kernel/k_process.cpp59
-rw-r--r--src/core/hle/kernel/k_process.h16
-rw-r--r--src/core/hle/kernel/k_thread.cpp8
-rw-r--r--src/core/hle/kernel/kernel.cpp49
-rw-r--r--src/core/hle/kernel/kernel.h11
-rw-r--r--src/core/hle/kernel/svc.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp4
12 files changed, 199 insertions, 212 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 954136adb..7723d9782 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -138,7 +138,6 @@ struct System::Impl {
138 138
139 kernel.Suspend(false); 139 kernel.Suspend(false);
140 core_timing.SyncPause(false); 140 core_timing.SyncPause(false);
141 cpu_manager.Pause(false);
142 is_paused = false; 141 is_paused = false;
143 142
144 return status; 143 return status;
@@ -150,25 +149,22 @@ struct System::Impl {
150 149
151 core_timing.SyncPause(true); 150 core_timing.SyncPause(true);
152 kernel.Suspend(true); 151 kernel.Suspend(true);
153 cpu_manager.Pause(true);
154 is_paused = true; 152 is_paused = true;
155 153
156 return status; 154 return status;
157 } 155 }
158 156
159 std::unique_lock<std::mutex> StallCPU() { 157 std::unique_lock<std::mutex> StallProcesses() {
160 std::unique_lock<std::mutex> lk(suspend_guard); 158 std::unique_lock<std::mutex> lk(suspend_guard);
161 kernel.Suspend(true); 159 kernel.Suspend(true);
162 core_timing.SyncPause(true); 160 core_timing.SyncPause(true);
163 cpu_manager.Pause(true);
164 return lk; 161 return lk;
165 } 162 }
166 163
167 void UnstallCPU() { 164 void UnstallProcesses() {
168 if (!is_paused) { 165 if (!is_paused) {
169 core_timing.SyncPause(false); 166 core_timing.SyncPause(false);
170 kernel.Suspend(false); 167 kernel.Suspend(false);
171 cpu_manager.Pause(false);
172 } 168 }
173 } 169 }
174 170
@@ -334,6 +330,8 @@ struct System::Impl {
334 gpu_core->NotifyShutdown(); 330 gpu_core->NotifyShutdown();
335 } 331 }
336 332
333 kernel.ShutdownCores();
334 cpu_manager.Shutdown();
337 debugger.reset(); 335 debugger.reset();
338 services.reset(); 336 services.reset();
339 service_manager.reset(); 337 service_manager.reset();
@@ -499,12 +497,12 @@ void System::DetachDebugger() {
499 } 497 }
500} 498}
501 499
502std::unique_lock<std::mutex> System::StallCPU() { 500std::unique_lock<std::mutex> System::StallProcesses() {
503 return impl->StallCPU(); 501 return impl->StallProcesses();
504} 502}
505 503
506void System::UnstallCPU() { 504void System::UnstallProcesses() {
507 impl->UnstallCPU(); 505 impl->UnstallProcesses();
508} 506}
509 507
510void System::InitializeDebugger() { 508void System::InitializeDebugger() {
diff --git a/src/core/core.h b/src/core/core.h
index 5c367349e..60efe4410 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -163,8 +163,8 @@ public:
163 /// Forcibly detach the debugger if it is running. 163 /// Forcibly detach the debugger if it is running.
164 void DetachDebugger(); 164 void DetachDebugger();
165 165
166 std::unique_lock<std::mutex> StallCPU(); 166 std::unique_lock<std::mutex> StallProcesses();
167 void UnstallCPU(); 167 void UnstallProcesses();
168 168
169 /** 169 /**
170 * Initialize the debugger. 170 * Initialize the debugger.
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 132fe5b60..1c07dc90e 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -16,31 +16,28 @@
16 16
17namespace Core { 17namespace Core {
18 18
19CpuManager::CpuManager(System& system_) 19CpuManager::CpuManager(System& system_) : system{system_} {}
20 : pause_barrier{std::make_unique<Common::Barrier>(1)}, system{system_} {}
21CpuManager::~CpuManager() = default; 20CpuManager::~CpuManager() = default;
22 21
23void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, 22void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager,
24 std::size_t core) { 23 std::size_t core) {
25 cpu_manager.RunThread(stop_token, core); 24 cpu_manager.RunThread(core);
26} 25}
27 26
28void CpuManager::Initialize() { 27void CpuManager::Initialize() {
29 running_mode = true; 28 num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
30 if (is_multicore) { 29
31 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 30 for (std::size_t core = 0; core < num_cores; core++) {
32 core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); 31 core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
33 }
34 pause_barrier = std::make_unique<Common::Barrier>(Core::Hardware::NUM_CPU_CORES + 1);
35 } else {
36 core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0);
37 pause_barrier = std::make_unique<Common::Barrier>(2);
38 } 32 }
39} 33}
40 34
41void CpuManager::Shutdown() { 35void CpuManager::Shutdown() {
42 running_mode = false; 36 for (std::size_t core = 0; core < num_cores; core++) {
43 Pause(false); 37 if (core_data[core].host_thread.joinable()) {
38 core_data[core].host_thread.join();
39 }
40 }
44} 41}
45 42
46std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { 43std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
@@ -51,8 +48,8 @@ std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
51 return IdleThreadFunction; 48 return IdleThreadFunction;
52} 49}
53 50
54std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() { 51std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
55 return SuspendThreadFunction; 52 return ShutdownThreadFunction;
56} 53}
57 54
58void CpuManager::GuestThreadFunction(void* cpu_manager_) { 55void CpuManager::GuestThreadFunction(void* cpu_manager_) {
@@ -82,17 +79,12 @@ void CpuManager::IdleThreadFunction(void* cpu_manager_) {
82 } 79 }
83} 80}
84 81
85void CpuManager::SuspendThreadFunction(void* cpu_manager_) { 82void CpuManager::ShutdownThreadFunction(void* cpu_manager) {
86 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 83 static_cast<CpuManager*>(cpu_manager)->ShutdownThread();
87 if (cpu_manager->is_multicore) {
88 cpu_manager->MultiCoreRunSuspendThread();
89 } else {
90 cpu_manager->SingleCoreRunSuspendThread();
91 }
92} 84}
93 85
94void* CpuManager::GetStartFuncParamater() { 86void* CpuManager::GetStartFuncParameter() {
95 return static_cast<void*>(this); 87 return this;
96} 88}
97 89
98/////////////////////////////////////////////////////////////////////////////// 90///////////////////////////////////////////////////////////////////////////////
@@ -132,21 +124,6 @@ void CpuManager::MultiCoreRunIdleThread() {
132 } 124 }
133} 125}
134 126
135void CpuManager::MultiCoreRunSuspendThread() {
136 auto& kernel = system.Kernel();
137 kernel.CurrentScheduler()->OnThreadStart();
138 while (true) {
139 auto core = kernel.CurrentPhysicalCoreIndex();
140 auto& scheduler = *kernel.CurrentScheduler();
141 Kernel::KThread* current_thread = scheduler.GetCurrentThread();
142 current_thread->DisableDispatch();
143
144 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
145 ASSERT(core == kernel.CurrentPhysicalCoreIndex());
146 scheduler.RescheduleCurrentCore();
147 }
148}
149
150/////////////////////////////////////////////////////////////////////////////// 127///////////////////////////////////////////////////////////////////////////////
151/// SingleCore /// 128/// SingleCore ///
152/////////////////////////////////////////////////////////////////////////////// 129///////////////////////////////////////////////////////////////////////////////
@@ -190,21 +167,6 @@ void CpuManager::SingleCoreRunIdleThread() {
190 } 167 }
191} 168}
192 169
193void CpuManager::SingleCoreRunSuspendThread() {
194 auto& kernel = system.Kernel();
195 kernel.CurrentScheduler()->OnThreadStart();
196 while (true) {
197 auto core = kernel.GetCurrentHostThreadID();
198 auto& scheduler = *kernel.CurrentScheduler();
199 Kernel::KThread* current_thread = scheduler.GetCurrentThread();
200 current_thread->DisableDispatch();
201
202 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context);
203 ASSERT(core == kernel.GetCurrentHostThreadID());
204 scheduler.RescheduleCurrentCore();
205 }
206}
207
208void CpuManager::PreemptSingleCore(bool from_running_enviroment) { 170void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
209 { 171 {
210 auto& kernel = system.Kernel(); 172 auto& kernel = system.Kernel();
@@ -237,24 +199,16 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
237 } 199 }
238} 200}
239 201
240void CpuManager::Pause(bool paused) { 202void CpuManager::ShutdownThread() {
241 std::scoped_lock lk{pause_lock}; 203 auto& kernel = system.Kernel();
242 204 auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
243 if (pause_state == paused) { 205 auto* current_thread = kernel.GetCurrentEmuThread();
244 return;
245 }
246
247 // Set the new state
248 pause_state.store(paused);
249
250 // Wake up any waiting threads
251 pause_state.notify_all();
252 206
253 // Wait for all threads to successfully change state before returning 207 Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
254 pause_barrier->Sync(); 208 UNREACHABLE();
255} 209}
256 210
257void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { 211void CpuManager::RunThread(std::size_t core) {
258 /// Initialization 212 /// Initialization
259 system.RegisterCoreThread(core); 213 system.RegisterCoreThread(core);
260 std::string name; 214 std::string name;
@@ -268,8 +222,6 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
268 Common::SetCurrentThreadPriority(Common::ThreadPriority::High); 222 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
269 auto& data = core_data[core]; 223 auto& data = core_data[core];
270 data.host_context = Common::Fiber::ThreadToFiber(); 224 data.host_context = Common::Fiber::ThreadToFiber();
271 const bool sc_sync = !is_async_gpu && !is_multicore;
272 bool sc_sync_first_use = sc_sync;
273 225
274 // Cleanup 226 // Cleanup
275 SCOPE_EXIT({ 227 SCOPE_EXIT({
@@ -277,32 +229,13 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
277 MicroProfileOnThreadExit(); 229 MicroProfileOnThreadExit();
278 }); 230 });
279 231
280 /// Running 232 // Running
281 while (running_mode) { 233 if (!is_async_gpu && !is_multicore) {
282 if (pause_state.load(std::memory_order_relaxed)) { 234 system.GPU().ObtainContext();
283 // Wait for caller to acknowledge pausing
284 pause_barrier->Sync();
285
286 // Wait until unpaused
287 pause_state.wait(true, std::memory_order_relaxed);
288
289 // Wait for caller to acknowledge unpausing
290 pause_barrier->Sync();
291 }
292
293 if (sc_sync_first_use) {
294 system.GPU().ObtainContext();
295 sc_sync_first_use = false;
296 }
297
298 // Emulation was stopped
299 if (stop_token.stop_requested()) {
300 return;
301 }
302
303 auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
304 Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
305 } 235 }
236
237 auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
238 Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
306} 239}
307 240
308} // namespace Core 241} // namespace Core
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index ddd9691ca..681bdaf19 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -46,12 +46,10 @@ public:
46 void Initialize(); 46 void Initialize();
47 void Shutdown(); 47 void Shutdown();
48 48
49 void Pause(bool paused);
50
51 static std::function<void(void*)> GetGuestThreadStartFunc(); 49 static std::function<void(void*)> GetGuestThreadStartFunc();
52 static std::function<void(void*)> GetIdleThreadStartFunc(); 50 static std::function<void(void*)> GetIdleThreadStartFunc();
53 static std::function<void(void*)> GetSuspendThreadStartFunc(); 51 static std::function<void(void*)> GetShutdownThreadStartFunc();
54 void* GetStartFuncParamater(); 52 void* GetStartFuncParameter();
55 53
56 void PreemptSingleCore(bool from_running_enviroment = true); 54 void PreemptSingleCore(bool from_running_enviroment = true);
57 55
@@ -63,38 +61,33 @@ private:
63 static void GuestThreadFunction(void* cpu_manager); 61 static void GuestThreadFunction(void* cpu_manager);
64 static void GuestRewindFunction(void* cpu_manager); 62 static void GuestRewindFunction(void* cpu_manager);
65 static void IdleThreadFunction(void* cpu_manager); 63 static void IdleThreadFunction(void* cpu_manager);
66 static void SuspendThreadFunction(void* cpu_manager); 64 static void ShutdownThreadFunction(void* cpu_manager);
67 65
68 void MultiCoreRunGuestThread(); 66 void MultiCoreRunGuestThread();
69 void MultiCoreRunGuestLoop(); 67 void MultiCoreRunGuestLoop();
70 void MultiCoreRunIdleThread(); 68 void MultiCoreRunIdleThread();
71 void MultiCoreRunSuspendThread();
72 69
73 void SingleCoreRunGuestThread(); 70 void SingleCoreRunGuestThread();
74 void SingleCoreRunGuestLoop(); 71 void SingleCoreRunGuestLoop();
75 void SingleCoreRunIdleThread(); 72 void SingleCoreRunIdleThread();
76 void SingleCoreRunSuspendThread();
77 73
78 static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core); 74 static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
79 75
80 void RunThread(std::stop_token stop_token, std::size_t core); 76 void ShutdownThread();
77 void RunThread(std::size_t core);
81 78
82 struct CoreData { 79 struct CoreData {
83 std::shared_ptr<Common::Fiber> host_context; 80 std::shared_ptr<Common::Fiber> host_context;
84 std::jthread host_thread; 81 std::jthread host_thread;
85 }; 82 };
86 83
87 std::atomic<bool> running_mode{};
88 std::atomic<bool> pause_state{};
89 std::unique_ptr<Common::Barrier> pause_barrier{};
90 std::mutex pause_lock{};
91
92 std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{}; 84 std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
93 85
94 bool is_async_gpu{}; 86 bool is_async_gpu{};
95 bool is_multicore{}; 87 bool is_multicore{};
96 std::atomic<std::size_t> current_core{}; 88 std::atomic<std::size_t> current_core{};
97 std::size_t idle_count{}; 89 std::size_t idle_count{};
90 std::size_t num_cores{};
98 static constexpr std::size_t max_cycle_runs = 5; 91 static constexpr std::size_t max_cycle_runs = 5;
99 92
100 System& system; 93 System& system;
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;
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 8c79b4f0f..cd863e715 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -275,11 +275,15 @@ void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr a
275 shmem->Close(); 275 shmem->Close();
276} 276}
277 277
278void KProcess::RegisterThread(const KThread* thread) { 278void KProcess::RegisterThread(KThread* thread) {
279 KScopedLightLock lk{list_lock};
280
279 thread_list.push_back(thread); 281 thread_list.push_back(thread);
280} 282}
281 283
282void KProcess::UnregisterThread(const KThread* thread) { 284void KProcess::UnregisterThread(KThread* thread) {
285 KScopedLightLock lk{list_lock};
286
283 thread_list.remove(thread); 287 thread_list.remove(thread);
284} 288}
285 289
@@ -297,6 +301,50 @@ ResultCode KProcess::Reset() {
297 return ResultSuccess; 301 return ResultSuccess;
298} 302}
299 303
304ResultCode KProcess::SetActivity(ProcessActivity activity) {
305 // Lock ourselves and the scheduler.
306 KScopedLightLock lk{state_lock};
307 KScopedLightLock list_lk{list_lock};
308 KScopedSchedulerLock sl{kernel};
309
310 // Validate our state.
311 R_UNLESS(status != ProcessStatus::Exiting, ResultInvalidState);
312 R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState);
313
314 // Either pause or resume.
315 if (activity == ProcessActivity::Paused) {
316 // Verify that we're not suspended.
317 if (is_suspended) {
318 return ResultInvalidState;
319 }
320
321 // Suspend all threads.
322 for (auto* thread : GetThreadList()) {
323 thread->RequestSuspend(SuspendType::Process);
324 }
325
326 // Set ourselves as suspended.
327 SetSuspended(true);
328 } else {
329 ASSERT(activity == ProcessActivity::Runnable);
330
331 // Verify that we're suspended.
332 if (!is_suspended) {
333 return ResultInvalidState;
334 }
335
336 // Resume all threads.
337 for (auto* thread : GetThreadList()) {
338 thread->Resume(SuspendType::Process);
339 }
340
341 // Set ourselves as resumed.
342 SetSuspended(false);
343 }
344
345 return ResultSuccess;
346}
347
300ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, 348ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
301 std::size_t code_size) { 349 std::size_t code_size) {
302 program_id = metadata.GetTitleID(); 350 program_id = metadata.GetTitleID();
@@ -556,9 +604,10 @@ bool KProcess::IsSignaled() const {
556} 604}
557 605
558KProcess::KProcess(KernelCore& kernel_) 606KProcess::KProcess(KernelCore& kernel_)
559 : KAutoObjectWithSlabHeapAndContainer{kernel_}, 607 : KAutoObjectWithSlabHeapAndContainer{kernel_}, page_table{std::make_unique<KPageTable>(
560 page_table{std::make_unique<KPageTable>(kernel_.System())}, handle_table{kernel_}, 608 kernel_.System())},
561 address_arbiter{kernel_.System()}, condition_var{kernel_.System()}, state_lock{kernel_} {} 609 handle_table{kernel_}, address_arbiter{kernel_.System()}, condition_var{kernel_.System()},
610 state_lock{kernel_}, list_lock{kernel_} {}
562 611
563KProcess::~KProcess() = default; 612KProcess::~KProcess() = default;
564 613
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 9f171e3da..e562a79b8 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -63,6 +63,11 @@ enum class ProcessStatus {
63 DebugBreak, 63 DebugBreak,
64}; 64};
65 65
66enum class ProcessActivity : u32 {
67 Runnable,
68 Paused,
69};
70
66class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { 71class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> {
67 KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); 72 KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
68 73
@@ -282,17 +287,17 @@ public:
282 u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const; 287 u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const;
283 288
284 /// Gets the list of all threads created with this process as their owner. 289 /// Gets the list of all threads created with this process as their owner.
285 const std::list<const KThread*>& GetThreadList() const { 290 std::list<KThread*>& GetThreadList() {
286 return thread_list; 291 return thread_list;
287 } 292 }
288 293
289 /// Registers a thread as being created under this process, 294 /// Registers a thread as being created under this process,
290 /// adding it to this process' thread list. 295 /// adding it to this process' thread list.
291 void RegisterThread(const KThread* thread); 296 void RegisterThread(KThread* thread);
292 297
293 /// Unregisters a thread from this process, removing it 298 /// Unregisters a thread from this process, removing it
294 /// from this process' thread list. 299 /// from this process' thread list.
295 void UnregisterThread(const KThread* thread); 300 void UnregisterThread(KThread* thread);
296 301
297 /// Clears the signaled state of the process if and only if it's signaled. 302 /// Clears the signaled state of the process if and only if it's signaled.
298 /// 303 ///
@@ -347,6 +352,8 @@ public:
347 352
348 void DoWorkerTaskImpl(); 353 void DoWorkerTaskImpl();
349 354
355 ResultCode SetActivity(ProcessActivity activity);
356
350 void PinCurrentThread(s32 core_id); 357 void PinCurrentThread(s32 core_id);
351 void UnpinCurrentThread(s32 core_id); 358 void UnpinCurrentThread(s32 core_id);
352 void UnpinThread(KThread* thread); 359 void UnpinThread(KThread* thread);
@@ -442,7 +449,7 @@ private:
442 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{}; 449 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
443 450
444 /// List of threads that are running with this process as their owner. 451 /// List of threads that are running with this process as their owner.
445 std::list<const KThread*> thread_list; 452 std::list<KThread*> thread_list;
446 453
447 /// List of shared memory that are running with this process as their owner. 454 /// List of shared memory that are running with this process as their owner.
448 std::list<KSharedMemoryInfo*> shared_memory_list; 455 std::list<KSharedMemoryInfo*> shared_memory_list;
@@ -475,6 +482,7 @@ private:
475 KThread* exception_thread{}; 482 KThread* exception_thread{};
476 483
477 KLightLock state_lock; 484 KLightLock state_lock;
485 KLightLock list_lock;
478 486
479 using TLPTree = 487 using TLPTree =
480 Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>; 488 Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index ea2160099..8d48a7901 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -267,15 +267,15 @@ ResultCode KThread::InitializeDummyThread(KThread* thread) {
267ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { 267ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
268 return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, 268 return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
269 Core::CpuManager::GetIdleThreadStartFunc(), 269 Core::CpuManager::GetIdleThreadStartFunc(),
270 system.GetCpuManager().GetStartFuncParamater()); 270 system.GetCpuManager().GetStartFuncParameter());
271} 271}
272 272
273ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, 273ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
274 KThreadFunction func, uintptr_t arg, 274 KThreadFunction func, uintptr_t arg,
275 s32 virt_core) { 275 s32 virt_core) {
276 return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority, 276 return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
277 Core::CpuManager::GetSuspendThreadStartFunc(), 277 Core::CpuManager::GetShutdownThreadStartFunc(),
278 system.GetCpuManager().GetStartFuncParamater()); 278 system.GetCpuManager().GetStartFuncParameter());
279} 279}
280 280
281ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread, 281ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
@@ -284,7 +284,7 @@ ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
284 system.Kernel().GlobalSchedulerContext().AddThread(thread); 284 system.Kernel().GlobalSchedulerContext().AddThread(thread);
285 return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, 285 return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
286 ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(), 286 ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
287 system.GetCpuManager().GetStartFuncParamater()); 287 system.GetCpuManager().GetStartFuncParameter());
288} 288}
289 289
290void KThread::PostDestroy(uintptr_t arg) { 290void KThread::PostDestroy(uintptr_t arg) {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b2c4f12b4..73593c7a0 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -76,7 +76,7 @@ struct KernelCore::Impl {
76 InitializeMemoryLayout(); 76 InitializeMemoryLayout();
77 Init::InitializeKPageBufferSlabHeap(system); 77 Init::InitializeKPageBufferSlabHeap(system);
78 InitializeSchedulers(); 78 InitializeSchedulers();
79 InitializeSuspendThreads(); 79 InitializeShutdownThreads();
80 InitializePreemption(kernel); 80 InitializePreemption(kernel);
81 81
82 RegisterHostThread(); 82 RegisterHostThread();
@@ -143,9 +143,9 @@ struct KernelCore::Impl {
143 CleanupObject(system_resource_limit); 143 CleanupObject(system_resource_limit);
144 144
145 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { 145 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
146 if (suspend_threads[core_id]) { 146 if (shutdown_threads[core_id]) {
147 suspend_threads[core_id]->Close(); 147 shutdown_threads[core_id]->Close();
148 suspend_threads[core_id] = nullptr; 148 shutdown_threads[core_id] = nullptr;
149 } 149 }
150 150
151 schedulers[core_id]->Finalize(); 151 schedulers[core_id]->Finalize();
@@ -247,14 +247,14 @@ struct KernelCore::Impl {
247 system.CoreTiming().ScheduleEvent(time_interval, preemption_event); 247 system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
248 } 248 }
249 249
250 void InitializeSuspendThreads() { 250 void InitializeShutdownThreads() {
251 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { 251 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
252 suspend_threads[core_id] = KThread::Create(system.Kernel()); 252 shutdown_threads[core_id] = KThread::Create(system.Kernel());
253 ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {}, 253 ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {},
254 core_id) 254 core_id)
255 .IsSuccess()); 255 .IsSuccess());
256 suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); 256 shutdown_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
257 suspend_threads[core_id]->DisableDispatch(); 257 shutdown_threads[core_id]->DisableDispatch();
258 } 258 }
259 } 259 }
260 260
@@ -769,7 +769,7 @@ struct KernelCore::Impl {
769 std::weak_ptr<ServiceThread> default_service_thread; 769 std::weak_ptr<ServiceThread> default_service_thread;
770 Common::ThreadWorker service_threads_manager; 770 Common::ThreadWorker service_threads_manager;
771 771
772 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads; 772 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
773 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; 773 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
774 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; 774 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
775 775
@@ -920,6 +920,12 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
920 return *impl->global_object_list_container; 920 return *impl->global_object_list_container;
921} 921}
922 922
923void KernelCore::InterruptAllPhysicalCores() {
924 for (auto& physical_core : impl->cores) {
925 physical_core.Interrupt();
926 }
927}
928
923void KernelCore::InvalidateAllInstructionCaches() { 929void KernelCore::InvalidateAllInstructionCaches() {
924 for (auto& physical_core : impl->cores) { 930 for (auto& physical_core : impl->cores) {
925 physical_core.ArmInterface().ClearInstructionCache(); 931 physical_core.ArmInterface().ClearInstructionCache();
@@ -1067,17 +1073,20 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const {
1067 return *impl->hidbus_shared_mem; 1073 return *impl->hidbus_shared_mem;
1068} 1074}
1069 1075
1070void KernelCore::Suspend(bool in_suspention) { 1076void KernelCore::Suspend(bool suspended) {
1071 const bool should_suspend = exception_exited || in_suspention; 1077 const bool should_suspend{exception_exited || suspended};
1072 { 1078 const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
1073 KScopedSchedulerLock lock(*this); 1079
1074 const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; 1080 for (auto* process : GetProcessList()) {
1075 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { 1081 process->SetActivity(activity);
1076 impl->suspend_threads[core_id]->SetState(state); 1082 }
1077 impl->suspend_threads[core_id]->SetWaitReasonForDebugging( 1083}
1078 ThreadWaitReasonForDebugging::Suspended); 1084
1079 } 1085void KernelCore::ShutdownCores() {
1086 for (auto* thread : impl->shutdown_threads) {
1087 void(thread->Run());
1080 } 1088 }
1089 InterruptAllPhysicalCores();
1081} 1090}
1082 1091
1083bool KernelCore::IsMulticore() const { 1092bool KernelCore::IsMulticore() const {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 926e14c6f..4e7beab0e 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -184,6 +184,8 @@ public:
184 184
185 const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const; 185 const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
186 186
187 void InterruptAllPhysicalCores();
188
187 void InvalidateAllInstructionCaches(); 189 void InvalidateAllInstructionCaches();
188 190
189 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); 191 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
@@ -269,12 +271,15 @@ public:
269 /// Gets the shared memory object for HIDBus services. 271 /// Gets the shared memory object for HIDBus services.
270 const Kernel::KSharedMemory& GetHidBusSharedMem() const; 272 const Kernel::KSharedMemory& GetHidBusSharedMem() const;
271 273
272 /// Suspend/unsuspend the OS. 274 /// Suspend/unsuspend all processes.
273 void Suspend(bool in_suspention); 275 void Suspend(bool suspend);
274 276
275 /// Exceptional exit the OS. 277 /// Exceptional exit all processes.
276 void ExceptionalExit(); 278 void ExceptionalExit();
277 279
280 /// Notify emulated CPU cores to shut down.
281 void ShutdownCores();
282
278 bool IsMulticore() const; 283 bool IsMulticore() const;
279 284
280 bool IsShuttingDown() const; 285 bool IsShuttingDown() const;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4f0a44363..47db0bacf 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2537,7 +2537,7 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
2537 return ResultOutOfRange; 2537 return ResultOutOfRange;
2538 } 2538 }
2539 2539
2540 const auto* const current_process = system.Kernel().CurrentProcess(); 2540 auto* const current_process = system.Kernel().CurrentProcess();
2541 const auto total_copy_size = out_thread_ids_size * sizeof(u64); 2541 const auto total_copy_size = out_thread_ids_size * sizeof(u64);
2542 2542
2543 if (out_thread_ids_size > 0 && 2543 if (out_thread_ids_size > 0 &&
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 705fefc83..527531f29 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -150,9 +150,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
150 event.event->GetWritableEvent().Clear(); 150 event.event->GetWritableEvent().Clear();
151 if (events_interface.failed[event_id]) { 151 if (events_interface.failed[event_id]) {
152 { 152 {
153 auto lk = system.StallCPU(); 153 auto lk = system.StallProcesses();
154 gpu.WaitFence(params.syncpt_id, target_value); 154 gpu.WaitFence(params.syncpt_id, target_value);
155 system.UnstallCPU(); 155 system.UnstallProcesses();
156 } 156 }
157 std::memcpy(output.data(), &params, sizeof(params)); 157 std::memcpy(output.data(), &params, sizeof(params));
158 events_interface.failed[event_id] = false; 158 events_interface.failed[event_id] = false;