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