diff options
-rw-r--r-- | .clang-tidy | 1 | ||||
-rw-r--r-- | deimos/core/BUILD | 1 | ||||
-rw-r--r-- | deimos/core/atomic.h | 51 | ||||
-rw-r--r-- | deimos/core/status.cpp | 27 | ||||
-rw-r--r-- | deimos/core/status.h | 12 |
5 files changed, 76 insertions, 16 deletions
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<typename T> struct Atomic { T value{}; };
+
+inline void AtomicFence(MemoryOrder order)
+{
+ __atomic_thread_fence((int)order);
+}
+
+template<typename T>
+inline void AtomicStore(Atomic<T>* a, T value, MemoryOrder order = MemoryOrder::kRelaxed)
+{
+ __atomic_store(&a->value, &value, (int)order);
+}
+
+template<typename T>
+inline T AtomicLoad(Atomic<T>* a, MemoryOrder order = MemoryOrder::kRelaxed)
+{
+ T value;
+ __atomic_load(&a->value, &value, (int)order);
+ return value;
+}
+
+template<typename T>
+inline T AtomicFetchIncrement(Atomic<T>* a, MemoryOrder order = MemoryOrder::kRelaxed)
+{
+ return __atomic_fetch_add(&a->value, 1, (int)order);
+}
+
+template<typename T>
+inline T AtomicFetchDecrement(Atomic<T>* 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<int32_t> 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<StatusRep*>(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<StatusRep*>(m_rep)->code;
+}
+
void Status::Unref() const
{
if (!IsInline())
{
auto* rep = std::bit_cast<StatusRep*>(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<StatusRep>);
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<StatusRep*>(m_rep)->code;
+ return RepCode();
}
};
|