From 10ec28c5de9442fe93635ae76ca397d138f9e93c Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Sat, 13 Apr 2024 01:41:13 +0200 Subject: Add atomics --- .clang-tidy | 1 + deimos/core/BUILD | 1 + deimos/core/atomic.h | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ deimos/core/status.cpp | 27 +++++++++++++++++++------- deimos/core/status.h | 12 +++--------- 5 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 deimos/core/atomic.h diff --git a/.clang-tidy b/.clang-tidy index bdee056..c8c8c55 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -23,3 +23,4 @@ Checks: - "-*-reinterpret-cast" - "-*-noexcept-move" - "-*-noexcept-move-constructor" + - "-*-noexcept-move-operations" diff --git a/deimos/core/BUILD b/deimos/core/BUILD index e4bfee8..84ed375 100644 --- a/deimos/core/BUILD +++ b/deimos/core/BUILD @@ -3,6 +3,7 @@ cc_library( hdrs = [ "allocator.h", "api_registry.h", + "atomic.h", "base.h", "gsl.h", "hash.h", diff --git a/deimos/core/atomic.h b/deimos/core/atomic.h new file mode 100644 index 0000000..c3d7947 --- /dev/null +++ b/deimos/core/atomic.h @@ -0,0 +1,51 @@ +#pragma once + +#include "deimos/core/base.h" + +namespace deimos +{ + +enum class MemoryOrder : int +{ + kRelaxed = __ATOMIC_RELAXED, + kAcquire = __ATOMIC_ACQUIRE, + kRelease = __ATOMIC_RELEASE, + kAcqRel = __ATOMIC_ACQ_REL, + kSeqCst = __ATOMIC_SEQ_CST, +}; + +template struct Atomic { T value{}; }; + +inline void AtomicFence(MemoryOrder order) +{ + __atomic_thread_fence((int)order); +} + +template +inline void AtomicStore(Atomic* a, T value, MemoryOrder order = MemoryOrder::kRelaxed) +{ + __atomic_store(&a->value, &value, (int)order); +} + +template +inline T AtomicLoad(Atomic* a, MemoryOrder order = MemoryOrder::kRelaxed) +{ + T value; + __atomic_load(&a->value, &value, (int)order); + return value; +} + +template +inline T AtomicFetchIncrement(Atomic* a, MemoryOrder order = MemoryOrder::kRelaxed) +{ + return __atomic_fetch_add(&a->value, 1, (int)order); +} + +template +inline T AtomicFetchDecrement(Atomic* a, MemoryOrder order = MemoryOrder::kRelaxed) +{ + return __atomic_fetch_sub(&a->value, 1, (int)order); +} + +} // namespace deimos + diff --git a/deimos/core/status.cpp b/deimos/core/status.cpp index ed1a665..f472aac 100644 --- a/deimos/core/status.cpp +++ b/deimos/core/status.cpp @@ -2,12 +2,20 @@ #include "deimos/core/api_registry.h" #include "deimos/core/allocator.h" +#include "deimos/core/atomic.h" static deimos::AllocatorApi* allocator_api; namespace deimos { +struct StatusRep +{ + Atomic ref_count; + StatusCode code{}; + StringView message; +}; + Status::Status(StatusCode code, StringView message) { if (code == StatusCode::kOk) @@ -23,7 +31,7 @@ Status::Status(StatusCode code, StringView message) MemoryCopy(message_ptr, message.data(), message.size()); message_ptr[message.size()] = '\0'; // NOLINT - rep->ref_count = 1; + AtomicStore(&rep->ref_count, 1); rep->code = code; rep->message = StringView(message_ptr, message.size()); @@ -38,22 +46,27 @@ void Status::Ref() const { auto* rep = std::bit_cast(m_rep); - Expects(rep->ref_count > 0); - rep->ref_count += 1; + Expects(AtomicLoad(&rep->ref_count) > 0); + AtomicFetchIncrement(&rep->ref_count); } } +StatusCode Status::RepCode() const +{ + Expects(!IsInline()); + return std::bit_cast(m_rep)->code; +} + void Status::Unref() const { if (!IsInline()) { auto* rep = std::bit_cast(m_rep); - Expects(rep->ref_count > 0); - rep->ref_count -= 1; - - if (rep->ref_count == 0) + Expects(AtomicLoad(&rep->ref_count) > 0); + if (AtomicFetchDecrement(&rep->ref_count, MemoryOrder::kRelease) == 1) { + AtomicFence(MemoryOrder::kAcquire); deimos_StaticAssert(std::is_trivially_destructible_v); allocator_api->system->Free( rep, (int64_t)sizeof(StatusRep) + rep->message.size() + 1); diff --git a/deimos/core/status.h b/deimos/core/status.h index f866182..bf34833 100644 --- a/deimos/core/status.h +++ b/deimos/core/status.h @@ -5,6 +5,7 @@ namespace deimos { +// NOLINTNEXTLINE(performance-enum-size) enum class StatusCode : uint32_t { kOk = 0, @@ -14,14 +15,6 @@ enum class StatusCode : uint32_t kInternal, }; -struct StatusRep -{ - // @Todo Make this atomic - int32_t ref_count{}; - StatusCode code{}; - StringView message; -}; - class Status { uintptr_t m_rep; @@ -38,6 +31,7 @@ class Status void Ref() const; void Unref() const; + StatusCode RepCode() const; public: constexpr Status() : Status(StatusCode::kOk) {} @@ -83,7 +77,7 @@ public: StatusCode code() const { if (IsInline()) { return (StatusCode)(m_rep >> 1U); } - return std::bit_cast(m_rep)->code; + return RepCode(); } }; -- cgit