diff options
| author | 2022-06-16 02:41:12 +0200 | |
|---|---|---|
| committer | 2022-06-16 02:41:12 +0200 | |
| commit | f86b770ff75efff029fa82b959b3f33eca1750fe (patch) | |
| tree | 8c1aa046c96d7f943288ecb3455f4091cdc31a09 /src/core/cpu_manager.cpp | |
| parent | Merge pull request #8460 from Morph1984/bounded-q (diff) | |
| parent | kernel: implement KProcess suspension (diff) | |
| download | yuzu-f86b770ff75efff029fa82b959b3f33eca1750fe.tar.gz yuzu-f86b770ff75efff029fa82b959b3f33eca1750fe.tar.xz yuzu-f86b770ff75efff029fa82b959b3f33eca1750fe.zip | |
Merge pull request #8457 from liamwhite/kprocess-suspend
kernel: implement KProcess suspension
Diffstat (limited to 'src/core/cpu_manager.cpp')
| -rw-r--r-- | src/core/cpu_manager.cpp | 127 |
1 files changed, 30 insertions, 97 deletions
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 |