summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorliamwhite <liamwhite@users.noreply.github.com>2022-12-25 18:50:57 +0100
committerGitHub <noreply@github.com>2022-12-25 18:50:57 +0100
commitea70d9c79e8eafe7e59a88dcb29d85c1a53fa9f3 (patch)
tree20348584375937e8af401cdd7a48e2878ed55c4c /src
parentMerge pull request #9453 from ameerj/scratch-vector (diff)
parenttime: add LockFreeAtomicType (diff)
downloadyuzu-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.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 {
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