From b6a68e8d510610e181d638ff993e327059bd6018 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Dec 2023 23:36:07 -0800 Subject: Remove some unnecessary atomic wrappers --- common/atomic.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'common/atomic.h') diff --git a/common/atomic.h b/common/atomic.h index 5e9b04c6..a579dcab 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -4,15 +4,12 @@ #include -using RefCount = std::atomic; - -inline void InitRef(RefCount &ref, unsigned int value) -{ ref.store(value, std::memory_order_relaxed); } -inline unsigned int ReadRef(RefCount &ref) -{ return ref.load(std::memory_order_acquire); } -inline unsigned int IncrementRef(RefCount &ref) +template +auto IncrementRef(std::atomic &ref) noexcept { return ref.fetch_add(1u, std::memory_order_acq_rel)+1u; } -inline unsigned int DecrementRef(RefCount &ref) + +template +auto DecrementRef(std::atomic &ref) noexcept { return ref.fetch_sub(1u, std::memory_order_acq_rel)-1u; } -- cgit v1.2.3 From aa23d619324ca7e9d51829a2cc5d276c98305eb9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jan 2024 10:53:52 -0800 Subject: Make and use a (simple) atomic unique_ptr --- common/atomic.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ core/context.cpp | 4 ++-- core/context.h | 2 +- 3 files changed, 69 insertions(+), 3 deletions(-) (limited to 'common/atomic.h') diff --git a/common/atomic.h b/common/atomic.h index a579dcab..51ddaa5d 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -2,7 +2,9 @@ #define AL_ATOMIC_H #include +#include +#include "almalloc.h" template auto IncrementRef(std::atomic &ref) noexcept @@ -27,4 +29,68 @@ inline void AtomicReplaceHead(std::atomic &head, T newhead) std::memory_order_acq_rel, std::memory_order_acquire)); } +namespace al { + +template> +class atomic_unique_ptr { + std::atomic> mPointer{}; + +public: + atomic_unique_ptr() = default; + atomic_unique_ptr(const atomic_unique_ptr&) = delete; + explicit atomic_unique_ptr(std::nullptr_t) noexcept { } + explicit atomic_unique_ptr(gsl::owner ptr) noexcept : mPointer{ptr} { } + explicit atomic_unique_ptr(std::unique_ptr&& rhs) noexcept : mPointer{rhs.release()} { } + ~atomic_unique_ptr() { if(auto ptr = mPointer.load(std::memory_order_relaxed)) D{}(ptr); } + + atomic_unique_ptr& operator=(const atomic_unique_ptr&) = delete; + atomic_unique_ptr& operator=(std::nullptr_t) noexcept + { + if(auto ptr = mPointer.exchange(nullptr)) + D{}(ptr); + return *this; + } + atomic_unique_ptr& operator=(std::unique_ptr&& rhs) noexcept + { + if(auto ptr = mPointer.exchange(rhs.release())) + D{}(ptr); + return *this; + } + + [[nodiscard]] + T* load(std::memory_order m=std::memory_order_seq_cst) const { return mPointer.load(m); } + void store(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept + { + if(auto oldptr = mPointer.exchange(nullptr, m)) + D{}(oldptr); + } + void store(gsl::owner ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { + if(auto oldptr = mPointer.exchange(ptr, m)) + D{}(oldptr); + } + void store(std::unique_ptr&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { + if(auto oldptr = mPointer.exchange(ptr.release(), m)) + D{}(oldptr); + } + + [[nodiscard]] + std::unique_ptr exchange(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept + { return std::unique_ptr{mPointer.exchange(nullptr, m)}; } + [[nodiscard]] + std::unique_ptr exchange(gsl::owner ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { return std::unique_ptr{mPointer.exchange(ptr, m)}; } + [[nodiscard]] + std::unique_ptr exchange(std::unique_ptr&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + { return std::unique_ptr{mPointer.exchange(ptr.release(), m)}; } + + [[nodiscard]] + bool is_lock_free() const noexcept { mPointer.is_lock_free(); } + + static constexpr auto is_always_lock_free = std::atomic>::is_always_lock_free; +}; + +} // namespace al + #endif /* AL_ATOMIC_H */ diff --git a/core/context.cpp b/core/context.cpp index b969583b..cb00ae70 100644 --- a/core/context.cpp +++ b/core/context.cpp @@ -52,7 +52,7 @@ ContextBase::~ContextBase() if(std::unique_ptr curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)}) std::destroy_n(curarray->end(), curarray->size()); - std::unique_ptr{mVoices.exchange(nullptr, std::memory_order_relaxed)}; + mVoices.store(nullptr, std::memory_order_relaxed); if(mAsyncEvents) { @@ -142,7 +142,7 @@ void ContextBase::allocVoices(size_t addcount) voice_iter = std::transform(cluster->begin(), cluster->end(), voice_iter, [](Voice &voice) noexcept -> Voice* { return &voice; }); - if(std::unique_ptr oldvoices{mVoices.exchange(newarray.release(), std::memory_order_acq_rel)}) + if(auto oldvoices = mVoices.exchange(std::move(newarray), std::memory_order_acq_rel)) std::ignore = mDevice->waitForMix(); } diff --git a/core/context.h b/core/context.h index 0b830205..6fc1ed5d 100644 --- a/core/context.h +++ b/core/context.h @@ -112,7 +112,7 @@ struct ContextBase { ContextParams mParams; using VoiceArray = al::FlexArray; - std::atomic mVoices{}; + al::atomic_unique_ptr mVoices{}; std::atomic mActiveVoiceCount{}; void allocVoices(size_t addcount); -- cgit v1.2.3 From 69ac4a4a9d9e0bc8a62b09d939e2a67f83e5544d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Jan 2024 03:26:37 -0800 Subject: Use an atomic exchange to destruct the atomic unique_ptr A relaxed load isn't required to synchronize with other threads. A thread could exchange the held pointer, and a subsequent load is allowed to get either the pre- or post-swap value (it's only required the value be "complete", not junk or some mix of the old and new value). An exchange, however, is guaranteed to synchronize with itself. If an atomic variable has the value 0, for example, with one thread swapping in the value 1 and another the value 2, the two threads are guaranteed to not both get 0 from the swap. --- common/atomic.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'common/atomic.h') diff --git a/common/atomic.h b/common/atomic.h index 51ddaa5d..8e75cb0e 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -41,7 +41,11 @@ public: explicit atomic_unique_ptr(std::nullptr_t) noexcept { } explicit atomic_unique_ptr(gsl::owner ptr) noexcept : mPointer{ptr} { } explicit atomic_unique_ptr(std::unique_ptr&& rhs) noexcept : mPointer{rhs.release()} { } - ~atomic_unique_ptr() { if(auto ptr = mPointer.load(std::memory_order_relaxed)) D{}(ptr); } + ~atomic_unique_ptr() + { + if(auto ptr = mPointer.exchange(nullptr, std::memory_order_relaxed)) + D{}(ptr); + } atomic_unique_ptr& operator=(const atomic_unique_ptr&) = delete; atomic_unique_ptr& operator=(std::nullptr_t) noexcept -- cgit v1.2.3 From 272bbc400df542dbe2ed0fe0d40112318cde0689 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Jan 2024 03:47:42 -0800 Subject: Properly handle the atomic unique_ptr type deleter --- common/atomic.h | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'common/atomic.h') diff --git a/common/atomic.h b/common/atomic.h index 8e75cb0e..4eb49598 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -35,26 +35,28 @@ template> class atomic_unique_ptr { std::atomic> mPointer{}; + using unique_ptr_t = std::unique_ptr; + public: atomic_unique_ptr() = default; atomic_unique_ptr(const atomic_unique_ptr&) = delete; explicit atomic_unique_ptr(std::nullptr_t) noexcept { } explicit atomic_unique_ptr(gsl::owner ptr) noexcept : mPointer{ptr} { } - explicit atomic_unique_ptr(std::unique_ptr&& rhs) noexcept : mPointer{rhs.release()} { } + explicit atomic_unique_ptr(unique_ptr_t&& rhs) noexcept : mPointer{rhs.release()} { } ~atomic_unique_ptr() { if(auto ptr = mPointer.exchange(nullptr, std::memory_order_relaxed)) D{}(ptr); } - atomic_unique_ptr& operator=(const atomic_unique_ptr&) = delete; - atomic_unique_ptr& operator=(std::nullptr_t) noexcept + auto operator=(const atomic_unique_ptr&) -> atomic_unique_ptr& = delete; + auto operator=(std::nullptr_t) noexcept -> atomic_unique_ptr& { if(auto ptr = mPointer.exchange(nullptr)) D{}(ptr); return *this; } - atomic_unique_ptr& operator=(std::unique_ptr&& rhs) noexcept + auto operator=(unique_ptr_t&& rhs) noexcept -> atomic_unique_ptr& { if(auto ptr = mPointer.exchange(rhs.release())) D{}(ptr); @@ -62,7 +64,8 @@ public: } [[nodiscard]] - T* load(std::memory_order m=std::memory_order_seq_cst) const { return mPointer.load(m); } + auto load(std::memory_order m=std::memory_order_seq_cst) const noexcept -> T* + { return mPointer.load(m); } void store(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept { if(auto oldptr = mPointer.exchange(nullptr, m)) @@ -73,24 +76,24 @@ public: if(auto oldptr = mPointer.exchange(ptr, m)) D{}(oldptr); } - void store(std::unique_ptr&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept + void store(unique_ptr_t&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept { if(auto oldptr = mPointer.exchange(ptr.release(), m)) D{}(oldptr); } [[nodiscard]] - std::unique_ptr exchange(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept - { return std::unique_ptr{mPointer.exchange(nullptr, m)}; } + auto exchange(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept -> unique_ptr_t + { return unique_ptr_t{mPointer.exchange(nullptr, m)}; } [[nodiscard]] - std::unique_ptr exchange(gsl::owner ptr, std::memory_order m=std::memory_order_seq_cst) noexcept - { return std::unique_ptr{mPointer.exchange(ptr, m)}; } + auto exchange(gsl::owner ptr, std::memory_order m=std::memory_order_seq_cst) noexcept -> unique_ptr_t + { return unique_ptr_t{mPointer.exchange(ptr, m)}; } [[nodiscard]] - std::unique_ptr exchange(std::unique_ptr&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept - { return std::unique_ptr{mPointer.exchange(ptr.release(), m)}; } + auto exchange(std::unique_ptr&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept -> unique_ptr_t + { return unique_ptr_t{mPointer.exchange(ptr.release(), m)}; } [[nodiscard]] - bool is_lock_free() const noexcept { mPointer.is_lock_free(); } + auto is_lock_free() const noexcept -> bool { mPointer.is_lock_free(); } static constexpr auto is_always_lock_free = std::atomic>::is_always_lock_free; }; -- cgit v1.2.3 From e90075031dfeec7ff03d5d1c5e319e7472312f46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Jan 2024 14:57:52 -0800 Subject: Add a missing return --- common/atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common/atomic.h') diff --git a/common/atomic.h b/common/atomic.h index 4eb49598..e85c4f76 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -93,7 +93,7 @@ public: { return unique_ptr_t{mPointer.exchange(ptr.release(), m)}; } [[nodiscard]] - auto is_lock_free() const noexcept -> bool { mPointer.is_lock_free(); } + auto is_lock_free() const noexcept -> bool { return mPointer.is_lock_free(); } static constexpr auto is_always_lock_free = std::atomic>::is_always_lock_free; }; -- cgit v1.2.3