Merge pull request #3401 from FernandoS27/synchronization
Set of refactors for Kernel Synchronization and Hardware Constants
This commit is contained in:
commit
f552d553ba
|
@ -181,14 +181,16 @@ add_library(core STATIC
|
||||||
hle/kernel/svc.cpp
|
hle/kernel/svc.cpp
|
||||||
hle/kernel/svc.h
|
hle/kernel/svc.h
|
||||||
hle/kernel/svc_wrap.h
|
hle/kernel/svc_wrap.h
|
||||||
|
hle/kernel/synchronization_object.cpp
|
||||||
|
hle/kernel/synchronization_object.h
|
||||||
|
hle/kernel/synchronization.cpp
|
||||||
|
hle/kernel/synchronization.h
|
||||||
hle/kernel/thread.cpp
|
hle/kernel/thread.cpp
|
||||||
hle/kernel/thread.h
|
hle/kernel/thread.h
|
||||||
hle/kernel/transfer_memory.cpp
|
hle/kernel/transfer_memory.cpp
|
||||||
hle/kernel/transfer_memory.h
|
hle/kernel/transfer_memory.h
|
||||||
hle/kernel/vm_manager.cpp
|
hle/kernel/vm_manager.cpp
|
||||||
hle/kernel/vm_manager.h
|
hle/kernel/vm_manager.h
|
||||||
hle/kernel/wait_object.cpp
|
|
||||||
hle/kernel/wait_object.h
|
|
||||||
hle/kernel/writable_event.cpp
|
hle/kernel/writable_event.cpp
|
||||||
hle/kernel/writable_event.h
|
hle/kernel/writable_event.h
|
||||||
hle/lock.cpp
|
hle/lock.cpp
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
|
@ -153,7 +154,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit(Common::PageTable& pag
|
||||||
config.tpidr_el0 = &cb->tpidr_el0;
|
config.tpidr_el0 = &cb->tpidr_el0;
|
||||||
config.dczid_el0 = 4;
|
config.dczid_el0 = 4;
|
||||||
config.ctr_el0 = 0x8444c004;
|
config.ctr_el0 = 0x8444c004;
|
||||||
config.cntfrq_el0 = Timing::CNTFREQ;
|
config.cntfrq_el0 = Hardware::CNTFREQ;
|
||||||
|
|
||||||
// Unpredictable instructions
|
// Unpredictable instructions
|
||||||
config.define_unpredictable_behaviour = true;
|
config.define_unpredictable_behaviour = true;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core::Timing {
|
||||||
|
|
||||||
|
@ -215,7 +216,7 @@ void CoreTiming::Idle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
||||||
return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
|
return std::chrono::microseconds{GetTicks() * 1000000 / Hardware::BASE_CLOCK_RATE};
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 CoreTiming::GetDowncount() const {
|
s64 CoreTiming::GetDowncount() const {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core::Timing {
|
||||||
|
|
||||||
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE;
|
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / Hardware::BASE_CLOCK_RATE;
|
||||||
|
|
||||||
s64 msToCycles(std::chrono::milliseconds ms) {
|
s64 msToCycles(std::chrono::milliseconds ms) {
|
||||||
if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) {
|
if (static_cast<u64>(ms.count() / 1000) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
@ -20,9 +20,9 @@ s64 msToCycles(std::chrono::milliseconds ms) {
|
||||||
}
|
}
|
||||||
if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) {
|
if (static_cast<u64>(ms.count()) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||||
return BASE_CLOCK_RATE * (ms.count() / 1000);
|
return Hardware::BASE_CLOCK_RATE * (ms.count() / 1000);
|
||||||
}
|
}
|
||||||
return (BASE_CLOCK_RATE * ms.count()) / 1000;
|
return (Hardware::BASE_CLOCK_RATE * ms.count()) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 usToCycles(std::chrono::microseconds us) {
|
s64 usToCycles(std::chrono::microseconds us) {
|
||||||
|
@ -32,9 +32,9 @@ s64 usToCycles(std::chrono::microseconds us) {
|
||||||
}
|
}
|
||||||
if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) {
|
if (static_cast<u64>(us.count()) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||||
return BASE_CLOCK_RATE * (us.count() / 1000000);
|
return Hardware::BASE_CLOCK_RATE * (us.count() / 1000000);
|
||||||
}
|
}
|
||||||
return (BASE_CLOCK_RATE * us.count()) / 1000000;
|
return (Hardware::BASE_CLOCK_RATE * us.count()) / 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 nsToCycles(std::chrono::nanoseconds ns) {
|
s64 nsToCycles(std::chrono::nanoseconds ns) {
|
||||||
|
@ -44,14 +44,14 @@ s64 nsToCycles(std::chrono::nanoseconds ns) {
|
||||||
}
|
}
|
||||||
if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) {
|
if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||||
return BASE_CLOCK_RATE * (ns.count() / 1000000000);
|
return Hardware::BASE_CLOCK_RATE * (ns.count() / 1000000000);
|
||||||
}
|
}
|
||||||
return (BASE_CLOCK_RATE * ns.count()) / 1000000000;
|
return (Hardware::BASE_CLOCK_RATE * ns.count()) / 1000000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CpuCyclesToClockCycles(u64 ticks) {
|
u64 CpuCyclesToClockCycles(u64 ticks) {
|
||||||
const u128 temporal = Common::Multiply64Into128(ticks, CNTFREQ);
|
const u128 temporal = Common::Multiply64Into128(ticks, Hardware::CNTFREQ);
|
||||||
return Common::Divide128On32(temporal, static_cast<u32>(BASE_CLOCK_RATE)).first;
|
return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Timing
|
} // namespace Core::Timing
|
||||||
|
|
|
@ -6,28 +6,24 @@
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core::Timing {
|
||||||
|
|
||||||
// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
|
|
||||||
// The exact value used is of course unverified.
|
|
||||||
constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch clock speed is 1020MHz un/docked
|
|
||||||
constexpr u64 CNTFREQ = 19200000; // Value from fusee.
|
|
||||||
|
|
||||||
s64 msToCycles(std::chrono::milliseconds ms);
|
s64 msToCycles(std::chrono::milliseconds ms);
|
||||||
s64 usToCycles(std::chrono::microseconds us);
|
s64 usToCycles(std::chrono::microseconds us);
|
||||||
s64 nsToCycles(std::chrono::nanoseconds ns);
|
s64 nsToCycles(std::chrono::nanoseconds ns);
|
||||||
|
|
||||||
inline std::chrono::milliseconds CyclesToMs(s64 cycles) {
|
inline std::chrono::milliseconds CyclesToMs(s64 cycles) {
|
||||||
return std::chrono::milliseconds(cycles * 1000 / BASE_CLOCK_RATE);
|
return std::chrono::milliseconds(cycles * 1000 / Hardware::BASE_CLOCK_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::chrono::nanoseconds CyclesToNs(s64 cycles) {
|
inline std::chrono::nanoseconds CyclesToNs(s64 cycles) {
|
||||||
return std::chrono::nanoseconds(cycles * 1000000000 / BASE_CLOCK_RATE);
|
return std::chrono::nanoseconds(cycles * 1000000000 / Hardware::BASE_CLOCK_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::chrono::microseconds CyclesToUs(s64 cycles) {
|
inline std::chrono::microseconds CyclesToUs(s64 cycles) {
|
||||||
return std::chrono::microseconds(cycles * 1000000 / BASE_CLOCK_RATE);
|
return std::chrono::microseconds(cycles * 1000000 / Hardware::BASE_CLOCK_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CpuCyclesToClockCycles(u64 ticks);
|
u64 CpuCyclesToClockCycles(u64 ticks);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
@ -39,9 +40,7 @@ public:
|
||||||
void RunLoop(bool tight_loop);
|
void RunLoop(bool tight_loop);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::size_t NUM_CPU_CORES = 4;
|
std::array<std::unique_ptr<CoreManager>, Hardware::NUM_CPU_CORES> core_managers;
|
||||||
|
|
||||||
std::array<std::unique_ptr<CoreManager>, NUM_CPU_CORES> core_managers;
|
|
||||||
std::size_t active_core{}; ///< Active core, only used in single thread mode
|
std::size_t active_core{}; ///< Active core, only used in single thread mode
|
||||||
|
|
||||||
System& system;
|
System& system;
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
namespace Hardware {
|
||||||
|
|
||||||
|
// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
|
||||||
|
// The exact value used is of course unverified.
|
||||||
|
constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked
|
||||||
|
constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed
|
||||||
|
constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
|
||||||
|
|
||||||
|
} // namespace Hardware
|
||||||
|
|
||||||
|
struct EmuThreadHandle {
|
||||||
|
u32 host_handle;
|
||||||
|
u32 guest_handle;
|
||||||
|
|
||||||
|
u64 GetRaw() const {
|
||||||
|
return (static_cast<u64>(host_handle) << 32) | guest_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const EmuThreadHandle& rhs) const {
|
||||||
|
return std::tie(host_handle, guest_handle) == std::tie(rhs.host_handle, rhs.guest_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const EmuThreadHandle& rhs) const {
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr EmuThreadHandle InvalidHandle() {
|
||||||
|
constexpr u32 invalid_handle = 0xFFFFFFFF;
|
||||||
|
return {invalid_handle, invalid_handle};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {}
|
ClientSession::ClientSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
|
|
||||||
ClientSession::~ClientSession() {
|
ClientSession::~ClientSession() {
|
||||||
// This destructor will be called automatically when the last ClientSession handle is closed by
|
// This destructor will be called automatically when the last ClientSession handle is closed by
|
||||||
|
@ -31,6 +31,11 @@ void ClientSession::Acquire(Thread* thread) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClientSession::IsSignaled() const {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
|
ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
|
||||||
std::shared_ptr<Session> parent,
|
std::shared_ptr<Session> parent,
|
||||||
std::string name) {
|
std::string name) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
union ResultCode;
|
union ResultCode;
|
||||||
|
@ -22,7 +22,7 @@ class KernelCore;
|
||||||
class Session;
|
class Session;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
class ClientSession final : public WaitObject {
|
class ClientSession final : public SynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit ClientSession(KernelCore& kernel);
|
explicit ClientSession(KernelCore& kernel);
|
||||||
~ClientSession() override;
|
~ClientSession() override;
|
||||||
|
@ -48,6 +48,8 @@ public:
|
||||||
|
|
||||||
void Acquire(Thread* thread) override;
|
void Acquire(Thread* thread) override;
|
||||||
|
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
|
static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
|
||||||
std::shared_ptr<Session> parent,
|
std::shared_ptr<Session> parent,
|
||||||
|
|
|
@ -47,9 +47,9 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||||
const std::string& reason, u64 timeout, WakeupCallback&& callback,
|
const std::string& reason, u64 timeout, WakeupCallback&& callback,
|
||||||
std::shared_ptr<WritableEvent> writable_event) {
|
std::shared_ptr<WritableEvent> writable_event) {
|
||||||
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
||||||
thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason,
|
thread->SetWakeupCallback(
|
||||||
std::shared_ptr<Thread> thread,
|
[context = *this, callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<WaitObject> object,
|
std::shared_ptr<SynchronizationObject> object,
|
||||||
std::size_t index) mutable -> bool {
|
std::size_t index) mutable -> bool {
|
||||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
|
ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
|
||||||
callback(thread, context, reason);
|
callback(thread, context, reason);
|
||||||
|
@ -67,7 +67,7 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||||
const auto readable_event{writable_event->GetReadableEvent()};
|
const auto readable_event{writable_event->GetReadableEvent()};
|
||||||
writable_event->Clear();
|
writable_event->Clear();
|
||||||
thread->SetStatus(ThreadStatus::WaitHLEEvent);
|
thread->SetStatus(ThreadStatus::WaitHLEEvent);
|
||||||
thread->SetWaitObjects({readable_event});
|
thread->SetSynchronizationObjects({readable_event});
|
||||||
readable_event->AddWaitingThread(thread);
|
readable_event->AddWaitingThread(thread);
|
||||||
|
|
||||||
if (timeout > 0) {
|
if (timeout > 0) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
|
#include "core/hle/kernel/synchronization.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
@ -54,10 +55,10 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
|
||||||
if (thread->GetStatus() == ThreadStatus::WaitSynch ||
|
if (thread->GetStatus() == ThreadStatus::WaitSynch ||
|
||||||
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
|
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
|
||||||
// Remove the thread from each of its waiting objects' waitlists
|
// Remove the thread from each of its waiting objects' waitlists
|
||||||
for (const auto& object : thread->GetWaitObjects()) {
|
for (const auto& object : thread->GetSynchronizationObjects()) {
|
||||||
object->RemoveWaitingThread(thread);
|
object->RemoveWaitingThread(thread);
|
||||||
}
|
}
|
||||||
thread->ClearWaitObjects();
|
thread->ClearSynchronizationObjects();
|
||||||
|
|
||||||
// Invoke the wakeup callback before clearing the wait objects
|
// Invoke the wakeup callback before clearing the wait objects
|
||||||
if (thread->HasWakeupCallback()) {
|
if (thread->HasWakeupCallback()) {
|
||||||
|
@ -96,7 +97,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
|
||||||
}
|
}
|
||||||
|
|
||||||
struct KernelCore::Impl {
|
struct KernelCore::Impl {
|
||||||
explicit Impl(Core::System& system) : system{system}, global_scheduler{system} {}
|
explicit Impl(Core::System& system)
|
||||||
|
: system{system}, global_scheduler{system}, synchronization{system} {}
|
||||||
|
|
||||||
void Initialize(KernelCore& kernel) {
|
void Initialize(KernelCore& kernel) {
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
@ -191,6 +193,7 @@ struct KernelCore::Impl {
|
||||||
std::vector<std::shared_ptr<Process>> process_list;
|
std::vector<std::shared_ptr<Process>> process_list;
|
||||||
Process* current_process = nullptr;
|
Process* current_process = nullptr;
|
||||||
Kernel::GlobalScheduler global_scheduler;
|
Kernel::GlobalScheduler global_scheduler;
|
||||||
|
Kernel::Synchronization synchronization;
|
||||||
|
|
||||||
std::shared_ptr<ResourceLimit> system_resource_limit;
|
std::shared_ptr<ResourceLimit> system_resource_limit;
|
||||||
|
|
||||||
|
@ -270,6 +273,14 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
|
||||||
return impl->cores[id];
|
return impl->cores[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kernel::Synchronization& KernelCore::Synchronization() {
|
||||||
|
return impl->synchronization;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Kernel::Synchronization& KernelCore::Synchronization() const {
|
||||||
|
return impl->synchronization;
|
||||||
|
}
|
||||||
|
|
||||||
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
|
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
|
||||||
return *impl->exclusive_monitor;
|
return *impl->exclusive_monitor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ class HandleTable;
|
||||||
class PhysicalCore;
|
class PhysicalCore;
|
||||||
class Process;
|
class Process;
|
||||||
class ResourceLimit;
|
class ResourceLimit;
|
||||||
|
class Synchronization;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
/// Represents a single instance of the kernel.
|
/// Represents a single instance of the kernel.
|
||||||
|
@ -92,6 +93,12 @@ public:
|
||||||
/// Gets the an instance of the respective physical CPU core.
|
/// Gets the an instance of the respective physical CPU core.
|
||||||
const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
|
const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
|
||||||
|
|
||||||
|
/// Gets the an instance of the Synchronization Interface.
|
||||||
|
Kernel::Synchronization& Synchronization();
|
||||||
|
|
||||||
|
/// Gets the an instance of the Synchronization Interface.
|
||||||
|
const Kernel::Synchronization& Synchronization() const;
|
||||||
|
|
||||||
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
/// Stops execution of 'id' core, in order to reschedule a new thread.
|
||||||
void PrepareReschedule(std::size_t id);
|
void PrepareReschedule(std::size_t id);
|
||||||
|
|
||||||
|
|
|
@ -337,7 +337,7 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::Process(Core::System& system)
|
Process::Process(Core::System& system)
|
||||||
: WaitObject{system.Kernel()}, vm_manager{system},
|
: SynchronizationObject{system.Kernel()}, vm_manager{system},
|
||||||
address_arbiter{system}, mutex{system}, system{system} {}
|
address_arbiter{system}, mutex{system}, system{system} {}
|
||||||
|
|
||||||
Process::~Process() = default;
|
Process::~Process() = default;
|
||||||
|
@ -357,7 +357,7 @@ void Process::ChangeStatus(ProcessStatus new_status) {
|
||||||
|
|
||||||
status = new_status;
|
status = new_status;
|
||||||
is_signaled = true;
|
is_signaled = true;
|
||||||
WakeupAllWaitingThreads();
|
Signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::AllocateMainThreadStack(u64 stack_size) {
|
void Process::AllocateMainThreadStack(u64 stack_size) {
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/mutex.h"
|
#include "core/hle/kernel/mutex.h"
|
||||||
#include "core/hle/kernel/process_capability.h"
|
#include "core/hle/kernel/process_capability.h"
|
||||||
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/kernel/vm_manager.h"
|
#include "core/hle/kernel/vm_manager.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -60,7 +60,7 @@ enum class ProcessStatus {
|
||||||
DebugBreak,
|
DebugBreak,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Process final : public WaitObject {
|
class Process final : public SynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit Process(Core::System& system);
|
explicit Process(Core::System& system);
|
||||||
~Process() override;
|
~Process() override;
|
||||||
|
@ -359,10 +359,6 @@ private:
|
||||||
/// specified by metadata provided to the process during loading.
|
/// specified by metadata provided to the process during loading.
|
||||||
bool is_64bit_process = true;
|
bool is_64bit_process = true;
|
||||||
|
|
||||||
/// Whether or not this process is signaled. This occurs
|
|
||||||
/// upon the process changing to a different state.
|
|
||||||
bool is_signaled = false;
|
|
||||||
|
|
||||||
/// Total running time for the process in ticks.
|
/// Total running time for the process in ticks.
|
||||||
u64 total_process_running_time_ticks = 0;
|
u64 total_process_running_time_ticks = 0;
|
||||||
|
|
||||||
|
|
|
@ -11,30 +11,30 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
|
ReadableEvent::ReadableEvent(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
ReadableEvent::~ReadableEvent() = default;
|
ReadableEvent::~ReadableEvent() = default;
|
||||||
|
|
||||||
bool ReadableEvent::ShouldWait(const Thread* thread) const {
|
bool ReadableEvent::ShouldWait(const Thread* thread) const {
|
||||||
return !signaled;
|
return !is_signaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadableEvent::Acquire(Thread* thread) {
|
void ReadableEvent::Acquire(Thread* thread) {
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
ASSERT_MSG(IsSignaled(), "object unavailable!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadableEvent::Signal() {
|
void ReadableEvent::Signal() {
|
||||||
if (!signaled) {
|
if (!is_signaled) {
|
||||||
signaled = true;
|
is_signaled = true;
|
||||||
WakeupAllWaitingThreads();
|
SynchronizationObject::Signal();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadableEvent::Clear() {
|
void ReadableEvent::Clear() {
|
||||||
signaled = false;
|
is_signaled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ReadableEvent::Reset() {
|
ResultCode ReadableEvent::Reset() {
|
||||||
if (!signaled) {
|
if (!is_signaled) {
|
||||||
return ERR_INVALID_STATE;
|
return ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
|
|
||||||
union ResultCode;
|
union ResultCode;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Kernel {
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
class WritableEvent;
|
class WritableEvent;
|
||||||
|
|
||||||
class ReadableEvent final : public WaitObject {
|
class ReadableEvent final : public SynchronizationObject {
|
||||||
friend class WritableEvent;
|
friend class WritableEvent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -46,13 +46,11 @@ public:
|
||||||
/// then ERR_INVALID_STATE will be returned.
|
/// then ERR_INVALID_STATE will be returned.
|
||||||
ResultCode Reset();
|
ResultCode Reset();
|
||||||
|
|
||||||
|
void Signal() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ReadableEvent(KernelCore& kernel);
|
explicit ReadableEvent(KernelCore& kernel);
|
||||||
|
|
||||||
void Signal();
|
|
||||||
|
|
||||||
bool signaled{};
|
|
||||||
|
|
||||||
std::string name; ///< Name of event (optional)
|
std::string name; ///< Name of event (optional)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -124,8 +124,8 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) {
|
||||||
"Thread yielding without being in front");
|
"Thread yielding without being in front");
|
||||||
scheduled_queue[core_id].yield(priority);
|
scheduled_queue[core_id].yield(priority);
|
||||||
|
|
||||||
std::array<Thread*, NUM_CPU_CORES> current_threads;
|
std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
|
||||||
for (u32 i = 0; i < NUM_CPU_CORES; i++) {
|
for (std::size_t i = 0; i < current_threads.size(); i++) {
|
||||||
current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
|
current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,8 +177,8 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread
|
||||||
// function...
|
// function...
|
||||||
if (scheduled_queue[core_id].empty()) {
|
if (scheduled_queue[core_id].empty()) {
|
||||||
// Here, "current_threads" is calculated after the ""yield"", unlike yield -1
|
// Here, "current_threads" is calculated after the ""yield"", unlike yield -1
|
||||||
std::array<Thread*, NUM_CPU_CORES> current_threads;
|
std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
|
||||||
for (u32 i = 0; i < NUM_CPU_CORES; i++) {
|
for (std::size_t i = 0; i < current_threads.size(); i++) {
|
||||||
current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
|
current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
|
||||||
}
|
}
|
||||||
for (auto& thread : suggested_queue[core_id]) {
|
for (auto& thread : suggested_queue[core_id]) {
|
||||||
|
@ -208,7 +208,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalScheduler::PreemptThreads() {
|
void GlobalScheduler::PreemptThreads() {
|
||||||
for (std::size_t core_id = 0; core_id < NUM_CPU_CORES; core_id++) {
|
for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
||||||
const u32 priority = preemption_priorities[core_id];
|
const u32 priority = preemption_priorities[core_id];
|
||||||
|
|
||||||
if (scheduled_queue[core_id].size(priority) > 0) {
|
if (scheduled_queue[core_id].size(priority) > 0) {
|
||||||
|
@ -349,7 +349,7 @@ bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread,
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalScheduler::Shutdown() {
|
void GlobalScheduler::Shutdown() {
|
||||||
for (std::size_t core = 0; core < NUM_CPU_CORES; core++) {
|
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
scheduled_queue[core].clear();
|
scheduled_queue[core].clear();
|
||||||
suggested_queue[core].clear();
|
suggested_queue[core].clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/multi_level_queue.h"
|
#include "common/multi_level_queue.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -23,8 +24,6 @@ class Process;
|
||||||
|
|
||||||
class GlobalScheduler final {
|
class GlobalScheduler final {
|
||||||
public:
|
public:
|
||||||
static constexpr u32 NUM_CPU_CORES = 4;
|
|
||||||
|
|
||||||
explicit GlobalScheduler(Core::System& system);
|
explicit GlobalScheduler(Core::System& system);
|
||||||
~GlobalScheduler();
|
~GlobalScheduler();
|
||||||
|
|
||||||
|
@ -125,7 +124,7 @@ public:
|
||||||
void PreemptThreads();
|
void PreemptThreads();
|
||||||
|
|
||||||
u32 CpuCoresCount() const {
|
u32 CpuCoresCount() const {
|
||||||
return NUM_CPU_CORES;
|
return Core::Hardware::NUM_CPU_CORES;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetReselectionPending() {
|
void SetReselectionPending() {
|
||||||
|
@ -149,13 +148,15 @@ private:
|
||||||
bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner);
|
bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner);
|
||||||
|
|
||||||
static constexpr u32 min_regular_priority = 2;
|
static constexpr u32 min_regular_priority = 2;
|
||||||
std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> scheduled_queue;
|
std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
|
||||||
std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> suggested_queue;
|
scheduled_queue;
|
||||||
|
std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
|
||||||
|
suggested_queue;
|
||||||
std::atomic<bool> is_reselection_pending{false};
|
std::atomic<bool> is_reselection_pending{false};
|
||||||
|
|
||||||
// The priority levels at which the global scheduler preempts threads every 10 ms. They are
|
// The priority levels at which the global scheduler preempts threads every 10 ms. They are
|
||||||
// ordered from Core 0 to Core 3.
|
// ordered from Core 0 to Core 3.
|
||||||
std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
|
std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
|
||||||
|
|
||||||
/// Lists all thread ids that aren't deleted/etc.
|
/// Lists all thread ids that aren't deleted/etc.
|
||||||
std::vector<std::shared_ptr<Thread>> thread_list;
|
std::vector<std::shared_ptr<Thread>> thread_list;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {}
|
ServerPort::ServerPort(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
ServerPort::~ServerPort() = default;
|
ServerPort::~ServerPort() = default;
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
|
ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
|
||||||
|
@ -39,6 +39,10 @@ void ServerPort::Acquire(Thread* thread) {
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ServerPort::IsSignaled() const {
|
||||||
|
return !pending_sessions.empty();
|
||||||
|
}
|
||||||
|
|
||||||
ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
|
ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
|
||||||
std::string name) {
|
std::string name) {
|
||||||
std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel);
|
std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -20,7 +20,7 @@ class KernelCore;
|
||||||
class ServerSession;
|
class ServerSession;
|
||||||
class SessionRequestHandler;
|
class SessionRequestHandler;
|
||||||
|
|
||||||
class ServerPort final : public WaitObject {
|
class ServerPort final : public SynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit ServerPort(KernelCore& kernel);
|
explicit ServerPort(KernelCore& kernel);
|
||||||
~ServerPort() override;
|
~ServerPort() override;
|
||||||
|
@ -82,6 +82,8 @@ public:
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
bool ShouldWait(const Thread* thread) const override;
|
||||||
void Acquire(Thread* thread) override;
|
void Acquire(Thread* thread) override;
|
||||||
|
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// ServerSessions waiting to be accepted by the port
|
/// ServerSessions waiting to be accepted by the port
|
||||||
std::vector<std::shared_ptr<ServerSession>> pending_sessions;
|
std::vector<std::shared_ptr<ServerSession>> pending_sessions;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
|
ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
ServerSession::~ServerSession() = default;
|
ServerSession::~ServerSession() = default;
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
|
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
|
||||||
|
@ -50,6 +50,16 @@ bool ServerSession::ShouldWait(const Thread* thread) const {
|
||||||
return pending_requesting_threads.empty() || currently_handling != nullptr;
|
return pending_requesting_threads.empty() || currently_handling != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ServerSession::IsSignaled() const {
|
||||||
|
// Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
|
||||||
|
if (!parent->Client()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait if we have no pending requests, or if we're currently handling a request.
|
||||||
|
return !pending_requesting_threads.empty() && currently_handling == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void ServerSession::Acquire(Thread* thread) {
|
void ServerSession::Acquire(Thread* thread) {
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||||
// We are now handling a request, pop it from the stack.
|
// We are now handling a request, pop it from the stack.
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/threadsafe_queue.h"
|
#include "common/threadsafe_queue.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
@ -41,7 +41,7 @@ class Thread;
|
||||||
* After the server replies to the request, the response is marshalled back to the caller's
|
* After the server replies to the request, the response is marshalled back to the caller's
|
||||||
* TLS buffer and control is transferred back to it.
|
* TLS buffer and control is transferred back to it.
|
||||||
*/
|
*/
|
||||||
class ServerSession final : public WaitObject {
|
class ServerSession final : public SynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit ServerSession(KernelCore& kernel);
|
explicit ServerSession(KernelCore& kernel);
|
||||||
~ServerSession() override;
|
~ServerSession() override;
|
||||||
|
@ -73,6 +73,8 @@ public:
|
||||||
return parent.get();
|
return parent.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the HLE handler for the session. This handler will be called to service IPC requests
|
* Sets the HLE handler for the session. This handler will be called to service IPC requests
|
||||||
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
|
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
Session::Session(KernelCore& kernel) : WaitObject{kernel} {}
|
Session::Session(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
Session::~Session() = default;
|
Session::~Session() = default;
|
||||||
|
|
||||||
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
|
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
|
||||||
|
@ -29,6 +29,11 @@ bool Session::ShouldWait(const Thread* thread) const {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Session::IsSignaled() const {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Session::Acquire(Thread* thread) {
|
void Session::Acquire(Thread* thread) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class ServerSession;
|
||||||
* Parent structure to link the client and server endpoints of a session with their associated
|
* Parent structure to link the client and server endpoints of a session with their associated
|
||||||
* client port.
|
* client port.
|
||||||
*/
|
*/
|
||||||
class Session final : public WaitObject {
|
class Session final : public SynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit Session(KernelCore& kernel);
|
explicit Session(KernelCore& kernel);
|
||||||
~Session() override;
|
~Session() override;
|
||||||
|
@ -39,6 +39,8 @@ public:
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
bool ShouldWait(const Thread* thread) const override;
|
||||||
|
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
void Acquire(Thread* thread) override;
|
void Acquire(Thread* thread) override;
|
||||||
|
|
||||||
std::shared_ptr<ClientSession> Client() {
|
std::shared_ptr<ClientSession> Client() {
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
#include "core/hle/kernel/svc_wrap.h"
|
#include "core/hle/kernel/svc_wrap.h"
|
||||||
|
#include "core/hle/kernel/synchronization.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/transfer_memory.h"
|
#include "core/hle/kernel/transfer_memory.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
|
@ -433,22 +434,6 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default thread wakeup callback for WaitSynchronization
|
|
||||||
static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
|
||||||
std::shared_ptr<WaitObject> object, std::size_t index) {
|
|
||||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
|
|
||||||
|
|
||||||
if (reason == ThreadWakeupReason::Timeout) {
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
|
||||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
|
||||||
thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
|
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
|
||||||
static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address,
|
static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address,
|
||||||
u64 handle_count, s64 nano_seconds) {
|
u64 handle_count, s64 nano_seconds) {
|
||||||
|
@ -472,14 +457,14 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* const thread = system.CurrentScheduler().GetCurrentThread();
|
auto* const thread = system.CurrentScheduler().GetCurrentThread();
|
||||||
|
auto& kernel = system.Kernel();
|
||||||
using ObjectPtr = Thread::ThreadWaitObjects::value_type;
|
using ObjectPtr = Thread::ThreadSynchronizationObjects::value_type;
|
||||||
Thread::ThreadWaitObjects objects(handle_count);
|
Thread::ThreadSynchronizationObjects objects(handle_count);
|
||||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||||
|
|
||||||
for (u64 i = 0; i < handle_count; ++i) {
|
for (u64 i = 0; i < handle_count; ++i) {
|
||||||
const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
|
const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
|
||||||
const auto object = handle_table.Get<WaitObject>(handle);
|
const auto object = handle_table.Get<SynchronizationObject>(handle);
|
||||||
|
|
||||||
if (object == nullptr) {
|
if (object == nullptr) {
|
||||||
LOG_ERROR(Kernel_SVC, "Object is a nullptr");
|
LOG_ERROR(Kernel_SVC, "Object is a nullptr");
|
||||||
|
@ -488,47 +473,10 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
|
||||||
|
|
||||||
objects[i] = object;
|
objects[i] = object;
|
||||||
}
|
}
|
||||||
|
auto& synchronization = kernel.Synchronization();
|
||||||
// Find the first object that is acquirable in the provided list of objects
|
const auto [result, handle_result] = synchronization.WaitFor(objects, nano_seconds);
|
||||||
auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
|
*index = handle_result;
|
||||||
return !object->ShouldWait(thread);
|
return result;
|
||||||
});
|
|
||||||
|
|
||||||
if (itr != objects.end()) {
|
|
||||||
// We found a ready object, acquire it and set the result value
|
|
||||||
WaitObject* object = itr->get();
|
|
||||||
object->Acquire(thread);
|
|
||||||
*index = static_cast<s32>(std::distance(objects.begin(), itr));
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No objects were ready to be acquired, prepare to suspend the thread.
|
|
||||||
|
|
||||||
// If a timeout value of 0 was provided, just return the Timeout error code instead of
|
|
||||||
// suspending the thread.
|
|
||||||
if (nano_seconds == 0) {
|
|
||||||
return RESULT_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->IsSyncCancelled()) {
|
|
||||||
thread->SetSyncCancelled(false);
|
|
||||||
return ERR_SYNCHRONIZATION_CANCELED;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& object : objects) {
|
|
||||||
object->AddWaitingThread(SharedFrom(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->SetWaitObjects(std::move(objects));
|
|
||||||
thread->SetStatus(ThreadStatus::WaitSynch);
|
|
||||||
|
|
||||||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
|
||||||
thread->WakeAfterDelay(nano_seconds);
|
|
||||||
thread->SetWakeupCallback(DefaultThreadWakeupCallback);
|
|
||||||
|
|
||||||
system.PrepareReschedule(thread->GetProcessorID());
|
|
||||||
|
|
||||||
return RESULT_TIMEOUT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resumes a thread waiting on WaitSynchronization
|
/// Resumes a thread waiting on WaitSynchronization
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/errors.h"
|
||||||
|
#include "core/hle/kernel/handle_table.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/scheduler.h"
|
||||||
|
#include "core/hle/kernel/synchronization.h"
|
||||||
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
/// Default thread wakeup callback for WaitSynchronization
|
||||||
|
static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<SynchronizationObject> object,
|
||||||
|
std::size_t index) {
|
||||||
|
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
|
||||||
|
|
||||||
|
if (reason == ThreadWakeupReason::Timeout) {
|
||||||
|
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||||
|
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
||||||
|
thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Synchronization::Synchronization(Core::System& system) : system{system} {}
|
||||||
|
|
||||||
|
void Synchronization::SignalObject(SynchronizationObject& obj) const {
|
||||||
|
if (obj.IsSignaled()) {
|
||||||
|
obj.WakeupAllWaitingThreads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<ResultCode, Handle> Synchronization::WaitFor(
|
||||||
|
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
|
||||||
|
auto* const thread = system.CurrentScheduler().GetCurrentThread();
|
||||||
|
// Find the first object that is acquirable in the provided list of objects
|
||||||
|
const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(),
|
||||||
|
[thread](const std::shared_ptr<SynchronizationObject>& object) {
|
||||||
|
return object->IsSignaled();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (itr != sync_objects.end()) {
|
||||||
|
// We found a ready object, acquire it and set the result value
|
||||||
|
SynchronizationObject* object = itr->get();
|
||||||
|
object->Acquire(thread);
|
||||||
|
const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
|
||||||
|
return {RESULT_SUCCESS, index};
|
||||||
|
}
|
||||||
|
|
||||||
|
// No objects were ready to be acquired, prepare to suspend the thread.
|
||||||
|
|
||||||
|
// If a timeout value of 0 was provided, just return the Timeout error code instead of
|
||||||
|
// suspending the thread.
|
||||||
|
if (nano_seconds == 0) {
|
||||||
|
return {RESULT_TIMEOUT, InvalidHandle};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread->IsSyncCancelled()) {
|
||||||
|
thread->SetSyncCancelled(false);
|
||||||
|
return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& object : sync_objects) {
|
||||||
|
object->AddWaitingThread(SharedFrom(thread));
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->SetSynchronizationObjects(std::move(sync_objects));
|
||||||
|
thread->SetStatus(ThreadStatus::WaitSynch);
|
||||||
|
|
||||||
|
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||||
|
thread->WakeAfterDelay(nano_seconds);
|
||||||
|
thread->SetWakeupCallback(DefaultThreadWakeupCallback);
|
||||||
|
|
||||||
|
system.PrepareReschedule(thread->GetProcessorID());
|
||||||
|
|
||||||
|
return {RESULT_TIMEOUT, InvalidHandle};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core/hle/kernel/object.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class SynchronizationObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 'Synchronization' class is an interface for handling synchronization methods
|
||||||
|
* used by Synchronization objects and synchronization SVCs. This centralizes processing of
|
||||||
|
* such
|
||||||
|
*/
|
||||||
|
class Synchronization {
|
||||||
|
public:
|
||||||
|
explicit Synchronization(Core::System& system);
|
||||||
|
|
||||||
|
/// Signals a synchronization object, waking up all its waiting threads
|
||||||
|
void SignalObject(SynchronizationObject& obj) const;
|
||||||
|
|
||||||
|
/// Tries to see if waiting for any of the sync_objects is necessary, if not
|
||||||
|
/// it returns Success and the handle index of the signaled sync object. In
|
||||||
|
/// case not, the current thread will be locked and wait for nano_seconds or
|
||||||
|
/// for a synchronization object to signal.
|
||||||
|
std::pair<ResultCode, Handle> WaitFor(
|
||||||
|
std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::System& system;
|
||||||
|
};
|
||||||
|
} // namespace Kernel
|
|
@ -10,20 +10,26 @@
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
|
#include "core/hle/kernel/synchronization.h"
|
||||||
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {}
|
SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
|
||||||
WaitObject::~WaitObject() = default;
|
SynchronizationObject::~SynchronizationObject() = default;
|
||||||
|
|
||||||
void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
|
void SynchronizationObject::Signal() {
|
||||||
|
kernel.Synchronization().SignalObject(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
|
||||||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
||||||
if (itr == waiting_threads.end())
|
if (itr == waiting_threads.end())
|
||||||
waiting_threads.push_back(std::move(thread));
|
waiting_threads.push_back(std::move(thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
|
void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
|
||||||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
||||||
// If a thread passed multiple handles to the same object,
|
// If a thread passed multiple handles to the same object,
|
||||||
// the kernel might attempt to remove the thread from the object's
|
// the kernel might attempt to remove the thread from the object's
|
||||||
|
@ -32,7 +38,7 @@ void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
|
||||||
waiting_threads.erase(itr);
|
waiting_threads.erase(itr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
|
std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const {
|
||||||
Thread* candidate = nullptr;
|
Thread* candidate = nullptr;
|
||||||
u32 candidate_priority = THREADPRIO_LOWEST + 1;
|
u32 candidate_priority = THREADPRIO_LOWEST + 1;
|
||||||
|
|
||||||
|
@ -57,7 +63,7 @@ std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
|
||||||
return SharedFrom(candidate);
|
return SharedFrom(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
|
void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
|
||||||
ASSERT(!ShouldWait(thread.get()));
|
ASSERT(!ShouldWait(thread.get()));
|
||||||
|
|
||||||
if (!thread) {
|
if (!thread) {
|
||||||
|
@ -65,7 +71,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread->IsSleepingOnWait()) {
|
if (thread->IsSleepingOnWait()) {
|
||||||
for (const auto& object : thread->GetWaitObjects()) {
|
for (const auto& object : thread->GetSynchronizationObjects()) {
|
||||||
ASSERT(!object->ShouldWait(thread.get()));
|
ASSERT(!object->ShouldWait(thread.get()));
|
||||||
object->Acquire(thread.get());
|
object->Acquire(thread.get());
|
||||||
}
|
}
|
||||||
|
@ -73,9 +79,9 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
|
||||||
Acquire(thread.get());
|
Acquire(thread.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this));
|
const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this));
|
||||||
|
|
||||||
thread->ClearWaitObjects();
|
thread->ClearSynchronizationObjects();
|
||||||
|
|
||||||
thread->CancelWakeupTimer();
|
thread->CancelWakeupTimer();
|
||||||
|
|
||||||
|
@ -90,13 +96,13 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitObject::WakeupAllWaitingThreads() {
|
void SynchronizationObject::WakeupAllWaitingThreads() {
|
||||||
while (auto thread = GetHighestPriorityReadyThread()) {
|
while (auto thread = GetHighestPriorityReadyThread()) {
|
||||||
WakeupWaitingThread(thread);
|
WakeupWaitingThread(thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const {
|
const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
|
||||||
return waiting_threads;
|
return waiting_threads;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ class KernelCore;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
/// Class that represents a Kernel object that a thread can be waiting on
|
/// Class that represents a Kernel object that a thread can be waiting on
|
||||||
class WaitObject : public Object {
|
class SynchronizationObject : public Object {
|
||||||
public:
|
public:
|
||||||
explicit WaitObject(KernelCore& kernel);
|
explicit SynchronizationObject(KernelCore& kernel);
|
||||||
~WaitObject() override;
|
~SynchronizationObject() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the specified thread should wait until the object is available
|
* Check if the specified thread should wait until the object is available
|
||||||
|
@ -30,6 +30,13 @@ public:
|
||||||
/// Acquire/lock the object for the specified thread if it is available
|
/// Acquire/lock the object for the specified thread if it is available
|
||||||
virtual void Acquire(Thread* thread) = 0;
|
virtual void Acquire(Thread* thread) = 0;
|
||||||
|
|
||||||
|
/// Signal this object
|
||||||
|
virtual void Signal();
|
||||||
|
|
||||||
|
virtual bool IsSignaled() const {
|
||||||
|
return is_signaled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a thread to wait on this object
|
* Add a thread to wait on this object
|
||||||
* @param thread Pointer to thread to add
|
* @param thread Pointer to thread to add
|
||||||
|
@ -60,16 +67,20 @@ public:
|
||||||
/// Get a const reference to the waiting threads list for debug use
|
/// Get a const reference to the waiting threads list for debug use
|
||||||
const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
|
const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool is_signaled{}; // Tells if this sync object is signalled;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Threads waiting for this object to become available
|
/// Threads waiting for this object to become available
|
||||||
std::vector<std::shared_ptr<Thread>> waiting_threads;
|
std::vector<std::shared_ptr<Thread>> waiting_threads;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specialization of DynamicObjectCast for WaitObjects
|
// Specialization of DynamicObjectCast for SynchronizationObjects
|
||||||
template <>
|
template <>
|
||||||
inline std::shared_ptr<WaitObject> DynamicObjectCast<WaitObject>(std::shared_ptr<Object> object) {
|
inline std::shared_ptr<SynchronizationObject> DynamicObjectCast<SynchronizationObject>(
|
||||||
|
std::shared_ptr<Object> object) {
|
||||||
if (object != nullptr && object->IsWaitable()) {
|
if (object != nullptr && object->IsWaitable()) {
|
||||||
return std::static_pointer_cast<WaitObject>(object);
|
return std::static_pointer_cast<SynchronizationObject>(object);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/errors.h"
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
@ -31,11 +32,15 @@ bool Thread::ShouldWait(const Thread* thread) const {
|
||||||
return status != ThreadStatus::Dead;
|
return status != ThreadStatus::Dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Thread::IsSignaled() const {
|
||||||
|
return status == ThreadStatus::Dead;
|
||||||
|
}
|
||||||
|
|
||||||
void Thread::Acquire(Thread* thread) {
|
void Thread::Acquire(Thread* thread) {
|
||||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {}
|
Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
Thread::~Thread() = default;
|
Thread::~Thread() = default;
|
||||||
|
|
||||||
void Thread::Stop() {
|
void Thread::Stop() {
|
||||||
|
@ -45,7 +50,7 @@ void Thread::Stop() {
|
||||||
kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
|
kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
|
||||||
callback_handle = 0;
|
callback_handle = 0;
|
||||||
SetStatus(ThreadStatus::Dead);
|
SetStatus(ThreadStatus::Dead);
|
||||||
WakeupAllWaitingThreads();
|
Signal();
|
||||||
|
|
||||||
// Clean up any dangling references in objects that this thread was waiting for
|
// Clean up any dangling references in objects that this thread was waiting for
|
||||||
for (auto& wait_object : wait_objects) {
|
for (auto& wait_object : wait_objects) {
|
||||||
|
@ -215,7 +220,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
|
||||||
context.cpu_registers[1] = output;
|
context.cpu_registers[1] = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 Thread::GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const {
|
s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const {
|
||||||
ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
|
ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
|
||||||
const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
|
const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
|
||||||
return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
|
return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
|
||||||
|
@ -336,14 +341,16 @@ void Thread::ChangeCore(u32 core, u64 mask) {
|
||||||
SetCoreAndAffinityMask(core, mask);
|
SetCoreAndAffinityMask(core, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::AllWaitObjectsReady() const {
|
bool Thread::AllSynchronizationObjectsReady() const {
|
||||||
return std::none_of(
|
return std::none_of(wait_objects.begin(), wait_objects.end(),
|
||||||
wait_objects.begin(), wait_objects.end(),
|
[this](const std::shared_ptr<SynchronizationObject>& object) {
|
||||||
[this](const std::shared_ptr<WaitObject>& object) { return object->ShouldWait(this); });
|
return object->ShouldWait(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<WaitObject> object, std::size_t index) {
|
std::shared_ptr<SynchronizationObject> object,
|
||||||
|
std::size_t index) {
|
||||||
ASSERT(wakeup_callback);
|
ASSERT(wakeup_callback);
|
||||||
return wakeup_callback(reason, std::move(thread), std::move(object), index);
|
return wakeup_callback(reason, std::move(thread), std::move(object), index);
|
||||||
}
|
}
|
||||||
|
@ -425,7 +432,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
|
||||||
const s32 old_core = processor_id;
|
const s32 old_core = processor_id;
|
||||||
if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) {
|
if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) {
|
||||||
if (static_cast<s32>(ideal_core) < 0) {
|
if (static_cast<s32>(ideal_core) < 0) {
|
||||||
processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES);
|
processor_id = HighestSetCore(affinity_mask, Core::Hardware::NUM_CPU_CORES);
|
||||||
} else {
|
} else {
|
||||||
processor_id = ideal_core;
|
processor_id = ideal_core;
|
||||||
}
|
}
|
||||||
|
@ -449,7 +456,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) {
|
||||||
scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this);
|
scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
|
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
||||||
scheduler.Unsuggest(current_priority, core, this);
|
scheduler.Unsuggest(current_priority, core, this);
|
||||||
}
|
}
|
||||||
|
@ -460,7 +467,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) {
|
||||||
scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this);
|
scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
|
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
||||||
scheduler.Suggest(current_priority, core, this);
|
scheduler.Suggest(current_priority, core, this);
|
||||||
}
|
}
|
||||||
|
@ -479,7 +486,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
|
||||||
scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
|
scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
|
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
||||||
scheduler.Unsuggest(old_priority, core, this);
|
scheduler.Unsuggest(old_priority, core, this);
|
||||||
}
|
}
|
||||||
|
@ -496,7 +503,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
|
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
|
||||||
scheduler.Suggest(current_priority, core, this);
|
scheduler.Suggest(current_priority, core, this);
|
||||||
}
|
}
|
||||||
|
@ -512,7 +519,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
|
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
if (((old_affinity_mask >> core) & 1) != 0) {
|
if (((old_affinity_mask >> core) & 1) != 0) {
|
||||||
if (core == static_cast<u32>(old_core)) {
|
if (core == static_cast<u32>(old_core)) {
|
||||||
scheduler.Unschedule(current_priority, core, this);
|
scheduler.Unschedule(current_priority, core, this);
|
||||||
|
@ -522,7 +529,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) {
|
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||||
if (((affinity_mask >> core) & 1) != 0) {
|
if (((affinity_mask >> core) & 1) != 0) {
|
||||||
if (core == static_cast<u32>(processor_id)) {
|
if (core == static_cast<u32>(processor_id)) {
|
||||||
scheduler.Schedule(current_priority, core, this);
|
scheduler.Schedule(current_priority, core, this);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -95,7 +95,7 @@ enum class ThreadSchedMasks : u32 {
|
||||||
ForcePauseMask = 0x0070,
|
ForcePauseMask = 0x0070,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Thread final : public WaitObject {
|
class Thread final : public SynchronizationObject {
|
||||||
public:
|
public:
|
||||||
explicit Thread(KernelCore& kernel);
|
explicit Thread(KernelCore& kernel);
|
||||||
~Thread() override;
|
~Thread() override;
|
||||||
|
@ -104,11 +104,11 @@ public:
|
||||||
|
|
||||||
using ThreadContext = Core::ARM_Interface::ThreadContext;
|
using ThreadContext = Core::ARM_Interface::ThreadContext;
|
||||||
|
|
||||||
using ThreadWaitObjects = std::vector<std::shared_ptr<WaitObject>>;
|
using ThreadSynchronizationObjects = std::vector<std::shared_ptr<SynchronizationObject>>;
|
||||||
|
|
||||||
using WakeupCallback =
|
using WakeupCallback =
|
||||||
std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<WaitObject> object, std::size_t index)>;
|
std::shared_ptr<SynchronizationObject> object, std::size_t index)>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a new thread. The new thread is immediately scheduled
|
* Creates and returns a new thread. The new thread is immediately scheduled
|
||||||
|
@ -146,6 +146,7 @@ public:
|
||||||
|
|
||||||
bool ShouldWait(const Thread* thread) const override;
|
bool ShouldWait(const Thread* thread) const override;
|
||||||
void Acquire(Thread* thread) override;
|
void Acquire(Thread* thread) override;
|
||||||
|
bool IsSignaled() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the thread's current priority
|
* Gets the thread's current priority
|
||||||
|
@ -233,7 +234,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param object Object to query the index of.
|
* @param object Object to query the index of.
|
||||||
*/
|
*/
|
||||||
s32 GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const;
|
s32 GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops a thread, invalidating it from further use
|
* Stops a thread, invalidating it from further use
|
||||||
|
@ -314,15 +315,15 @@ public:
|
||||||
return owner_process;
|
return owner_process;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ThreadWaitObjects& GetWaitObjects() const {
|
const ThreadSynchronizationObjects& GetSynchronizationObjects() const {
|
||||||
return wait_objects;
|
return wait_objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetWaitObjects(ThreadWaitObjects objects) {
|
void SetSynchronizationObjects(ThreadSynchronizationObjects objects) {
|
||||||
wait_objects = std::move(objects);
|
wait_objects = std::move(objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearWaitObjects() {
|
void ClearSynchronizationObjects() {
|
||||||
for (const auto& waiting_object : wait_objects) {
|
for (const auto& waiting_object : wait_objects) {
|
||||||
waiting_object->RemoveWaitingThread(SharedFrom(this));
|
waiting_object->RemoveWaitingThread(SharedFrom(this));
|
||||||
}
|
}
|
||||||
|
@ -330,7 +331,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether all the objects this thread is waiting on are ready.
|
/// Determines whether all the objects this thread is waiting on are ready.
|
||||||
bool AllWaitObjectsReady() const;
|
bool AllSynchronizationObjectsReady() const;
|
||||||
|
|
||||||
const MutexWaitingThreads& GetMutexWaitingThreads() const {
|
const MutexWaitingThreads& GetMutexWaitingThreads() const {
|
||||||
return wait_mutex_threads;
|
return wait_mutex_threads;
|
||||||
|
@ -395,7 +396,7 @@ public:
|
||||||
* will cause an assertion to trigger.
|
* will cause an assertion to trigger.
|
||||||
*/
|
*/
|
||||||
bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<WaitObject> object, std::size_t index);
|
std::shared_ptr<SynchronizationObject> object, std::size_t index);
|
||||||
|
|
||||||
u32 GetIdealCore() const {
|
u32 GetIdealCore() const {
|
||||||
return ideal_core;
|
return ideal_core;
|
||||||
|
@ -494,7 +495,7 @@ private:
|
||||||
|
|
||||||
/// Objects that the thread is waiting on, in the same order as they were
|
/// Objects that the thread is waiting on, in the same order as they were
|
||||||
/// passed to WaitSynchronization.
|
/// passed to WaitSynchronization.
|
||||||
ThreadWaitObjects wait_objects;
|
ThreadSynchronizationObjects wait_objects;
|
||||||
|
|
||||||
/// List of threads that are waiting for a mutex that is held by this thread.
|
/// List of threads that are waiting for a mutex that is held by this thread.
|
||||||
MutexWaitingThreads wait_mutex_threads;
|
MutexWaitingThreads wait_mutex_threads;
|
||||||
|
|
|
@ -22,7 +22,6 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) {
|
||||||
writable_event->name = name + ":Writable";
|
writable_event->name = name + ":Writable";
|
||||||
writable_event->readable = readable_event;
|
writable_event->readable = readable_event;
|
||||||
readable_event->name = name + ":Readable";
|
readable_event->name = name + ":Readable";
|
||||||
readable_event->signaled = false;
|
|
||||||
|
|
||||||
return {std::move(readable_event), std::move(writable_event)};
|
return {std::move(readable_event), std::move(writable_event)};
|
||||||
}
|
}
|
||||||
|
@ -40,7 +39,7 @@ void WritableEvent::Clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WritableEvent::IsSignaled() const {
|
bool WritableEvent::IsSignaled() const {
|
||||||
return readable->signaled;
|
return readable->IsSignaled();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "core/frontend/input.h"
|
#include "core/frontend/input.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
|
@ -37,11 +38,11 @@ namespace Service::HID {
|
||||||
|
|
||||||
// Updating period for each HID device.
|
// Updating period for each HID device.
|
||||||
// TODO(ogniK): Find actual polling rate of hid
|
// TODO(ogniK): Find actual polling rate of hid
|
||||||
constexpr s64 pad_update_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 66);
|
constexpr s64 pad_update_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 66);
|
||||||
[[maybe_unused]] constexpr s64 accelerometer_update_ticks =
|
[[maybe_unused]] constexpr s64 accelerometer_update_ticks =
|
||||||
static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100);
|
static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100);
|
||||||
[[maybe_unused]] constexpr s64 gyroscope_update_ticks =
|
[[maybe_unused]] constexpr s64 gyroscope_update_ticks =
|
||||||
static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 100);
|
static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 100);
|
||||||
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
|
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
|
||||||
|
|
||||||
IAppletResource::IAppletResource(Core::System& system)
|
IAppletResource::IAppletResource(Core::System& system)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
|
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
|
||||||
|
@ -26,8 +27,8 @@
|
||||||
|
|
||||||
namespace Service::NVFlinger {
|
namespace Service::NVFlinger {
|
||||||
|
|
||||||
constexpr s64 frame_ticks = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
|
constexpr s64 frame_ticks = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 60);
|
||||||
constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 30);
|
constexpr s64 frame_ticks_30fps = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 30);
|
||||||
|
|
||||||
NVFlinger::NVFlinger(Core::System& system) : system(system) {
|
NVFlinger::NVFlinger(Core::System& system) : system(system) {
|
||||||
displays.emplace_back(0, "Default", system);
|
displays.emplace_back(0, "Default", system);
|
||||||
|
@ -222,7 +223,7 @@ void NVFlinger::Compose() {
|
||||||
|
|
||||||
s64 NVFlinger::GetNextTicks() const {
|
s64 NVFlinger::GetNextTicks() const {
|
||||||
constexpr s64 max_hertz = 120LL;
|
constexpr s64 max_hertz = 120LL;
|
||||||
return (Core::Timing::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz;
|
return (Core::Hardware::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::NVFlinger
|
} // namespace Service::NVFlinger
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/service/time/standard_steady_clock_core.h"
|
#include "core/hle/service/time/standard_steady_clock_core.h"
|
||||||
|
|
||||||
namespace Service::Time::Clock {
|
namespace Service::Time::Clock {
|
||||||
|
@ -12,7 +13,7 @@ namespace Service::Time::Clock {
|
||||||
TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
|
TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
|
||||||
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
|
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
|
||||||
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
Core::Timing::CNTFREQ)};
|
Core::Hardware::CNTFREQ)};
|
||||||
TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
|
TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
|
||||||
|
|
||||||
if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
|
if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/service/time/tick_based_steady_clock_core.h"
|
#include "core/hle/service/time/tick_based_steady_clock_core.h"
|
||||||
|
|
||||||
namespace Service::Time::Clock {
|
namespace Service::Time::Clock {
|
||||||
|
@ -12,7 +13,7 @@ namespace Service::Time::Clock {
|
||||||
SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
|
SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
|
||||||
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
|
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
|
||||||
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
Core::Timing::CNTFREQ)};
|
Core::Hardware::CNTFREQ)};
|
||||||
|
|
||||||
return {ticks_time_span.ToSeconds(), GetClockSourceId()};
|
return {ticks_time_span.ToSeconds(), GetClockSourceId()};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
|
@ -233,7 +234,7 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe
|
||||||
if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
|
if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
|
||||||
const auto ticks{Clock::TimeSpanType::FromTicks(
|
const auto ticks{Clock::TimeSpanType::FromTicks(
|
||||||
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
Core::Timing::CNTFREQ)};
|
Core::Hardware::CNTFREQ)};
|
||||||
const s64 base_time_point{context.offset + current_time_point.time_point -
|
const s64 base_time_point{context.offset + current_time_point.time_point -
|
||||||
ticks.ToSeconds()};
|
ticks.ToSeconds()};
|
||||||
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
|
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/service/time/clock_types.h"
|
#include "core/hle/service/time/clock_types.h"
|
||||||
#include "core/hle/service/time/steady_clock_core.h"
|
#include "core/hle/service/time/steady_clock_core.h"
|
||||||
#include "core/hle/service/time/time_sharedmemory.h"
|
#include "core/hle/service/time/time_sharedmemory.h"
|
||||||
|
@ -31,7 +32,7 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system,
|
||||||
Clock::TimeSpanType current_time_point) {
|
Clock::TimeSpanType current_time_point) {
|
||||||
const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
|
const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
|
||||||
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
Core::Timing::CNTFREQ)};
|
Core::Hardware::CNTFREQ)};
|
||||||
const Clock::SteadyClockContext context{
|
const Clock::SteadyClockContext context{
|
||||||
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
|
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
|
||||||
clock_source_id};
|
clock_source_id};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/service/hid/controllers/npad.h"
|
#include "core/hle/service/hid/controllers/npad.h"
|
||||||
#include "core/hle/service/hid/hid.h"
|
#include "core/hle/service/hid/hid.h"
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
|
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
|
||||||
constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12);
|
constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 12);
|
||||||
constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
|
constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
|
||||||
|
|
||||||
StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
|
StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
|
||||||
|
|
|
@ -7,13 +7,14 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/core_timing_util.h"
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hardware_properties.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/tools/freezer.h"
|
#include "core/tools/freezer.h"
|
||||||
|
|
||||||
namespace Tools {
|
namespace Tools {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
|
constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Hardware::BASE_CLOCK_RATE / 60);
|
||||||
|
|
||||||
u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
|
u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) {
|
||||||
switch (width) {
|
switch (width) {
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
|
#include "core/hle/kernel/synchronization_object.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
WaitTreeItem::WaitTreeItem() = default;
|
WaitTreeItem::WaitTreeItem() = default;
|
||||||
|
@ -133,8 +133,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {}
|
WaitTreeSynchronizationObject::WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& o)
|
||||||
WaitTreeWaitObject::~WaitTreeWaitObject() = default;
|
: object(o) {}
|
||||||
|
WaitTreeSynchronizationObject::~WaitTreeSynchronizationObject() = default;
|
||||||
|
|
||||||
WaitTreeExpandableItem::WaitTreeExpandableItem() = default;
|
WaitTreeExpandableItem::WaitTreeExpandableItem() = default;
|
||||||
WaitTreeExpandableItem::~WaitTreeExpandableItem() = default;
|
WaitTreeExpandableItem::~WaitTreeExpandableItem() = default;
|
||||||
|
@ -143,25 +144,26 @@ bool WaitTreeExpandableItem::IsExpandable() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WaitTreeWaitObject::GetText() const {
|
QString WaitTreeSynchronizationObject::GetText() const {
|
||||||
return tr("[%1]%2 %3")
|
return tr("[%1]%2 %3")
|
||||||
.arg(object.GetObjectId())
|
.arg(object.GetObjectId())
|
||||||
.arg(QString::fromStdString(object.GetTypeName()),
|
.arg(QString::fromStdString(object.GetTypeName()),
|
||||||
QString::fromStdString(object.GetName()));
|
QString::fromStdString(object.GetName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) {
|
std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
|
||||||
|
const Kernel::SynchronizationObject& object) {
|
||||||
switch (object.GetHandleType()) {
|
switch (object.GetHandleType()) {
|
||||||
case Kernel::HandleType::ReadableEvent:
|
case Kernel::HandleType::ReadableEvent:
|
||||||
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
|
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
|
||||||
case Kernel::HandleType::Thread:
|
case Kernel::HandleType::Thread:
|
||||||
return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object));
|
return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object));
|
||||||
default:
|
default:
|
||||||
return std::make_unique<WaitTreeWaitObject>(object);
|
return std::make_unique<WaitTreeSynchronizationObject>(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() const {
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> list;
|
std::vector<std::unique_ptr<WaitTreeItem>> list;
|
||||||
|
|
||||||
const auto& threads = object.GetWaitingThreads();
|
const auto& threads = object.GetWaitingThreads();
|
||||||
|
@ -173,8 +175,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() con
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeObjectList::WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::WaitObject>>& list,
|
WaitTreeObjectList::WaitTreeObjectList(
|
||||||
bool w_all)
|
const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list, bool w_all)
|
||||||
: object_list(list), wait_all(w_all) {}
|
: object_list(list), wait_all(w_all) {}
|
||||||
|
|
||||||
WaitTreeObjectList::~WaitTreeObjectList() = default;
|
WaitTreeObjectList::~WaitTreeObjectList() = default;
|
||||||
|
@ -188,11 +190,12 @@ QString WaitTreeObjectList::GetText() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const {
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size());
|
std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size());
|
||||||
std::transform(object_list.begin(), object_list.end(), list.begin(),
|
std::transform(object_list.begin(), object_list.end(), list.begin(),
|
||||||
[](const auto& t) { return WaitTreeWaitObject::make(*t); });
|
[](const auto& t) { return WaitTreeSynchronizationObject::make(*t); });
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) : WaitTreeWaitObject(thread) {}
|
WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread)
|
||||||
|
: WaitTreeSynchronizationObject(thread) {}
|
||||||
WaitTreeThread::~WaitTreeThread() = default;
|
WaitTreeThread::~WaitTreeThread() = default;
|
||||||
|
|
||||||
QString WaitTreeThread::GetText() const {
|
QString WaitTreeThread::GetText() const {
|
||||||
|
@ -241,7 +244,8 @@ QString WaitTreeThread::GetText() const {
|
||||||
const QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
|
const QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
|
||||||
.arg(context.pc, 8, 16, QLatin1Char{'0'})
|
.arg(context.pc, 8, 16, QLatin1Char{'0'})
|
||||||
.arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'});
|
.arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'});
|
||||||
return QStringLiteral("%1%2 (%3) ").arg(WaitTreeWaitObject::GetText(), pc_info, status);
|
return QStringLiteral("%1%2 (%3) ")
|
||||||
|
.arg(WaitTreeSynchronizationObject::GetText(), pc_info, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor WaitTreeThread::GetColor() const {
|
QColor WaitTreeThread::GetColor() const {
|
||||||
|
@ -273,7 +277,7 @@ QColor WaitTreeThread::GetColor() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
|
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren());
|
||||||
|
|
||||||
const auto& thread = static_cast<const Kernel::Thread&>(object);
|
const auto& thread = static_cast<const Kernel::Thread&>(object);
|
||||||
|
|
||||||
|
@ -314,7 +318,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
|
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
|
||||||
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(),
|
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetSynchronizationObjects(),
|
||||||
thread.IsSleepingOnWait()));
|
thread.IsSleepingOnWait()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +327,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {}
|
WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object)
|
||||||
|
: WaitTreeSynchronizationObject(object) {}
|
||||||
WaitTreeEvent::~WaitTreeEvent() = default;
|
WaitTreeEvent::~WaitTreeEvent() = default;
|
||||||
|
|
||||||
WaitTreeThreadList::WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list)
|
WaitTreeThreadList::WaitTreeThreadList(const std::vector<std::shared_ptr<Kernel::Thread>>& list)
|
||||||
|
|
|
@ -19,7 +19,7 @@ class EmuThread;
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class HandleTable;
|
class HandleTable;
|
||||||
class ReadableEvent;
|
class ReadableEvent;
|
||||||
class WaitObject;
|
class SynchronizationObject;
|
||||||
class Thread;
|
class Thread;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
@ -99,35 +99,37 @@ private:
|
||||||
const Kernel::Thread& thread;
|
const Kernel::Thread& thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeWaitObject : public WaitTreeExpandableItem {
|
class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeWaitObject(const Kernel::WaitObject& object);
|
explicit WaitTreeSynchronizationObject(const Kernel::SynchronizationObject& object);
|
||||||
~WaitTreeWaitObject() override;
|
~WaitTreeSynchronizationObject() override;
|
||||||
|
|
||||||
static std::unique_ptr<WaitTreeWaitObject> make(const Kernel::WaitObject& object);
|
static std::unique_ptr<WaitTreeSynchronizationObject> make(
|
||||||
|
const Kernel::SynchronizationObject& object);
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const Kernel::WaitObject& object;
|
const Kernel::SynchronizationObject& object;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeObjectList : public WaitTreeExpandableItem {
|
class WaitTreeObjectList : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::WaitObject>>& list, bool wait_all);
|
WaitTreeObjectList(const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& list,
|
||||||
|
bool wait_all);
|
||||||
~WaitTreeObjectList() override;
|
~WaitTreeObjectList() override;
|
||||||
|
|
||||||
QString GetText() const override;
|
QString GetText() const override;
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<std::shared_ptr<Kernel::WaitObject>>& object_list;
|
const std::vector<std::shared_ptr<Kernel::SynchronizationObject>>& object_list;
|
||||||
bool wait_all;
|
bool wait_all;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeThread : public WaitTreeWaitObject {
|
class WaitTreeThread : public WaitTreeSynchronizationObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeThread(const Kernel::Thread& thread);
|
explicit WaitTreeThread(const Kernel::Thread& thread);
|
||||||
|
@ -138,7 +140,7 @@ public:
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeEvent : public WaitTreeWaitObject {
|
class WaitTreeEvent : public WaitTreeSynchronizationObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WaitTreeEvent(const Kernel::ReadableEvent& object);
|
explicit WaitTreeEvent(const Kernel::ReadableEvent& object);
|
||||||
|
|
Loading…
Reference in New Issue