Browse Source
Merge pull request #1777 from lioncash/core-mgr
Merge pull request #1777 from lioncash/core-mgr
core: Relocate CPU core management to its own classnce_cpp
committed by
GitHub
4 changed files with 225 additions and 97 deletions
-
2src/core/CMakeLists.txt
-
119src/core/core.cpp
-
142src/core/cpu_core_manager.cpp
-
59src/core/cpu_core_manager.h
@ -0,0 +1,142 @@ |
|||||
|
// Copyright 2018 yuzu emulator team
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "core/arm/exclusive_monitor.h"
|
||||
|
#include "core/core.h"
|
||||
|
#include "core/core_cpu.h"
|
||||
|
#include "core/cpu_core_manager.h"
|
||||
|
#include "core/gdbstub/gdbstub.h"
|
||||
|
#include "core/settings.h"
|
||||
|
|
||||
|
namespace Core { |
||||
|
namespace { |
||||
|
void RunCpuCore(const System& system, Cpu& cpu_state) { |
||||
|
while (system.IsPoweredOn()) { |
||||
|
cpu_state.RunLoop(true); |
||||
|
} |
||||
|
} |
||||
|
} // Anonymous namespace
|
||||
|
|
||||
|
CpuCoreManager::CpuCoreManager() = default; |
||||
|
CpuCoreManager::~CpuCoreManager() = default; |
||||
|
|
||||
|
void CpuCoreManager::Initialize(System& system) { |
||||
|
barrier = std::make_unique<CpuBarrier>(); |
||||
|
exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); |
||||
|
|
||||
|
for (std::size_t index = 0; index < cores.size(); ++index) { |
||||
|
cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index); |
||||
|
} |
||||
|
|
||||
|
// Create threads for CPU cores 1-3, and build thread_to_cpu map
|
||||
|
// CPU core 0 is run on the main thread
|
||||
|
thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); |
||||
|
if (!Settings::values.use_multi_core) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (std::size_t index = 0; index < core_threads.size(); ++index) { |
||||
|
core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system), |
||||
|
std::ref(*cores[index + 1])); |
||||
|
thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void CpuCoreManager::Shutdown() { |
||||
|
barrier->NotifyEnd(); |
||||
|
if (Settings::values.use_multi_core) { |
||||
|
for (auto& thread : core_threads) { |
||||
|
thread->join(); |
||||
|
thread.reset(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
thread_to_cpu.clear(); |
||||
|
for (auto& cpu_core : cores) { |
||||
|
cpu_core.reset(); |
||||
|
} |
||||
|
|
||||
|
exclusive_monitor.reset(); |
||||
|
barrier.reset(); |
||||
|
} |
||||
|
|
||||
|
Cpu& CpuCoreManager::GetCore(std::size_t index) { |
||||
|
return *cores.at(index); |
||||
|
} |
||||
|
|
||||
|
const Cpu& CpuCoreManager::GetCore(std::size_t index) const { |
||||
|
return *cores.at(index); |
||||
|
} |
||||
|
|
||||
|
ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() { |
||||
|
return *exclusive_monitor; |
||||
|
} |
||||
|
|
||||
|
const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const { |
||||
|
return *exclusive_monitor; |
||||
|
} |
||||
|
|
||||
|
Cpu& CpuCoreManager::GetCurrentCore() { |
||||
|
if (Settings::values.use_multi_core) { |
||||
|
const auto& search = thread_to_cpu.find(std::this_thread::get_id()); |
||||
|
ASSERT(search != thread_to_cpu.end()); |
||||
|
ASSERT(search->second); |
||||
|
return *search->second; |
||||
|
} |
||||
|
|
||||
|
// Otherwise, use single-threaded mode active_core variable
|
||||
|
return *cores[active_core]; |
||||
|
} |
||||
|
|
||||
|
const Cpu& CpuCoreManager::GetCurrentCore() const { |
||||
|
if (Settings::values.use_multi_core) { |
||||
|
const auto& search = thread_to_cpu.find(std::this_thread::get_id()); |
||||
|
ASSERT(search != thread_to_cpu.end()); |
||||
|
ASSERT(search->second); |
||||
|
return *search->second; |
||||
|
} |
||||
|
|
||||
|
// Otherwise, use single-threaded mode active_core variable
|
||||
|
return *cores[active_core]; |
||||
|
} |
||||
|
|
||||
|
void CpuCoreManager::RunLoop(bool tight_loop) { |
||||
|
// Update thread_to_cpu in case Core 0 is run from a different host thread
|
||||
|
thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); |
||||
|
|
||||
|
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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { |
||||
|
cores[active_core]->RunLoop(tight_loop); |
||||
|
if (Settings::values.use_multi_core) { |
||||
|
// Cores 1-3 are run on other threads in this mode
|
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (GDBStub::IsServerEnabled()) { |
||||
|
GDBStub::SetCpuStepFlag(false); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void CpuCoreManager::InvalidateAllInstructionCaches() { |
||||
|
for (auto& cpu : cores) { |
||||
|
cpu->ArmInterface().ClearInstructionCache(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace Core
|
||||
@ -0,0 +1,59 @@ |
|||||
|
// Copyright 2018 yuzu emulator team |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
#include <map> |
||||
|
#include <memory> |
||||
|
#include <thread> |
||||
|
|
||||
|
namespace Core { |
||||
|
|
||||
|
class Cpu; |
||||
|
class CpuBarrier; |
||||
|
class ExclusiveMonitor; |
||||
|
class System; |
||||
|
|
||||
|
class CpuCoreManager { |
||||
|
public: |
||||
|
CpuCoreManager(); |
||||
|
CpuCoreManager(const CpuCoreManager&) = delete; |
||||
|
CpuCoreManager(CpuCoreManager&&) = delete; |
||||
|
|
||||
|
~CpuCoreManager(); |
||||
|
|
||||
|
CpuCoreManager& operator=(const CpuCoreManager&) = delete; |
||||
|
CpuCoreManager& operator=(CpuCoreManager&&) = delete; |
||||
|
|
||||
|
void Initialize(System& system); |
||||
|
void Shutdown(); |
||||
|
|
||||
|
Cpu& GetCore(std::size_t index); |
||||
|
const Cpu& GetCore(std::size_t index) const; |
||||
|
|
||||
|
Cpu& GetCurrentCore(); |
||||
|
const Cpu& GetCurrentCore() const; |
||||
|
|
||||
|
ExclusiveMonitor& GetExclusiveMonitor(); |
||||
|
const ExclusiveMonitor& GetExclusiveMonitor() const; |
||||
|
|
||||
|
void RunLoop(bool tight_loop); |
||||
|
|
||||
|
void InvalidateAllInstructionCaches(); |
||||
|
|
||||
|
private: |
||||
|
static constexpr std::size_t NUM_CPU_CORES = 4; |
||||
|
|
||||
|
std::unique_ptr<ExclusiveMonitor> exclusive_monitor; |
||||
|
std::unique_ptr<CpuBarrier> barrier; |
||||
|
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores; |
||||
|
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads; |
||||
|
std::size_t active_core{}; ///< Active core, only used in single thread mode |
||||
|
|
||||
|
/// Map of guest threads to CPU cores |
||||
|
std::map<std::thread::id, Cpu*> thread_to_cpu; |
||||
|
}; |
||||
|
|
||||
|
} // namespace Core |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue