summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar liamwhite2022-12-25 12:50:57 -0500
committerGravatar GitHub2022-12-25 12:50:57 -0500
commitea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3 (patch)
tree20348584375937e8af401cdd7a48e2878ed55c4c /src
parentMerge pull request #9453 from ameerj/scratch-vector (diff)
parenttime: add LockFreeAtomicType (diff)
downloadyuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar.gz
yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.tar.xz
yuzu-ea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3.zip
Merge pull request #9487 from liamwhite/look-at-the-time
time: add LockFreeAtomicType
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/time/clock_types.h1
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp17
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h87
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 {
49static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size"); 49static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size");
50static_assert(std::is_trivially_copyable_v<SteadyClockContext>, 50static_assert(std::is_trivially_copyable_v<SteadyClockContext>,
51 "SteadyClockContext must be trivially copyable"); 51 "SteadyClockContext must be trivially copyable");
52using StandardSteadyClockTimePointType = SteadyClockContext;
52 53
53struct SystemClockContext { 54struct SystemClockContext {
54 s64 offset; 55 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,
26 const Clock::SteadyClockContext context{ 26 const Clock::SteadyClockContext context{
27 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), 27 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
28 clock_source_id}; 28 clock_source_id};
29 shared_memory_format.standard_steady_clock_timepoint.StoreData( 29 StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context);
30 system.Kernel().GetTimeSharedMem().GetPointer(), context);
31} 30}
32 31
33void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { 32void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
34 shared_memory_format.standard_local_system_clock_context.StoreData( 33 StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context);
35 system.Kernel().GetTimeSharedMem().GetPointer(), context);
36} 34}
37 35
38void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { 36void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
39 shared_memory_format.standard_network_system_clock_context.StoreData( 37 StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context);
40 system.Kernel().GetTimeSharedMem().GetPointer(), context);
41} 38}
42 39
43void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { 40void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
44 shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( 41 StoreToLockFreeAtomicType(
45 system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled); 42 &GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled);
43}
44
45SharedMemory::Format* SharedMemory::GetFormat() {
46 return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer());
46} 47}
47 48
48} // namespace Service::Time 49} // 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 @@
10 10
11namespace Service::Time { 11namespace Service::Time {
12 12
13// Note: this type is not safe for concurrent writes.
14template <typename T>
15struct LockFreeAtomicType {
16 u32 counter_;
17 std::array<T, 2> value_;
18};
19
20template <typename T>
21static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) {
22 // Get the current counter.
23 auto counter = p->counter_;
24
25 // Increment the counter.
26 ++counter;
27
28 // Store the updated value.
29 p->value_[counter % 2] = value;
30
31 // Fence memory.
32 std::atomic_thread_fence(std::memory_order_release);
33
34 // Set the updated counter.
35 p->counter_ = counter;
36}
37
38template <typename T>
39static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) {
40 while (true) {
41 // Get the counter.
42 auto counter = p->counter_;
43
44 // Get the value.
45 auto value = p->value_[counter % 2];
46
47 // Fence memory.
48 std::atomic_thread_fence(std::memory_order_acquire);
49
50 // Check that the counter matches.
51 if (counter == p->counter_) {
52 return value;
53 }
54 }
55}
56
13class SharedMemory final { 57class SharedMemory final {
14public: 58public:
15 explicit SharedMemory(Core::System& system_); 59 explicit SharedMemory(Core::System& system_);
16 ~SharedMemory(); 60 ~SharedMemory();
17 61
18 // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
19 template <typename T, std::size_t Offset>
20 struct MemoryBarrier {
21 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
22 u32_le read_attempt{};
23 std::array<T, 2> data{};
24
25 // These are not actually memory barriers at the moment as we don't have multicore and all
26 // HLE is mutexed. This will need to properly be implemented when we start updating the time
27 // points on threads. As of right now, we'll be updated both values synchronously and just
28 // incrementing the read_attempt to indicate that we waited.
29 void StoreData(u8* shared_memory, T data_to_store) {
30 std::memcpy(this, shared_memory + Offset, sizeof(*this));
31 read_attempt++;
32 data[read_attempt & 1] = data_to_store;
33 std::memcpy(shared_memory + Offset, this, sizeof(*this));
34 }
35
36 // For reading we're just going to read the last stored value. If there was no value stored
37 // it will just end up reading an empty value as intended.
38 T ReadData(u8* shared_memory) {
39 std::memcpy(this, shared_memory + Offset, sizeof(*this));
40 return data[(read_attempt - 1) & 1];
41 }
42 };
43
44 // Shared memory format 62 // Shared memory format
45 struct Format { 63 struct Format {
46 MemoryBarrier<Clock::SteadyClockContext, 0x0> standard_steady_clock_timepoint; 64 LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint;
47 MemoryBarrier<Clock::SystemClockContext, 0x38> standard_local_system_clock_context; 65 LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context;
48 MemoryBarrier<Clock::SystemClockContext, 0x80> standard_network_system_clock_context; 66 LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context;
49 MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction; 67 LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled;
50 u32_le format_version; 68 u32 format_version;
51 }; 69 };
70 static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0);
71 static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38);
72 static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80);
73 static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) ==
74 0xc8);
52 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); 75 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
53 76
54 void SetupStandardSteadyClock(const Common::UUID& clock_source_id, 77 void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
@@ -56,10 +79,10 @@ public:
56 void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context); 79 void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
57 void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context); 80 void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
58 void SetAutomaticCorrectionEnabled(bool is_enabled); 81 void SetAutomaticCorrectionEnabled(bool is_enabled);
82 Format* GetFormat();
59 83
60private: 84private:
61 Core::System& system; 85 Core::System& system;
62 Format shared_memory_format{};
63}; 86};
64 87
65} // namespace Service::Time 88} // namespace Service::Time