diff options
author | liamwhite <liamwhite@users.noreply.github.com> | 2022-12-25 18:50:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-25 18:50:57 +0100 |
commit | ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3 (patch) | |
tree | 20348584375937e8af401cdd7a48e2878ed55c4c /src | |
parent | Merge pull request #9453 from ameerj/scratch-vector (diff) | |
parent | time: add LockFreeAtomicType (diff) | |
download | yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar.gz yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar.bz2 yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar.lz yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar.xz yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar.zst yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/core/hle/service/time/clock_types.h | 1 | ||||
-rw-r--r-- | src/core/hle/service/time/time_sharedmemory.cpp | 17 | ||||
-rw-r--r-- | src/core/hle/service/time/time_sharedmemory.h | 87 |
3 files changed, 65 insertions, 40 deletions
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h index ef070f32f..ed1eb5b2d 100644 --- a/src/core/hle/service/time/clock_types.h +++ b/src/core/hle/service/time/clock_types.h @@ -49,6 +49,7 @@ struct SteadyClockContext { static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size"); static_assert(std::is_trivially_copyable_v<SteadyClockContext>, "SteadyClockContext must be trivially copyable"); +using StandardSteadyClockTimePointType = SteadyClockContext; struct SystemClockContext { s64 offset; diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index a3aa0e77f..ff53a7d6f 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -26,23 +26,24 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, const Clock::SteadyClockContext context{ static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), clock_source_id}; - shared_memory_format.standard_steady_clock_timepoint.StoreData( - system.Kernel().GetTimeSharedMem().GetPointer(), context); + StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context); } void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { - shared_memory_format.standard_local_system_clock_context.StoreData( - system.Kernel().GetTimeSharedMem().GetPointer(), context); + StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context); } void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { - shared_memory_format.standard_network_system_clock_context.StoreData( - system.Kernel().GetTimeSharedMem().GetPointer(), context); + StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context); } void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { - shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( - system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled); + StoreToLockFreeAtomicType( + &GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled); +} + +SharedMemory::Format* SharedMemory::GetFormat() { + return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer()); } } // namespace Service::Time diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h index 561685acd..044a4d24e 100644 --- a/src/core/hle/service/time/time_sharedmemory.h +++ b/src/core/hle/service/time/time_sharedmemory.h @@ -10,45 +10,68 @@ namespace Service::Time { +// Note: this type is not safe for concurrent writes. +template <typename T> +struct LockFreeAtomicType { + u32 counter_; + std::array<T, 2> value_; +}; + +template <typename T> +static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) { + // Get the current counter. + auto counter = p->counter_; + + // Increment the counter. + ++counter; + + // Store the updated value. + p->value_[counter % 2] = value; + + // Fence memory. + std::atomic_thread_fence(std::memory_order_release); + + // Set the updated counter. + p->counter_ = counter; +} + +template <typename T> +static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) { + while (true) { + // Get the counter. + auto counter = p->counter_; + + // Get the value. + auto value = p->value_[counter % 2]; + + // Fence memory. + std::atomic_thread_fence(std::memory_order_acquire); + + // Check that the counter matches. + if (counter == p->counter_) { + return value; + } + } +} + class SharedMemory final { public: explicit SharedMemory(Core::System& system_); ~SharedMemory(); - // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? - template <typename T, std::size_t Offset> - struct MemoryBarrier { - static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); - u32_le read_attempt{}; - std::array<T, 2> data{}; - - // These are not actually memory barriers at the moment as we don't have multicore and all - // HLE is mutexed. This will need to properly be implemented when we start updating the time - // points on threads. As of right now, we'll be updated both values synchronously and just - // incrementing the read_attempt to indicate that we waited. - void StoreData(u8* shared_memory, T data_to_store) { - std::memcpy(this, shared_memory + Offset, sizeof(*this)); - read_attempt++; - data[read_attempt & 1] = data_to_store; - std::memcpy(shared_memory + Offset, this, sizeof(*this)); - } - - // For reading we're just going to read the last stored value. If there was no value stored - // it will just end up reading an empty value as intended. - T ReadData(u8* shared_memory) { - std::memcpy(this, shared_memory + Offset, sizeof(*this)); - return data[(read_attempt - 1) & 1]; - } - }; - // Shared memory format struct Format { - MemoryBarrier<Clock::SteadyClockContext, 0x0> standard_steady_clock_timepoint; - MemoryBarrier<Clock::SystemClockContext, 0x38> standard_local_system_clock_context; - MemoryBarrier<Clock::SystemClockContext, 0x80> standard_network_system_clock_context; - MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction; - u32_le format_version; + LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint; + LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context; + LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context; + LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled; + u32 format_version; }; + static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0); + static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38); + static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80); + static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) == + 0xc8); static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); void SetupStandardSteadyClock(const Common::UUID& clock_source_id, @@ -56,10 +79,10 @@ public: void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context); void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context); void SetAutomaticCorrectionEnabled(bool is_enabled); + Format* GetFormat(); private: Core::System& system; - Format shared_memory_format{}; }; } // namespace Service::Time |