diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core.cpp | 18 | ||||
| -rw-r--r-- | src/core/core.h | 4 | ||||
| -rw-r--r-- | src/core/cpu_manager.cpp | 127 | ||||
| -rw-r--r-- | src/core/cpu_manager.h | 19 | ||||
| -rw-r--r-- | src/core/debugger/debugger.cpp | 94 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 59 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.h | 16 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 49 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 4 |
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 | ||
| 502 | std::unique_lock<std::mutex> System::StallCPU() { | 500 | std::unique_lock<std::mutex> System::StallProcesses() { |
| 503 | return impl->StallCPU(); | 501 | return impl->StallProcesses(); |
| 504 | } | 502 | } |
| 505 | 503 | ||
| 506 | void System::UnstallCPU() { | 504 | void System::UnstallProcesses() { |
| 507 | impl->UnstallCPU(); | 505 | impl->UnstallProcesses(); |
| 508 | } | 506 | } |
| 509 | 507 | ||
| 510 | void System::InitializeDebugger() { | 508 | void 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 | ||
| 17 | namespace Core { | 17 | namespace Core { |
| 18 | 18 | ||
| 19 | CpuManager::CpuManager(System& system_) | 19 | CpuManager::CpuManager(System& system_) : system{system_} {} |
| 20 | : pause_barrier{std::make_unique<Common::Barrier>(1)}, system{system_} {} | ||
| 21 | CpuManager::~CpuManager() = default; | 20 | CpuManager::~CpuManager() = default; |
| 22 | 21 | ||
| 23 | void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, | 22 | void 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 | ||
| 28 | void CpuManager::Initialize() { | 27 | void 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 | ||
| 41 | void CpuManager::Shutdown() { | 35 | void 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 | ||
| 46 | std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { | 43 | std::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 | ||
| 54 | std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() { | 51 | std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() { |
| 55 | return SuspendThreadFunction; | 52 | return ShutdownThreadFunction; |
| 56 | } | 53 | } |
| 57 | 54 | ||
| 58 | void CpuManager::GuestThreadFunction(void* cpu_manager_) { | 55 | void CpuManager::GuestThreadFunction(void* cpu_manager_) { |
| @@ -82,17 +79,12 @@ void CpuManager::IdleThreadFunction(void* cpu_manager_) { | |||
| 82 | } | 79 | } |
| 83 | } | 80 | } |
| 84 | 81 | ||
| 85 | void CpuManager::SuspendThreadFunction(void* cpu_manager_) { | 82 | void 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 | ||
| 94 | void* CpuManager::GetStartFuncParamater() { | 86 | void* 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 | ||
| 135 | void 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 | ||
| 193 | void 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 | |||
| 208 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | 170 | void 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 | ||
| 240 | void CpuManager::Pause(bool paused) { | 202 | void 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 | ||
| 257 | void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | 211 | void 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 | ||
| 278 | void KProcess::RegisterThread(const KThread* thread) { | 278 | void 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 | ||
| 282 | void KProcess::UnregisterThread(const KThread* thread) { | 284 | void 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 | ||
| 304 | ResultCode 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 | |||
| 300 | ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, | 348 | ResultCode 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 | ||
| 558 | KProcess::KProcess(KernelCore& kernel_) | 606 | KProcess::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 | ||
| 563 | KProcess::~KProcess() = default; | 612 | KProcess::~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 | ||
| 66 | enum class ProcessActivity : u32 { | ||
| 67 | Runnable, | ||
| 68 | Paused, | ||
| 69 | }; | ||
| 70 | |||
| 66 | class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { | 71 | class 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) { | |||
| 267 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { | 267 | ResultCode 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 | ||
| 273 | ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, | 273 | ResultCode 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 | ||
| 281 | ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread, | 281 | ResultCode 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 | ||
| 290 | void KThread::PostDestroy(uintptr_t arg) { | 290 | void 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 | ||
| 923 | void KernelCore::InterruptAllPhysicalCores() { | ||
| 924 | for (auto& physical_core : impl->cores) { | ||
| 925 | physical_core.Interrupt(); | ||
| 926 | } | ||
| 927 | } | ||
| 928 | |||
| 923 | void KernelCore::InvalidateAllInstructionCaches() { | 929 | void 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 | ||
| 1070 | void KernelCore::Suspend(bool in_suspention) { | 1076 | void 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 | } | 1085 | void KernelCore::ShutdownCores() { |
| 1086 | for (auto* thread : impl->shutdown_threads) { | ||
| 1087 | void(thread->Run()); | ||
| 1080 | } | 1088 | } |
| 1089 | InterruptAllPhysicalCores(); | ||
| 1081 | } | 1090 | } |
| 1082 | 1091 | ||
| 1083 | bool KernelCore::IsMulticore() const { | 1092 | bool 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(), ¶ms, sizeof(params)); | 157 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 158 | events_interface.failed[event_id] = false; | 158 | events_interface.failed[event_id] = false; |