summaryrefslogtreecommitdiff
path: root/src/core/cpu_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/cpu_manager.cpp')
-rw-r--r--src/core/cpu_manager.cpp186
1 files changed, 160 insertions, 26 deletions
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 9a261968a..e72f89808 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -26,9 +26,13 @@ void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
26 26
27void CpuManager::Initialize() { 27void CpuManager::Initialize() {
28 running_mode = true; 28 running_mode = true;
29 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 29 if (is_multicore) {
30 core_data[core].host_thread = 30 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
31 std::make_unique<std::thread>(ThreadStart, std::ref(*this), core); 31 core_data[core].host_thread =
32 std::make_unique<std::thread>(ThreadStart, std::ref(*this), core);
33 }
34 } else {
35 core_data[0].host_thread = std::make_unique<std::thread>(ThreadStart, std::ref(*this), 0);
32 } 36 }
33} 37}
34 38
@@ -41,52 +45,72 @@ void CpuManager::Shutdown() {
41 } 45 }
42} 46}
43 47
48std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
49 return std::function<void(void*)>(GuestThreadFunction);
50}
51
52std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
53 return std::function<void(void*)>(IdleThreadFunction);
54}
55
56std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
57 return std::function<void(void*)>(SuspendThreadFunction);
58}
59
44void CpuManager::GuestThreadFunction(void* cpu_manager_) { 60void CpuManager::GuestThreadFunction(void* cpu_manager_) {
45 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 61 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
46 cpu_manager->RunGuestThread(); 62 if (cpu_manager->is_multicore) {
63 cpu_manager->MultiCoreRunGuestThread();
64 } else {
65 cpu_manager->SingleCoreRunGuestThread();
66 }
47} 67}
48 68
49void CpuManager::GuestRewindFunction(void* cpu_manager_) { 69void CpuManager::GuestRewindFunction(void* cpu_manager_) {
50 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 70 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
51 cpu_manager->RunGuestLoop(); 71 if (cpu_manager->is_multicore) {
72 cpu_manager->MultiCoreRunGuestLoop();
73 } else {
74 cpu_manager->SingleCoreRunGuestLoop();
75 }
52} 76}
53 77
54void CpuManager::IdleThreadFunction(void* cpu_manager_) { 78void CpuManager::IdleThreadFunction(void* cpu_manager_) {
55 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 79 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
56 cpu_manager->RunIdleThread(); 80 if (cpu_manager->is_multicore) {
81 cpu_manager->MultiCoreRunIdleThread();
82 } else {
83 cpu_manager->SingleCoreRunIdleThread();
84 }
57} 85}
58 86
59void CpuManager::SuspendThreadFunction(void* cpu_manager_) { 87void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
60 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); 88 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
61 cpu_manager->RunSuspendThread(); 89 if (cpu_manager->is_multicore) {
62} 90 cpu_manager->MultiCoreRunSuspendThread();
63 91 } else {
64std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { 92 cpu_manager->SingleCoreRunSuspendThread();
65 return std::function<void(void*)>(GuestThreadFunction); 93 }
66}
67
68std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
69 return std::function<void(void*)>(IdleThreadFunction);
70}
71
72std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
73 return std::function<void(void*)>(SuspendThreadFunction);
74} 94}
75 95
76void* CpuManager::GetStartFuncParamater() { 96void* CpuManager::GetStartFuncParamater() {
77 return static_cast<void*>(this); 97 return static_cast<void*>(this);
78} 98}
79 99
80void CpuManager::RunGuestThread() { 100///////////////////////////////////////////////////////////////////////////////
101/// MultiCore ///
102///////////////////////////////////////////////////////////////////////////////
103
104void CpuManager::MultiCoreRunGuestThread() {
81 auto& kernel = system.Kernel(); 105 auto& kernel = system.Kernel();
82 { 106 {
83 auto& sched = kernel.CurrentScheduler(); 107 auto& sched = kernel.CurrentScheduler();
84 sched.OnThreadStart(); 108 sched.OnThreadStart();
85 } 109 }
86 RunGuestLoop(); 110 MultiCoreRunGuestLoop();
87} 111}
88 112
89void CpuManager::RunGuestLoop() { 113void CpuManager::MultiCoreRunGuestLoop() {
90 auto& kernel = system.Kernel(); 114 auto& kernel = system.Kernel();
91 auto* thread = kernel.CurrentScheduler().GetCurrentThread(); 115 auto* thread = kernel.CurrentScheduler().GetCurrentThread();
92 auto host_context = thread->GetHostContext(); 116 auto host_context = thread->GetHostContext();
@@ -103,7 +127,7 @@ void CpuManager::RunGuestLoop() {
103 } 127 }
104} 128}
105 129
106void CpuManager::RunIdleThread() { 130void CpuManager::MultiCoreRunIdleThread() {
107 auto& kernel = system.Kernel(); 131 auto& kernel = system.Kernel();
108 while (true) { 132 while (true) {
109 auto& physical_core = kernel.CurrentPhysicalCore(); 133 auto& physical_core = kernel.CurrentPhysicalCore();
@@ -113,7 +137,7 @@ void CpuManager::RunIdleThread() {
113 } 137 }
114} 138}
115 139
116void CpuManager::RunSuspendThread() { 140void CpuManager::MultiCoreRunSuspendThread() {
117 auto& kernel = system.Kernel(); 141 auto& kernel = system.Kernel();
118 { 142 {
119 auto& sched = kernel.CurrentScheduler(); 143 auto& sched = kernel.CurrentScheduler();
@@ -130,7 +154,7 @@ void CpuManager::RunSuspendThread() {
130 } 154 }
131} 155}
132 156
133void CpuManager::Pause(bool paused) { 157void CpuManager::MultiCorePause(bool paused) {
134 if (!paused) { 158 if (!paused) {
135 bool all_not_barrier = false; 159 bool all_not_barrier = false;
136 while (!all_not_barrier) { 160 while (!all_not_barrier) {
@@ -171,10 +195,120 @@ void CpuManager::Pause(bool paused) {
171 paused_state = paused; 195 paused_state = paused;
172} 196}
173 197
198///////////////////////////////////////////////////////////////////////////////
199/// SingleCore ///
200///////////////////////////////////////////////////////////////////////////////
201
202void CpuManager::SingleCoreRunGuestThread() {
203 auto& kernel = system.Kernel();
204 {
205 auto& sched = kernel.CurrentScheduler();
206 sched.OnThreadStart();
207 }
208 SingleCoreRunGuestLoop();
209}
210
211void CpuManager::SingleCoreRunGuestLoop() {
212 auto& kernel = system.Kernel();
213 auto* thread = kernel.CurrentScheduler().GetCurrentThread();
214 auto host_context = thread->GetHostContext();
215 host_context->SetRewindPoint(std::function<void(void*)>(GuestRewindFunction), this);
216 host_context.reset();
217 while (true) {
218 auto& physical_core = kernel.CurrentPhysicalCore();
219 while (!physical_core.IsInterrupted()) {
220 physical_core.Run();
221 preemption_count++;
222 if (preemption_count % max_cycle_runs == 0) {
223 break;
224 }
225 }
226 physical_core.ClearExclusive();
227 PreemptSingleCore();
228 auto& scheduler = physical_core.Scheduler();
229 scheduler.TryDoContextSwitch();
230 }
231}
232
233void CpuManager::SingleCoreRunIdleThread() {
234 auto& kernel = system.Kernel();
235 while (true) {
236 auto& physical_core = kernel.CurrentPhysicalCore();
237 PreemptSingleCore();
238 auto& scheduler = physical_core.Scheduler();
239 scheduler.TryDoContextSwitch();
240 }
241}
242
243void CpuManager::SingleCoreRunSuspendThread() {
244 auto& kernel = system.Kernel();
245 {
246 auto& sched = kernel.CurrentScheduler();
247 sched.OnThreadStart();
248 }
249 while (true) {
250 auto core = kernel.GetCurrentHostThreadID();
251 auto& scheduler = kernel.CurrentScheduler();
252 Kernel::Thread* current_thread = scheduler.GetCurrentThread();
253 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
254 ASSERT(scheduler.ContextSwitchPending());
255 ASSERT(core == kernel.GetCurrentHostThreadID());
256 scheduler.TryDoContextSwitch();
257 }
258}
259
260void CpuManager::PreemptSingleCore() {
261 preemption_count = 0;
262 std::size_t old_core = current_core;
263 current_core = (current_core + 1) % Core::Hardware::NUM_CPU_CORES;
264 auto& scheduler = system.Kernel().Scheduler(old_core);
265 Kernel::Thread* current_thread = system.Kernel().Scheduler(old_core).GetCurrentThread();
266 Kernel::Thread* next_thread = system.Kernel().Scheduler(current_core).GetCurrentThread();
267 Common::Fiber::YieldTo(current_thread->GetHostContext(), next_thread->GetHostContext());
268}
269
270void CpuManager::SingleCorePause(bool paused) {
271 if (!paused) {
272 bool all_not_barrier = false;
273 while (!all_not_barrier) {
274 all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load();
275 }
276 core_data[0].enter_barrier->Set();
277 if (paused_state.load()) {
278 bool all_barrier = false;
279 while (!all_barrier) {
280 all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
281 }
282 core_data[0].exit_barrier->Set();
283 }
284 } else {
285 /// Wait until all cores are paused.
286 bool all_barrier = false;
287 while (!all_barrier) {
288 all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
289 }
290 /// Don't release the barrier
291 }
292 paused_state = paused;
293}
294
295void CpuManager::Pause(bool paused) {
296 if (is_multicore) {
297 MultiCorePause(paused);
298 } else {
299 SingleCorePause(paused);
300 }
301}
302
174void CpuManager::RunThread(std::size_t core) { 303void CpuManager::RunThread(std::size_t core) {
175 /// Initialization 304 /// Initialization
176 system.RegisterCoreThread(core); 305 system.RegisterCoreThread(core);
177 std::string name = "yuzu:CoreHostThread_" + std::to_string(core); 306 std::string name;
307 if (is_multicore) {
308 name = "yuzu:CoreCPUThread_" + std::to_string(core);
309 } else {
310 name = "yuzu:CPUThread";
311 }
178 MicroProfileOnThreadCreate(name.c_str()); 312 MicroProfileOnThreadCreate(name.c_str());
179 Common::SetCurrentThreadName(name.c_str()); 313 Common::SetCurrentThreadName(name.c_str());
180 auto& data = core_data[core]; 314 auto& data = core_data[core];