aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/atomic.h66
-rw-r--r--core/context.cpp4
-rw-r--r--core/context.h2
3 files changed, 69 insertions, 3 deletions
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 <atomic>
+#include <memory>
+#include "almalloc.h"
template<typename T>
auto IncrementRef(std::atomic<T> &ref) noexcept
@@ -27,4 +29,68 @@ inline void AtomicReplaceHead(std::atomic<T> &head, T newhead)
std::memory_order_acq_rel, std::memory_order_acquire));
}
+namespace al {
+
+template<typename T, typename D=std::default_delete<T>>
+class atomic_unique_ptr {
+ std::atomic<gsl::owner<T*>> 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<T*> ptr) noexcept : mPointer{ptr} { }
+ explicit atomic_unique_ptr(std::unique_ptr<T>&& 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<T>&& 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<T*> 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<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<T> exchange(std::nullptr_t, std::memory_order m=std::memory_order_seq_cst) noexcept
+ { return std::unique_ptr<T>{mPointer.exchange(nullptr, m)}; }
+ [[nodiscard]]
+ std::unique_ptr<T> exchange(gsl::owner<T*> ptr, std::memory_order m=std::memory_order_seq_cst) noexcept
+ { return std::unique_ptr<T>{mPointer.exchange(ptr, m)}; }
+ [[nodiscard]]
+ std::unique_ptr<T> exchange(std::unique_ptr<T>&& ptr, std::memory_order m=std::memory_order_seq_cst) noexcept
+ { return std::unique_ptr<T>{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<gsl::owner<T*>>::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<EffectSlotArray> curarray{mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)})
std::destroy_n(curarray->end(), curarray->size());
- std::unique_ptr<ContextBase::VoiceArray>{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<ContextBase::VoiceArray> 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<Voice*>;
- std::atomic<VoiceArray*> mVoices{};
+ al::atomic_unique_ptr<VoiceArray> mVoices{};
std::atomic<size_t> mActiveVoiceCount{};
void allocVoices(size_t addcount);