diff options
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 b4718fbbe..271e1ba04 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 | /////////////////////////////////////////////////////////////////////////////// |
| @@ -134,21 +126,6 @@ void CpuManager::MultiCoreRunIdleThread() { | |||
| 134 | } | 126 | } |
| 135 | } | 127 | } |
| 136 | 128 | ||
| 137 | void CpuManager::MultiCoreRunSuspendThread() { | ||
| 138 | auto& kernel = system.Kernel(); | ||
| 139 | kernel.CurrentScheduler()->OnThreadStart(); | ||
| 140 | while (true) { | ||
| 141 | auto core = kernel.CurrentPhysicalCoreIndex(); | ||
| 142 | auto& scheduler = *kernel.CurrentScheduler(); | ||
| 143 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | ||
| 144 | current_thread->DisableDispatch(); | ||
| 145 | |||
| 146 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); | ||
| 147 | ASSERT(core == kernel.CurrentPhysicalCoreIndex()); | ||
| 148 | scheduler.RescheduleCurrentCore(); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | /////////////////////////////////////////////////////////////////////////////// | 129 | /////////////////////////////////////////////////////////////////////////////// |
| 153 | /// SingleCore /// | 130 | /// SingleCore /// |
| 154 | /////////////////////////////////////////////////////////////////////////////// | 131 | /////////////////////////////////////////////////////////////////////////////// |
| @@ -194,21 +171,6 @@ void CpuManager::SingleCoreRunIdleThread() { | |||
| 194 | } | 171 | } |
| 195 | } | 172 | } |
| 196 | 173 | ||
| 197 | void CpuManager::SingleCoreRunSuspendThread() { | ||
| 198 | auto& kernel = system.Kernel(); | ||
| 199 | kernel.CurrentScheduler()->OnThreadStart(); | ||
| 200 | while (true) { | ||
| 201 | auto core = kernel.GetCurrentHostThreadID(); | ||
| 202 | auto& scheduler = *kernel.CurrentScheduler(); | ||
| 203 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | ||
| 204 | current_thread->DisableDispatch(); | ||
| 205 | |||
| 206 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); | ||
| 207 | ASSERT(core == kernel.GetCurrentHostThreadID()); | ||
| 208 | scheduler.RescheduleCurrentCore(); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | 174 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { |
| 213 | { | 175 | { |
| 214 | auto& kernel = system.Kernel(); | 176 | auto& kernel = system.Kernel(); |
| @@ -241,24 +203,16 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | |||
| 241 | } | 203 | } |
| 242 | } | 204 | } |
| 243 | 205 | ||
| 244 | void CpuManager::Pause(bool paused) { | 206 | void CpuManager::ShutdownThread() { |
| 245 | std::scoped_lock lk{pause_lock}; | 207 | auto& kernel = system.Kernel(); |
| 246 | 208 | auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0; | |
| 247 | if (pause_state == paused) { | 209 | auto* current_thread = kernel.GetCurrentEmuThread(); |
| 248 | return; | ||
| 249 | } | ||
| 250 | |||
| 251 | // Set the new state | ||
| 252 | pause_state.store(paused); | ||
| 253 | |||
| 254 | // Wake up any waiting threads | ||
| 255 | pause_state.notify_all(); | ||
| 256 | 210 | ||
| 257 | // Wait for all threads to successfully change state before returning | 211 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); |
| 258 | pause_barrier->Sync(); | 212 | UNREACHABLE(); |
| 259 | } | 213 | } |
| 260 | 214 | ||
| 261 | void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | 215 | void CpuManager::RunThread(std::size_t core) { |
| 262 | /// Initialization | 216 | /// Initialization |
| 263 | system.RegisterCoreThread(core); | 217 | system.RegisterCoreThread(core); |
| 264 | std::string name; | 218 | std::string name; |
| @@ -272,8 +226,6 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | |||
| 272 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | 226 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); |
| 273 | auto& data = core_data[core]; | 227 | auto& data = core_data[core]; |
| 274 | data.host_context = Common::Fiber::ThreadToFiber(); | 228 | data.host_context = Common::Fiber::ThreadToFiber(); |
| 275 | const bool sc_sync = !is_async_gpu && !is_multicore; | ||
| 276 | bool sc_sync_first_use = sc_sync; | ||
| 277 | 229 | ||
| 278 | // Cleanup | 230 | // Cleanup |
| 279 | SCOPE_EXIT({ | 231 | SCOPE_EXIT({ |
| @@ -281,32 +233,13 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | |||
| 281 | MicroProfileOnThreadExit(); | 233 | MicroProfileOnThreadExit(); |
| 282 | }); | 234 | }); |
| 283 | 235 | ||
| 284 | /// Running | 236 | // Running |
| 285 | while (running_mode) { | 237 | if (!is_async_gpu && !is_multicore) { |
| 286 | if (pause_state.load(std::memory_order_relaxed)) { | 238 | system.GPU().ObtainContext(); |
| 287 | // Wait for caller to acknowledge pausing | ||
| 288 | pause_barrier->Sync(); | ||
| 289 | |||
| 290 | // Wait until unpaused | ||
| 291 | pause_state.wait(true, std::memory_order_relaxed); | ||
| 292 | |||
| 293 | // Wait for caller to acknowledge unpausing | ||
| 294 | pause_barrier->Sync(); | ||
| 295 | } | ||
| 296 | |||
| 297 | if (sc_sync_first_use) { | ||
| 298 | system.GPU().ObtainContext(); | ||
| 299 | sc_sync_first_use = false; | ||
| 300 | } | ||
| 301 | |||
| 302 | // Emulation was stopped | ||
| 303 | if (stop_token.stop_requested()) { | ||
| 304 | return; | ||
| 305 | } | ||
| 306 | |||
| 307 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | ||
| 308 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); | ||
| 309 | } | 239 | } |
| 240 | |||
| 241 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | ||
| 242 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); | ||
| 310 | } | 243 | } |
| 311 | 244 | ||
| 312 | } // namespace Core | 245 | } // namespace Core |