Merge pull request #3401 from FernandoS27/synchronization
Set of refactors for Kernel Synchronization and Hardware Constants
This commit is contained in:
		| @@ -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; | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								src/core/hardware_properties.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/core/hardware_properties.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										87
									
								
								src/core/hle/kernel/synchronization.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/core/hle/kernel/synchronization.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
							
								
								
									
										44
									
								
								src/core/hle/kernel/synchronization.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/core/hle/kernel/synchronization.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user