diff options
Diffstat (limited to 'src/core/cpu_manager.cpp')
| -rw-r--r-- | src/core/cpu_manager.cpp | 152 |
1 files changed, 101 insertions, 51 deletions
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 428194129..838d6be21 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -42,19 +42,19 @@ void CpuManager::Shutdown() { | |||
| 42 | } | 42 | } |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void CpuManager::GuestActivateFunction() { | 45 | void CpuManager::GuestThreadFunction() { |
| 46 | if (is_multicore) { | 46 | if (is_multicore) { |
| 47 | MultiCoreGuestActivate(); | 47 | MultiCoreRunGuestThread(); |
| 48 | } else { | 48 | } else { |
| 49 | SingleCoreGuestActivate(); | 49 | SingleCoreRunGuestThread(); |
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | void CpuManager::GuestThreadFunction() { | 53 | void CpuManager::IdleThreadFunction() { |
| 54 | if (is_multicore) { | 54 | if (is_multicore) { |
| 55 | MultiCoreRunGuestThread(); | 55 | MultiCoreRunIdleThread(); |
| 56 | } else { | 56 | } else { |
| 57 | SingleCoreRunGuestThread(); | 57 | SingleCoreRunIdleThread(); |
| 58 | } | 58 | } |
| 59 | } | 59 | } |
| 60 | 60 | ||
| @@ -62,19 +62,6 @@ void CpuManager::ShutdownThreadFunction() { | |||
| 62 | ShutdownThread(); | 62 | ShutdownThread(); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | void CpuManager::WaitForAndHandleInterrupt() { | ||
| 66 | auto& kernel = system.Kernel(); | ||
| 67 | auto& physical_core = kernel.CurrentPhysicalCore(); | ||
| 68 | |||
| 69 | ASSERT(Kernel::GetCurrentThread(kernel).GetDisableDispatchCount() == 1); | ||
| 70 | |||
| 71 | if (!physical_core.IsInterrupted()) { | ||
| 72 | physical_core.Idle(); | ||
| 73 | } | ||
| 74 | |||
| 75 | HandleInterrupt(); | ||
| 76 | } | ||
| 77 | |||
| 78 | void CpuManager::HandleInterrupt() { | 65 | void CpuManager::HandleInterrupt() { |
| 79 | auto& kernel = system.Kernel(); | 66 | auto& kernel = system.Kernel(); |
| 80 | auto core_index = kernel.CurrentPhysicalCoreIndex(); | 67 | auto core_index = kernel.CurrentPhysicalCoreIndex(); |
| @@ -86,49 +73,121 @@ void CpuManager::HandleInterrupt() { | |||
| 86 | /// MultiCore /// | 73 | /// MultiCore /// |
| 87 | /////////////////////////////////////////////////////////////////////////////// | 74 | /////////////////////////////////////////////////////////////////////////////// |
| 88 | 75 | ||
| 89 | void CpuManager::MultiCoreGuestActivate() { | 76 | void CpuManager::MultiCoreRunGuestThread() { |
| 90 | // Similar to the HorizonKernelMain callback in HOS | 77 | // Similar to UserModeThreadStarter in HOS |
| 91 | auto& kernel = system.Kernel(); | 78 | auto& kernel = system.Kernel(); |
| 92 | auto* scheduler = kernel.CurrentScheduler(); | 79 | kernel.CurrentScheduler()->OnThreadStart(); |
| 93 | 80 | ||
| 94 | scheduler->Activate(); | 81 | while (true) { |
| 95 | UNREACHABLE(); | 82 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 83 | while (!physical_core->IsInterrupted()) { | ||
| 84 | physical_core->Run(); | ||
| 85 | physical_core = &kernel.CurrentPhysicalCore(); | ||
| 86 | } | ||
| 87 | |||
| 88 | HandleInterrupt(); | ||
| 89 | } | ||
| 96 | } | 90 | } |
| 97 | 91 | ||
| 98 | void CpuManager::MultiCoreRunGuestThread() { | 92 | void CpuManager::MultiCoreRunIdleThread() { |
| 99 | // Similar to UserModeThreadStarter in HOS | 93 | // Not accurate to HOS. Remove this entire method when singlecore is removed. |
| 94 | // See notes in KScheduler::ScheduleImpl for more information about why this | ||
| 95 | // is inaccurate. | ||
| 96 | |||
| 100 | auto& kernel = system.Kernel(); | 97 | auto& kernel = system.Kernel(); |
| 101 | auto* thread = kernel.GetCurrentEmuThread(); | 98 | kernel.CurrentScheduler()->OnThreadStart(); |
| 102 | thread->EnableDispatch(); | 99 | |
| 100 | while (true) { | ||
| 101 | auto& physical_core = kernel.CurrentPhysicalCore(); | ||
| 102 | if (!physical_core.IsInterrupted()) { | ||
| 103 | physical_core.Idle(); | ||
| 104 | } | ||
| 103 | 105 | ||
| 104 | MultiCoreRunGuestLoop(); | 106 | HandleInterrupt(); |
| 107 | } | ||
| 105 | } | 108 | } |
| 106 | 109 | ||
| 107 | void CpuManager::MultiCoreRunGuestLoop() { | 110 | /////////////////////////////////////////////////////////////////////////////// |
| 111 | /// SingleCore /// | ||
| 112 | /////////////////////////////////////////////////////////////////////////////// | ||
| 113 | |||
| 114 | void CpuManager::SingleCoreRunGuestThread() { | ||
| 108 | auto& kernel = system.Kernel(); | 115 | auto& kernel = system.Kernel(); |
| 116 | kernel.CurrentScheduler()->OnThreadStart(); | ||
| 109 | 117 | ||
| 110 | while (true) { | 118 | while (true) { |
| 111 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 119 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 112 | while (!physical_core->IsInterrupted()) { | 120 | if (!physical_core->IsInterrupted()) { |
| 113 | physical_core->Run(); | 121 | physical_core->Run(); |
| 114 | physical_core = &kernel.CurrentPhysicalCore(); | 122 | physical_core = &kernel.CurrentPhysicalCore(); |
| 115 | } | 123 | } |
| 116 | 124 | ||
| 125 | kernel.SetIsPhantomModeForSingleCore(true); | ||
| 126 | system.CoreTiming().Advance(); | ||
| 127 | kernel.SetIsPhantomModeForSingleCore(false); | ||
| 128 | |||
| 129 | PreemptSingleCore(); | ||
| 117 | HandleInterrupt(); | 130 | HandleInterrupt(); |
| 118 | } | 131 | } |
| 119 | } | 132 | } |
| 120 | 133 | ||
| 121 | /////////////////////////////////////////////////////////////////////////////// | 134 | void CpuManager::SingleCoreRunIdleThread() { |
| 122 | /// SingleCore /// | 135 | auto& kernel = system.Kernel(); |
| 123 | /////////////////////////////////////////////////////////////////////////////// | 136 | kernel.CurrentScheduler()->OnThreadStart(); |
| 137 | |||
| 138 | while (true) { | ||
| 139 | PreemptSingleCore(false); | ||
| 140 | system.CoreTiming().AddTicks(1000U); | ||
| 141 | idle_count++; | ||
| 142 | HandleInterrupt(); | ||
| 143 | } | ||
| 144 | } | ||
| 124 | 145 | ||
| 125 | void CpuManager::SingleCoreGuestActivate() {} | 146 | void CpuManager::PreemptSingleCore(bool from_running_environment) { |
| 147 | { | ||
| 148 | auto& kernel = system.Kernel(); | ||
| 149 | auto& scheduler = kernel.Scheduler(current_core); | ||
| 150 | |||
| 151 | Kernel::KThread* current_thread = scheduler.GetSchedulerCurrentThread(); | ||
| 152 | if (idle_count >= 4 || from_running_environment) { | ||
| 153 | if (!from_running_environment) { | ||
| 154 | system.CoreTiming().Idle(); | ||
| 155 | idle_count = 0; | ||
| 156 | } | ||
| 157 | kernel.SetIsPhantomModeForSingleCore(true); | ||
| 158 | system.CoreTiming().Advance(); | ||
| 159 | kernel.SetIsPhantomModeForSingleCore(false); | ||
| 160 | } | ||
| 161 | current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); | ||
| 162 | system.CoreTiming().ResetTicks(); | ||
| 163 | scheduler.Unload(scheduler.GetSchedulerCurrentThread()); | ||
| 126 | 164 | ||
| 127 | void CpuManager::SingleCoreRunGuestThread() {} | 165 | auto& next_scheduler = kernel.Scheduler(current_core); |
| 128 | 166 | ||
| 129 | void CpuManager::SingleCoreRunGuestLoop() {} | 167 | // Disable dispatch. We're about to preempt this thread. |
| 168 | Kernel::KScopedDisableDispatch dd{kernel}; | ||
| 169 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.GetSwitchFiber()); | ||
| 170 | } | ||
| 130 | 171 | ||
| 131 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) {} | 172 | // We've now been scheduled again, and we may have exchanged schedulers. |
| 173 | // Reload the scheduler in case it's different. | ||
| 174 | { | ||
| 175 | auto& scheduler = system.Kernel().Scheduler(current_core); | ||
| 176 | scheduler.Reload(scheduler.GetSchedulerCurrentThread()); | ||
| 177 | if (!scheduler.IsIdle()) { | ||
| 178 | idle_count = 0; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | void CpuManager::GuestActivate() { | ||
| 184 | // Similar to the HorizonKernelMain callback in HOS | ||
| 185 | auto& kernel = system.Kernel(); | ||
| 186 | auto* scheduler = kernel.CurrentScheduler(); | ||
| 187 | |||
| 188 | scheduler->Activate(); | ||
| 189 | UNREACHABLE(); | ||
| 190 | } | ||
| 132 | 191 | ||
| 133 | void CpuManager::ShutdownThread() { | 192 | void CpuManager::ShutdownThread() { |
| 134 | auto& kernel = system.Kernel(); | 193 | auto& kernel = system.Kernel(); |
| @@ -168,20 +227,11 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 168 | } | 227 | } |
| 169 | 228 | ||
| 170 | auto& kernel = system.Kernel(); | 229 | auto& kernel = system.Kernel(); |
| 230 | auto& scheduler = *kernel.CurrentScheduler(); | ||
| 231 | auto* thread = scheduler.GetSchedulerCurrentThread(); | ||
| 232 | Kernel::SetCurrentThread(kernel, thread); | ||
| 171 | 233 | ||
| 172 | auto* main_thread = Kernel::KThread::Create(kernel); | 234 | Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext()); |
| 173 | main_thread->SetName(fmt::format("MainThread:{}", core)); | ||
| 174 | ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, static_cast<s32>(core)) | ||
| 175 | .IsSuccess()); | ||
| 176 | |||
| 177 | auto* idle_thread = Kernel::KThread::Create(kernel); | ||
| 178 | ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast<s32>(core)) | ||
| 179 | .IsSuccess()); | ||
| 180 | |||
| 181 | kernel.SetCurrentEmuThread(main_thread); | ||
| 182 | kernel.CurrentScheduler()->Initialize(idle_thread); | ||
| 183 | |||
| 184 | Common::Fiber::YieldTo(data.host_context, *main_thread->GetHostContext()); | ||
| 185 | } | 235 | } |
| 186 | 236 | ||
| 187 | } // namespace Core | 237 | } // namespace Core |