summaryrefslogtreecommitdiff
path: root/deimos
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-04-13 01:41:13 +0200
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-04-13 01:41:13 +0200
commit10ec28c5de9442fe93635ae76ca397d138f9e93c (patch)
tree7795ff5e2b15659f78328d14338a7c033f0ffe41 /deimos
parenta6abeaaf3a68e3b7072f75acae4cfdf720ad20f4 (diff)
Add atomics
Diffstat (limited to 'deimos')
-rw-r--r--deimos/core/BUILD1
-rw-r--r--deimos/core/atomic.h51
-rw-r--r--deimos/core/status.cpp27
-rw-r--r--deimos/core/status.h12
4 files changed, 75 insertions, 16 deletions
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();
}
};