summaryrefslogtreecommitdiff
path: root/src/core/cpu_manager.cpp
diff options
context:
space:
mode:
authorGravatar Liam2022-07-05 23:27:25 -0400
committerGravatar Liam2022-07-14 22:47:18 -0400
commit21945ae127480c8332c1110ceada2df4a42a5848 (patch)
treea385c64a14b0d8e8dd71410eaa47575462f8f368 /src/core/cpu_manager.cpp
parentkernel: use KScheduler from mesosphere (diff)
downloadyuzu-21945ae127480c8332c1110ceada2df4a42a5848.tar.gz
yuzu-21945ae127480c8332c1110ceada2df4a42a5848.tar.xz
yuzu-21945ae127480c8332c1110ceada2df4a42a5848.zip
kernel: fix issues with single core mode
Diffstat (limited to 'src/core/cpu_manager.cpp')
-rw-r--r--src/core/cpu_manager.cpp152
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
45void CpuManager::GuestActivateFunction() { 45void 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
53void CpuManager::GuestThreadFunction() { 53void 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
65void 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
78void CpuManager::HandleInterrupt() { 65void 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
89void CpuManager::MultiCoreGuestActivate() { 76void 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
98void CpuManager::MultiCoreRunGuestThread() { 92void 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
107void CpuManager::MultiCoreRunGuestLoop() { 110///////////////////////////////////////////////////////////////////////////////
111/// SingleCore ///
112///////////////////////////////////////////////////////////////////////////////
113
114void 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/////////////////////////////////////////////////////////////////////////////// 134void 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
125void CpuManager::SingleCoreGuestActivate() {} 146void 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
127void CpuManager::SingleCoreRunGuestThread() {} 165 auto& next_scheduler = kernel.Scheduler(current_core);
128 166
129void 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
131void 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
183void 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
133void CpuManager::ShutdownThread() { 192void 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