diff options
Diffstat (limited to 'src/core/cpu_manager.cpp')
| -rw-r--r-- | src/core/cpu_manager.cpp | 133 |
1 files changed, 69 insertions, 64 deletions
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 688b99eba..373395047 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -4,15 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/fiber.h" | 5 | #include "common/fiber.h" |
| 6 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 7 | #include "common/scope_exit.h" | ||
| 7 | #include "common/thread.h" | 8 | #include "common/thread.h" |
| 8 | #include "core/arm/exclusive_monitor.h" | 9 | #include "core/arm/exclusive_monitor.h" |
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| 10 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 11 | #include "core/cpu_manager.h" | 12 | #include "core/cpu_manager.h" |
| 12 | #include "core/gdbstub/gdbstub.h" | 13 | #include "core/hle/kernel/k_scheduler.h" |
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/physical_core.h" | 15 | #include "core/hle/kernel/physical_core.h" |
| 15 | #include "core/hle/kernel/scheduler.h" | ||
| 16 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/thread.h" |
| 17 | #include "video_core/gpu.h" | 17 | #include "video_core/gpu.h" |
| 18 | 18 | ||
| @@ -109,28 +109,26 @@ void* CpuManager::GetStartFuncParamater() { | |||
| 109 | 109 | ||
| 110 | void CpuManager::MultiCoreRunGuestThread() { | 110 | void CpuManager::MultiCoreRunGuestThread() { |
| 111 | auto& kernel = system.Kernel(); | 111 | auto& kernel = system.Kernel(); |
| 112 | { | 112 | kernel.CurrentScheduler()->OnThreadStart(); |
| 113 | auto& sched = kernel.CurrentScheduler(); | 113 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 114 | sched.OnThreadStart(); | 114 | auto& host_context = thread->GetHostContext(); |
| 115 | } | 115 | host_context->SetRewindPoint(GuestRewindFunction, this); |
| 116 | MultiCoreRunGuestLoop(); | 116 | MultiCoreRunGuestLoop(); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void CpuManager::MultiCoreRunGuestLoop() { | 119 | void CpuManager::MultiCoreRunGuestLoop() { |
| 120 | auto& kernel = system.Kernel(); | 120 | auto& kernel = system.Kernel(); |
| 121 | auto* thread = kernel.CurrentScheduler().GetCurrentThread(); | 121 | |
| 122 | while (true) { | 122 | while (true) { |
| 123 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 123 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 124 | auto& arm_interface = thread->ArmInterface(); | ||
| 125 | system.EnterDynarmicProfile(); | 124 | system.EnterDynarmicProfile(); |
| 126 | while (!physical_core->IsInterrupted()) { | 125 | while (!physical_core->IsInterrupted()) { |
| 127 | arm_interface.Run(); | 126 | physical_core->Run(); |
| 128 | physical_core = &kernel.CurrentPhysicalCore(); | 127 | physical_core = &kernel.CurrentPhysicalCore(); |
| 129 | } | 128 | } |
| 130 | system.ExitDynarmicProfile(); | 129 | system.ExitDynarmicProfile(); |
| 131 | arm_interface.ClearExclusiveState(); | 130 | physical_core->ArmInterface().ClearExclusiveState(); |
| 132 | auto& scheduler = kernel.CurrentScheduler(); | 131 | kernel.CurrentScheduler()->RescheduleCurrentCore(); |
| 133 | scheduler.TryDoContextSwitch(); | ||
| 134 | } | 132 | } |
| 135 | } | 133 | } |
| 136 | 134 | ||
| @@ -139,25 +137,21 @@ void CpuManager::MultiCoreRunIdleThread() { | |||
| 139 | while (true) { | 137 | while (true) { |
| 140 | auto& physical_core = kernel.CurrentPhysicalCore(); | 138 | auto& physical_core = kernel.CurrentPhysicalCore(); |
| 141 | physical_core.Idle(); | 139 | physical_core.Idle(); |
| 142 | auto& scheduler = kernel.CurrentScheduler(); | 140 | kernel.CurrentScheduler()->RescheduleCurrentCore(); |
| 143 | scheduler.TryDoContextSwitch(); | ||
| 144 | } | 141 | } |
| 145 | } | 142 | } |
| 146 | 143 | ||
| 147 | void CpuManager::MultiCoreRunSuspendThread() { | 144 | void CpuManager::MultiCoreRunSuspendThread() { |
| 148 | auto& kernel = system.Kernel(); | 145 | auto& kernel = system.Kernel(); |
| 149 | { | 146 | kernel.CurrentScheduler()->OnThreadStart(); |
| 150 | auto& sched = kernel.CurrentScheduler(); | ||
| 151 | sched.OnThreadStart(); | ||
| 152 | } | ||
| 153 | while (true) { | 147 | while (true) { |
| 154 | auto core = kernel.GetCurrentHostThreadID(); | 148 | auto core = kernel.GetCurrentHostThreadID(); |
| 155 | auto& scheduler = kernel.CurrentScheduler(); | 149 | auto& scheduler = *kernel.CurrentScheduler(); |
| 156 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 150 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 157 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); | 151 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); |
| 158 | ASSERT(scheduler.ContextSwitchPending()); | 152 | ASSERT(scheduler.ContextSwitchPending()); |
| 159 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 153 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 160 | scheduler.TryDoContextSwitch(); | 154 | scheduler.RescheduleCurrentCore(); |
| 161 | } | 155 | } |
| 162 | } | 156 | } |
| 163 | 157 | ||
| @@ -205,32 +199,31 @@ void CpuManager::MultiCorePause(bool paused) { | |||
| 205 | 199 | ||
| 206 | void CpuManager::SingleCoreRunGuestThread() { | 200 | void CpuManager::SingleCoreRunGuestThread() { |
| 207 | auto& kernel = system.Kernel(); | 201 | auto& kernel = system.Kernel(); |
| 208 | { | 202 | kernel.CurrentScheduler()->OnThreadStart(); |
| 209 | auto& sched = kernel.CurrentScheduler(); | 203 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 210 | sched.OnThreadStart(); | 204 | auto& host_context = thread->GetHostContext(); |
| 211 | } | 205 | host_context->SetRewindPoint(GuestRewindFunction, this); |
| 212 | SingleCoreRunGuestLoop(); | 206 | SingleCoreRunGuestLoop(); |
| 213 | } | 207 | } |
| 214 | 208 | ||
| 215 | void CpuManager::SingleCoreRunGuestLoop() { | 209 | void CpuManager::SingleCoreRunGuestLoop() { |
| 216 | auto& kernel = system.Kernel(); | 210 | auto& kernel = system.Kernel(); |
| 217 | auto* thread = kernel.CurrentScheduler().GetCurrentThread(); | 211 | auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 218 | while (true) { | 212 | while (true) { |
| 219 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 213 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 220 | auto& arm_interface = thread->ArmInterface(); | ||
| 221 | system.EnterDynarmicProfile(); | 214 | system.EnterDynarmicProfile(); |
| 222 | if (!physical_core->IsInterrupted()) { | 215 | if (!physical_core->IsInterrupted()) { |
| 223 | arm_interface.Run(); | 216 | physical_core->Run(); |
| 224 | physical_core = &kernel.CurrentPhysicalCore(); | 217 | physical_core = &kernel.CurrentPhysicalCore(); |
| 225 | } | 218 | } |
| 226 | system.ExitDynarmicProfile(); | 219 | system.ExitDynarmicProfile(); |
| 227 | thread->SetPhantomMode(true); | 220 | thread->SetPhantomMode(true); |
| 228 | system.CoreTiming().Advance(); | 221 | system.CoreTiming().Advance(); |
| 229 | thread->SetPhantomMode(false); | 222 | thread->SetPhantomMode(false); |
| 230 | arm_interface.ClearExclusiveState(); | 223 | physical_core->ArmInterface().ClearExclusiveState(); |
| 231 | PreemptSingleCore(); | 224 | PreemptSingleCore(); |
| 232 | auto& scheduler = kernel.Scheduler(current_core); | 225 | auto& scheduler = kernel.Scheduler(current_core); |
| 233 | scheduler.TryDoContextSwitch(); | 226 | scheduler.RescheduleCurrentCore(); |
| 234 | } | 227 | } |
| 235 | } | 228 | } |
| 236 | 229 | ||
| @@ -242,51 +235,53 @@ void CpuManager::SingleCoreRunIdleThread() { | |||
| 242 | system.CoreTiming().AddTicks(1000U); | 235 | system.CoreTiming().AddTicks(1000U); |
| 243 | idle_count++; | 236 | idle_count++; |
| 244 | auto& scheduler = physical_core.Scheduler(); | 237 | auto& scheduler = physical_core.Scheduler(); |
| 245 | scheduler.TryDoContextSwitch(); | 238 | scheduler.RescheduleCurrentCore(); |
| 246 | } | 239 | } |
| 247 | } | 240 | } |
| 248 | 241 | ||
| 249 | void CpuManager::SingleCoreRunSuspendThread() { | 242 | void CpuManager::SingleCoreRunSuspendThread() { |
| 250 | auto& kernel = system.Kernel(); | 243 | auto& kernel = system.Kernel(); |
| 251 | { | 244 | kernel.CurrentScheduler()->OnThreadStart(); |
| 252 | auto& sched = kernel.CurrentScheduler(); | ||
| 253 | sched.OnThreadStart(); | ||
| 254 | } | ||
| 255 | while (true) { | 245 | while (true) { |
| 256 | auto core = kernel.GetCurrentHostThreadID(); | 246 | auto core = kernel.GetCurrentHostThreadID(); |
| 257 | auto& scheduler = kernel.CurrentScheduler(); | 247 | auto& scheduler = *kernel.CurrentScheduler(); |
| 258 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 248 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 259 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); | 249 | Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); |
| 260 | ASSERT(scheduler.ContextSwitchPending()); | 250 | ASSERT(scheduler.ContextSwitchPending()); |
| 261 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 251 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 262 | scheduler.TryDoContextSwitch(); | 252 | scheduler.RescheduleCurrentCore(); |
| 263 | } | 253 | } |
| 264 | } | 254 | } |
| 265 | 255 | ||
| 266 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | 256 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { |
| 267 | std::size_t old_core = current_core; | 257 | { |
| 268 | auto& scheduler = system.Kernel().Scheduler(old_core); | 258 | auto& scheduler = system.Kernel().Scheduler(current_core); |
| 269 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 259 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 270 | if (idle_count >= 4 || from_running_enviroment) { | 260 | if (idle_count >= 4 || from_running_enviroment) { |
| 271 | if (!from_running_enviroment) { | 261 | if (!from_running_enviroment) { |
| 272 | system.CoreTiming().Idle(); | 262 | system.CoreTiming().Idle(); |
| 273 | idle_count = 0; | 263 | idle_count = 0; |
| 264 | } | ||
| 265 | current_thread->SetPhantomMode(true); | ||
| 266 | system.CoreTiming().Advance(); | ||
| 267 | current_thread->SetPhantomMode(false); | ||
| 274 | } | 268 | } |
| 275 | current_thread->SetPhantomMode(true); | 269 | current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); |
| 276 | system.CoreTiming().Advance(); | 270 | system.CoreTiming().ResetTicks(); |
| 277 | current_thread->SetPhantomMode(false); | 271 | scheduler.Unload(scheduler.GetCurrentThread()); |
| 272 | |||
| 273 | auto& next_scheduler = system.Kernel().Scheduler(current_core); | ||
| 274 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); | ||
| 278 | } | 275 | } |
| 279 | current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); | 276 | |
| 280 | system.CoreTiming().ResetTicks(); | 277 | // May have changed scheduler |
| 281 | scheduler.Unload(); | 278 | { |
| 282 | auto& next_scheduler = system.Kernel().Scheduler(current_core); | 279 | auto& scheduler = system.Kernel().Scheduler(current_core); |
| 283 | Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); | 280 | scheduler.Reload(scheduler.GetCurrentThread()); |
| 284 | /// May have changed scheduler | 281 | auto* currrent_thread2 = scheduler.GetCurrentThread(); |
| 285 | auto& current_scheduler = system.Kernel().Scheduler(current_core); | 282 | if (!currrent_thread2->IsIdleThread()) { |
| 286 | current_scheduler.Reload(); | 283 | idle_count = 0; |
| 287 | auto* currrent_thread2 = current_scheduler.GetCurrentThread(); | 284 | } |
| 288 | if (!currrent_thread2->IsIdleThread()) { | ||
| 289 | idle_count = 0; | ||
| 290 | } | 285 | } |
| 291 | } | 286 | } |
| 292 | 287 | ||
| @@ -343,6 +338,16 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 343 | data.initialized = true; | 338 | data.initialized = true; |
| 344 | const bool sc_sync = !is_async_gpu && !is_multicore; | 339 | const bool sc_sync = !is_async_gpu && !is_multicore; |
| 345 | bool sc_sync_first_use = sc_sync; | 340 | bool sc_sync_first_use = sc_sync; |
| 341 | |||
| 342 | // Cleanup | ||
| 343 | SCOPE_EXIT({ | ||
| 344 | data.host_context->Exit(); | ||
| 345 | data.enter_barrier.reset(); | ||
| 346 | data.exit_barrier.reset(); | ||
| 347 | data.initialized = false; | ||
| 348 | MicroProfileOnThreadExit(); | ||
| 349 | }); | ||
| 350 | |||
| 346 | /// Running | 351 | /// Running |
| 347 | while (running_mode) { | 352 | while (running_mode) { |
| 348 | data.is_running = false; | 353 | data.is_running = false; |
| @@ -351,8 +356,13 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 351 | system.GPU().ObtainContext(); | 356 | system.GPU().ObtainContext(); |
| 352 | sc_sync_first_use = false; | 357 | sc_sync_first_use = false; |
| 353 | } | 358 | } |
| 354 | auto& scheduler = system.Kernel().CurrentScheduler(); | 359 | |
| 355 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 360 | // Abort if emulation was killed before the session really starts |
| 361 | if (!system.IsPoweredOn()) { | ||
| 362 | return; | ||
| 363 | } | ||
| 364 | |||
| 365 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | ||
| 356 | data.is_running = true; | 366 | data.is_running = true; |
| 357 | Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); | 367 | Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); |
| 358 | data.is_running = false; | 368 | data.is_running = false; |
| @@ -360,11 +370,6 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 360 | data.exit_barrier->Wait(); | 370 | data.exit_barrier->Wait(); |
| 361 | data.is_paused = false; | 371 | data.is_paused = false; |
| 362 | } | 372 | } |
| 363 | /// Time to cleanup | ||
| 364 | data.host_context->Exit(); | ||
| 365 | data.enter_barrier.reset(); | ||
| 366 | data.exit_barrier.reset(); | ||
| 367 | data.initialized = false; | ||
| 368 | } | 373 | } |
| 369 | 374 | ||
| 370 | } // namespace Core | 375 | } // namespace Core |