summaryrefslogtreecommitdiffstats
path: root/src/core/cpu_manager.cpp
diff options
context:
space:
mode:
authorFernando Sahmkow <fsahmkow27@gmail.com>2020-02-25 03:04:12 +0100
committerFernando Sahmkow <fsahmkow27@gmail.com>2020-06-27 17:35:06 +0200
commite31425df3877636c098ec7426ebd2067920715cb (patch)
tree5c0fc518a4ebb8413c491b43a9fdd99450c7bd80 /src/core/cpu_manager.cpp
parentMerge pull request #3396 from FernandoS27/prometheus-1 (diff)
downloadyuzu-e31425df3877636c098ec7426ebd2067920715cb.tar
yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.gz
yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.bz2
yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.lz
yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.xz
yuzu-e31425df3877636c098ec7426ebd2067920715cb.tar.zst
yuzu-e31425df3877636c098ec7426ebd2067920715cb.zip
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/fiber.h"
+#include "common/thread.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
-#include "core/core_manager.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/physical_core.h"
+#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/thread.h"
namespace Core {
CpuManager::CpuManager(System& system) : system{system} {}
CpuManager::~CpuManager() = default;
+void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
+ cpu_manager.RunThread(core);
+}
+
void CpuManager::Initialize() {
- for (std::size_t index = 0; index < core_managers.size(); ++index) {
- core_managers[index] = std::make_unique<CoreManager>(system, index);
+ running_mode = true;
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+ core_data[core].host_thread =
+ std::make_unique<std::thread>(ThreadStart, std::ref(*this), core);
}
}
void CpuManager::Shutdown() {
- for (auto& cpu_core : core_managers) {
- cpu_core.reset();
+ running_mode = false;
+ Pause(false);
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+ core_data[core].host_thread->join();
}
}
-CoreManager& CpuManager::GetCoreManager(std::size_t index) {
- return *core_managers.at(index);
+void CpuManager::GuestThreadFunction(void* cpu_manager_) {
+ CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
+ cpu_manager->RunGuestThread();
}
-const CoreManager& CpuManager::GetCoreManager(std::size_t index) const {
- return *core_managers.at(index);
+void CpuManager::IdleThreadFunction(void* cpu_manager_) {
+ CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
+ cpu_manager->RunIdleThread();
}
-CoreManager& CpuManager::GetCurrentCoreManager() {
- // Otherwise, use single-threaded mode active_core variable
- return *core_managers[active_core];
+void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
+ CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
+ cpu_manager->RunSuspendThread();
}
-const CoreManager& CpuManager::GetCurrentCoreManager() const {
- // Otherwise, use single-threaded mode active_core variable
- return *core_managers[active_core];
+std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
+ return std::function<void(void*)>(GuestThreadFunction);
}
-void CpuManager::RunLoop(bool tight_loop) {
- if (GDBStub::IsServerEnabled()) {
- GDBStub::HandlePacket();
-
- // If the loop is halted and we want to step, use a tiny (1) number of instructions to
- // execute. Otherwise, get out of the loop function.
- if (GDBStub::GetCpuHaltFlag()) {
- if (GDBStub::GetCpuStepFlag()) {
- tight_loop = false;
- } else {
- return;
- }
- }
+std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
+ return std::function<void(void*)>(IdleThreadFunction);
+}
+
+std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
+ return std::function<void(void*)>(SuspendThreadFunction);
+}
+
+void* CpuManager::GetStartFuncParamater() {
+ return static_cast<void*>(this);
+}
+
+void CpuManager::RunGuestThread() {
+ auto& kernel = system.Kernel();
+ {
+ auto& sched = kernel.CurrentScheduler();
+ sched.OnThreadStart();
+ }
+ while (true) {
+ auto& physical_core = kernel.CurrentPhysicalCore();
+ LOG_CRITICAL(Core_ARM, "Running Guest Thread");
+ physical_core.Idle();
+ LOG_CRITICAL(Core_ARM, "Leaving Guest Thread");
+ // physical_core.Run();
+ auto& scheduler = physical_core.Scheduler();
+ scheduler.TryDoContextSwitch();
}
+}
- auto& core_timing = system.CoreTiming();
- core_timing.ResetRun();
- bool keep_running{};
- do {
- keep_running = false;
- for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
- core_timing.SwitchContext(active_core);
- if (core_timing.CanCurrentContextRun()) {
- core_managers[active_core]->RunLoop(tight_loop);
+void CpuManager::RunIdleThread() {
+ auto& kernel = system.Kernel();
+ while (true) {
+ auto& physical_core = kernel.CurrentPhysicalCore();
+ LOG_CRITICAL(Core_ARM, "Running Idle Thread");
+ physical_core.Idle();
+ auto& scheduler = physical_core.Scheduler();
+ scheduler.TryDoContextSwitch();
+ }
+}
+
+void CpuManager::RunSuspendThread() {
+ LOG_CRITICAL(Core_ARM, "Suspending Thread Entered");
+ auto& kernel = system.Kernel();
+ {
+ auto& sched = kernel.CurrentScheduler();
+ sched.OnThreadStart();
+ }
+ while (true) {
+ auto core = kernel.GetCurrentHostThreadID();
+ auto& scheduler = kernel.CurrentScheduler();
+ Kernel::Thread* current_thread = scheduler.GetCurrentThread();
+ LOG_CRITICAL(Core_ARM, "Suspending Core {}", core);
+ Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
+ LOG_CRITICAL(Core_ARM, "Unsuspending Core {}", core);
+ ASSERT(scheduler.ContextSwitchPending());
+ ASSERT(core == kernel.GetCurrentHostThreadID());
+ scheduler.TryDoContextSwitch();
+ }
+}
+
+void CpuManager::Pause(bool paused) {
+ if (!paused) {
+ bool all_not_barrier = false;
+ while (!all_not_barrier) {
+ all_not_barrier = true;
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+ all_not_barrier &=
+ !core_data[core].is_running.load() && core_data[core].initialized.load();
}
- keep_running |= core_timing.CanCurrentContextRun();
}
- } while (keep_running);
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+ core_data[core].enter_barrier->Set();
+ }
+ if (paused_state.load()) {
+ bool all_barrier = false;
+ while (!all_barrier) {
+ all_barrier = true;
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+ all_barrier &=
+ core_data[core].is_paused.load() && core_data[core].initialized.load();
+ }
+ }
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+ core_data[core].exit_barrier->Set();
+ }
+ }
+ } else {
+ /// Wait until all cores are paused.
+ bool all_barrier = false;
+ while (!all_barrier) {
+ all_barrier = true;
+ for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+ all_barrier &=
+ core_data[core].is_paused.load() && core_data[core].initialized.load();
+ }
+ }
+ /// Don't release the barrier
+ }
+ paused_state = paused;
+}
- if (GDBStub::IsServerEnabled()) {
- GDBStub::SetCpuStepFlag(false);
+void CpuManager::RunThread(std::size_t core) {
+ /// Initialization
+ system.RegisterCoreThread(core);
+ std::string name = "yuzu:CoreHostThread_" + std::to_string(core);
+ Common::SetCurrentThreadName(name.c_str());
+ auto& data = core_data[core];
+ data.enter_barrier = std::make_unique<Common::Event>();
+ data.exit_barrier = std::make_unique<Common::Event>();
+ data.host_context = Common::Fiber::ThreadToFiber();
+ data.is_running = false;
+ data.initialized = true;
+ /// Running
+ while (running_mode) {
+ data.is_running = false;
+ data.enter_barrier->Wait();
+ auto& scheduler = system.Kernel().CurrentScheduler();
+ Kernel::Thread* current_thread = scheduler.GetCurrentThread();
+ data.is_running = true;
+ Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext());
+ data.is_running = false;
+ data.is_paused = true;
+ data.exit_barrier->Wait();
+ data.is_paused = false;
}
+ /// Time to cleanup
+ data.host_context->Exit();
+ data.enter_barrier.reset();
+ data.exit_barrier.reset();
+ data.initialized = false;
}
} // namespace Core