summaryrefslogtreecommitdiff
path: root/src/core/cpu_manager.cpp
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-24 22:04:12 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:35:06 -0400
commite31425df3877636c098ec7426ebd2067920715cb (patch)
tree5c0fc518a4ebb8413c491b43a9fdd99450c7bd80 /src/core/cpu_manager.cpp
parentMerge pull request #3396 from FernandoS27/prometheus-1 (diff)
downloadyuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.gz
yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.xz
yuzu-e31425df3877636c098ec7426ebd2067920715cb.zip
General: Recover Prometheus project from harddrive failure
This commit: Implements CPU Interrupts, Replaces Cycle Timing for Host Timing, Reworks the Kernel's Scheduler, Introduce Idle State and Suspended State, Recreates the bootmanager, Initializes Multicore system.
Diffstat (limited to 'src/core/cpu_manager.cpp')
-rw-r--r--src/core/cpu_manager.cpp194
1 files changed, 153 insertions, 41 deletions
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 70ddbdcca..494850992 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -2,80 +2,192 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/fiber.h"
6#include "common/thread.h"
5#include "core/arm/exclusive_monitor.h" 7#include "core/arm/exclusive_monitor.h"
6#include "core/core.h" 8#include "core/core.h"
7#include "core/core_manager.h"
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/cpu_manager.h" 10#include "core/cpu_manager.h"
10#include "core/gdbstub/gdbstub.h" 11#include "core/gdbstub/gdbstub.h"
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/physical_core.h"
14#include "core/hle/kernel/scheduler.h"
15#include "core/hle/kernel/thread.h"
11 16
12namespace Core { 17namespace Core {
13 18
14CpuManager::CpuManager(System& system) : system{system} {} 19CpuManager::CpuManager(System& system) : system{system} {}
15CpuManager::~CpuManager() = default; 20CpuManager::~CpuManager() = default;
16 21
22void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
23 cpu_manager.RunThread(core);
24}
25
17void CpuManager::Initialize() { 26void CpuManager::Initialize() {
18 for (std::size_t index = 0; index < core_managers.size(); ++index) { 27 running_mode = true;
19 core_managers[index] = std::make_unique<CoreManager>(system, index); 28 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
29 core_data[core].host_thread =
30 std::make_unique<std::thread>(ThreadStart, std::ref(*this), core);
20 } 31 }
21} 32}
22 33
23void CpuManager::Shutdown() { 34void CpuManager::Shutdown() {
24 for (auto& cpu_core : core_managers) { 35 running_mode = false;
25 cpu_core.reset(); 36 Pause(false);
37 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
38 core_data[core].host_thread->join();
26 } 39 }
27} 40}
28 41
29CoreManager& CpuManager::GetCoreManager(std::size_t index) { 42void CpuManager::GuestThreadFunction(void* cpu_manager_) {
30 return *core_managers.at(index); 43 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
44 cpu_manager->RunGuestThread();
31} 45}
32 46
33const CoreManager& CpuManager::GetCoreManager(std::size_t index) const { 47void CpuManager::IdleThreadFunction(void* cpu_manager_) {
34 return *core_managers.at(index); 48 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
49 cpu_manager->RunIdleThread();
35} 50}
36 51
37CoreManager& CpuManager::GetCurrentCoreManager() { 52void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
38 // Otherwise, use single-threaded mode active_core variable 53 CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
39 return *core_managers[active_core]; 54 cpu_manager->RunSuspendThread();
40} 55}
41 56
42const CoreManager& CpuManager::GetCurrentCoreManager() const { 57std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
43 // Otherwise, use single-threaded mode active_core variable 58 return std::function<void(void*)>(GuestThreadFunction);
44 return *core_managers[active_core];
45} 59}
46 60
47void CpuManager::RunLoop(bool tight_loop) { 61std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
48 if (GDBStub::IsServerEnabled()) { 62 return std::function<void(void*)>(IdleThreadFunction);
49 GDBStub::HandlePacket(); 63}
50 64
51 // If the loop is halted and we want to step, use a tiny (1) number of instructions to 65std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
52 // execute. Otherwise, get out of the loop function. 66 return std::function<void(void*)>(SuspendThreadFunction);
53 if (GDBStub::GetCpuHaltFlag()) { 67}
54 if (GDBStub::GetCpuStepFlag()) { 68
55 tight_loop = false; 69void* CpuManager::GetStartFuncParamater() {
56 } else { 70 return static_cast<void*>(this);
57 return; 71}
58 } 72
59 } 73void CpuManager::RunGuestThread() {
74 auto& kernel = system.Kernel();
75 {
76 auto& sched = kernel.CurrentScheduler();
77 sched.OnThreadStart();
78 }
79 while (true) {
80 auto& physical_core = kernel.CurrentPhysicalCore();
81 LOG_CRITICAL(Core_ARM, "Running Guest Thread");
82 physical_core.Idle();
83 LOG_CRITICAL(Core_ARM, "Leaving Guest Thread");
84 // physical_core.Run();
85 auto& scheduler = physical_core.Scheduler();
86 scheduler.TryDoContextSwitch();
60 } 87 }
88}
61 89
62 auto& core_timing = system.CoreTiming(); 90void CpuManager::RunIdleThread() {
63 core_timing.ResetRun(); 91 auto& kernel = system.Kernel();
64 bool keep_running{}; 92 while (true) {
65 do { 93 auto& physical_core = kernel.CurrentPhysicalCore();
66 keep_running = false; 94 LOG_CRITICAL(Core_ARM, "Running Idle Thread");
67 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { 95 physical_core.Idle();
68 core_timing.SwitchContext(active_core); 96 auto& scheduler = physical_core.Scheduler();
69 if (core_timing.CanCurrentContextRun()) { 97 scheduler.TryDoContextSwitch();
70 core_managers[active_core]->RunLoop(tight_loop); 98 }
99}
100
101void CpuManager::RunSuspendThread() {
102 LOG_CRITICAL(Core_ARM, "Suspending Thread Entered");
103 auto& kernel = system.Kernel();
104 {
105 auto& sched = kernel.CurrentScheduler();
106 sched.OnThreadStart();
107 }
108 while (true) {
109 auto core = kernel.GetCurrentHostThreadID();
110 auto& scheduler = kernel.CurrentScheduler();
111 Kernel::Thread* current_thread = scheduler.GetCurrentThread();
112 LOG_CRITICAL(Core_ARM, "Suspending Core {}", core);
113 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
114 LOG_CRITICAL(Core_ARM, "Unsuspending Core {}", core);
115 ASSERT(scheduler.ContextSwitchPending());
116 ASSERT(core == kernel.GetCurrentHostThreadID());
117 scheduler.TryDoContextSwitch();
118 }
119}
120
121void CpuManager::Pause(bool paused) {
122 if (!paused) {
123 bool all_not_barrier = false;
124 while (!all_not_barrier) {
125 all_not_barrier = true;
126 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
127 all_not_barrier &=
128 !core_data[core].is_running.load() && core_data[core].initialized.load();
71 } 129 }
72 keep_running |= core_timing.CanCurrentContextRun();
73 } 130 }
74 } while (keep_running); 131 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
132 core_data[core].enter_barrier->Set();
133 }
134 if (paused_state.load()) {
135 bool all_barrier = false;
136 while (!all_barrier) {
137 all_barrier = true;
138 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
139 all_barrier &=
140 core_data[core].is_paused.load() && core_data[core].initialized.load();
141 }
142 }
143 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
144 core_data[core].exit_barrier->Set();
145 }
146 }
147 } else {
148 /// Wait until all cores are paused.
149 bool all_barrier = false;
150 while (!all_barrier) {
151 all_barrier = true;
152 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
153 all_barrier &=
154 core_data[core].is_paused.load() && core_data[core].initialized.load();
155 }
156 }
157 /// Don't release the barrier
158 }
159 paused_state = paused;
160}
75 161
76 if (GDBStub::IsServerEnabled()) { 162void CpuManager::RunThread(std::size_t core) {
77 GDBStub::SetCpuStepFlag(false); 163 /// Initialization
164 system.RegisterCoreThread(core);
165 std::string name = "yuzu:CoreHostThread_" + std::to_string(core);
166 Common::SetCurrentThreadName(name.c_str());
167 auto& data = core_data[core];
168 data.enter_barrier = std::make_unique<Common::Event>();
169 data.exit_barrier = std::make_unique<Common::Event>();
170 data.host_context = Common::Fiber::ThreadToFiber();
171 data.is_running = false;
172 data.initialized = true;
173 /// Running
174 while (running_mode) {
175 data.is_running = false;
176 data.enter_barrier->Wait();
177 auto& scheduler = system.Kernel().CurrentScheduler();
178 Kernel::Thread* current_thread = scheduler.GetCurrentThread();
179 data.is_running = true;
180 Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext());
181 data.is_running = false;
182 data.is_paused = true;
183 data.exit_barrier->Wait();
184 data.is_paused = false;
78 } 185 }
186 /// Time to cleanup
187 data.host_context->Exit();
188 data.enter_barrier.reset();
189 data.exit_barrier.reset();
190 data.initialized = false;
79} 191}
80 192
81} // namespace Core 193} // namespace Core