aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--al/auxeffectslot.cpp44
-rw-r--r--al/buffer.cpp8
-rw-r--r--al/event.cpp2
-rw-r--r--al/source.cpp26
-rw-r--r--alc/alc.cpp70
-rw-r--r--alc/alcmain.h5
-rw-r--r--alc/alcontext.h9
-rw-r--r--alc/alu.cpp24
-rw-r--r--alc/backends/base.cpp4
-rw-r--r--alc/effects/base.h9
-rw-r--r--alc/hrtf.cpp8
-rw-r--r--common/atomic.h16
-rw-r--r--common/intrusive_ptr.h48
14 files changed, 133 insertions, 141 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e72f2a01..5f3f9763 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -598,6 +598,7 @@ SET(COMMON_OBJS
common/aloptional.h
common/alspan.h
common/atomic.h
+ common/intrusive_ptr.h
common/math_defs.h
common/opthelpers.h
common/threads.cpp
diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp
index 2d10efde..b4e93858 100644
--- a/al/auxeffectslot.cpp
+++ b/al/auxeffectslot.cpp
@@ -320,7 +320,7 @@ START_API_FUNC
context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", id);
return true;
}
- if(ReadRef(&slot->ref) != 0)
+ if(ReadRef(slot->ref) != 0)
{
context->setError(AL_INVALID_NAME, "Deleting in-use effect slot %u", id);
return true;
@@ -418,14 +418,14 @@ START_API_FUNC
/* We must force an update if there was an existing effect slot
* target, in case it's about to be deleted.
*/
- if(target) IncrementRef(&target->ref);
- DecrementRef(&oldtarget->ref);
+ if(target) IncrementRef(target->ref);
+ DecrementRef(oldtarget->ref);
slot->Target = target;
UpdateEffectSlotProps(slot, context.get());
return;
}
- if(target) IncrementRef(&target->ref);
+ if(target) IncrementRef(target->ref);
slot->Target = target;
break;
@@ -651,7 +651,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
{
statelock.unlock();
mixer_mode.leave();
- State->DecRef();
+ State->release();
return AL_OUT_OF_MEMORY;
}
mixer_mode.leave();
@@ -667,7 +667,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
EffectSlot->Effect.Props = effect->Props;
}
- EffectSlot->Effect.State->DecRef();
+ EffectSlot->Effect.State->release();
EffectSlot->Effect.State = State;
}
else if(effect)
@@ -678,7 +678,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
while(props)
{
if(props->State)
- props->State->DecRef();
+ props->State->release();
props->State = nullptr;
props = props->next.load(std::memory_order_relaxed);
}
@@ -687,20 +687,6 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
}
-void EffectState::IncRef() noexcept
-{
- auto ref = IncrementRef(&mRef);
- TRACEREF("EffectState %p increasing refcount to %u\n", this, ref);
-}
-
-void EffectState::DecRef() noexcept
-{
- auto ref = DecrementRef(&mRef);
- TRACEREF("EffectState %p decreasing refcount to %u\n", this, ref);
- if(ref == 0) delete this;
-}
-
-
ALenum InitEffectSlot(ALeffectslot *slot)
{
EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)};
@@ -708,7 +694,7 @@ ALenum InitEffectSlot(ALeffectslot *slot)
slot->Effect.State = factory->create();
if(!slot->Effect.State) return AL_OUT_OF_MEMORY;
- slot->Effect.State->IncRef();
+ slot->Effect.State->add_ref();
slot->Params.mEffectState = slot->Effect.State;
return AL_NO_ERROR;
}
@@ -716,21 +702,21 @@ ALenum InitEffectSlot(ALeffectslot *slot)
ALeffectslot::~ALeffectslot()
{
if(Target)
- DecrementRef(&Target->ref);
+ DecrementRef(Target->ref);
Target = nullptr;
ALeffectslotProps *props{Update.load()};
if(props)
{
- if(props->State) props->State->DecRef();
+ if(props->State) props->State->release();
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
al_free(props);
}
if(Effect.State)
- Effect.State->DecRef();
+ Effect.State->release();
if(Params.mEffectState)
- Params.mEffectState->DecRef();
+ Params.mEffectState->release();
}
void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
@@ -759,7 +745,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
* delete it.
*/
EffectState *oldstate{props->State};
- slot->Effect.State->IncRef();
+ slot->Effect.State->add_ref();
props->State = slot->Effect.State;
/* Set the new container for updating internal parameters. */
@@ -770,13 +756,13 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
* freelist.
*/
if(props->State)
- props->State->DecRef();
+ props->State->release();
props->State = nullptr;
AtomicReplaceHead(context->mFreeEffectslotProps, props);
}
if(oldstate)
- oldstate->DecRef();
+ oldstate->release();
}
void UpdateAllEffectSlotProps(ALCcontext *context)
diff --git a/al/buffer.cpp b/al/buffer.cpp
index 4e843e03..173c76bd 100644
--- a/al/buffer.cpp
+++ b/al/buffer.cpp
@@ -380,7 +380,7 @@ const ALchar *NameFromUserFmtType(UserFmtType type)
*/
void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access)
{
- if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0))
+ if(UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0))
SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u",
ALBuf->id);
@@ -671,7 +671,7 @@ START_API_FUNC
context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid);
return true;
}
- if(UNLIKELY(ReadRef(&ALBuf->ref) != 0))
+ if(UNLIKELY(ReadRef(ALBuf->ref) != 0))
{
context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid);
return true;
@@ -768,7 +768,7 @@ START_API_FUNC
else
{
ALbitfieldSOFT unavailable = (albuf->Access^access) & access;
- if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)))
+ if(UNLIKELY(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)))
context->setError(AL_INVALID_OPERATION,
"Mapping in-use buffer %u without persistent mapping", buffer);
else if(UNLIKELY(albuf->MappedAccess != 0))
@@ -1126,7 +1126,7 @@ START_API_FUNC
else switch(param)
{
case AL_LOOP_POINTS_SOFT:
- if(UNLIKELY(ReadRef(&albuf->ref) != 0))
+ if(UNLIKELY(ReadRef(albuf->ref) != 0))
context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points",
buffer);
else if(UNLIKELY(values[0] < 0 || values[0] >= values[1] ||
diff --git a/al/event.cpp b/al/event.cpp
index 0d41e713..75827b59 100644
--- a/al/event.cpp
+++ b/al/event.cpp
@@ -64,7 +64,7 @@ static int EventThread(ALCcontext *context)
if(evt.EnumType == EventType_ReleaseEffectState)
{
- evt.u.mEffectState->DecRef();
+ evt.u.mEffectState->release();
continue;
}
diff --git a/al/source.cpp b/al/source.cpp
index 6708c970..1e0940de 100644
--- a/al/source.cpp
+++ b/al/source.cpp
@@ -1309,7 +1309,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co
newlist->mMaxSamples = buffer->SampleLen;
newlist->mNumBuffers = 1;
newlist->mBuffers[0] = buffer;
- IncrementRef(&buffer->ref);
+ IncrementRef(buffer->ref);
/* Source is now Static */
Source->SourceType = AL_STATIC;
@@ -1331,7 +1331,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co
std::for_each(temp->begin(), temp->end(),
[](ALbuffer *buffer) -> void
- { if(buffer) DecrementRef(&buffer->ref); });
+ { if(buffer) DecrementRef(buffer->ref); });
al_free(temp);
}
return AL_TRUE;
@@ -1475,9 +1475,9 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co
if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source))
{
/* Add refcount on the new slot, and release the previous slot */
- if(slot) IncrementRef(&slot->ref);
+ if(slot) IncrementRef(slot->ref);
if(Source->Send[values[1]].Slot)
- DecrementRef(&Source->Send[values[1]].Slot->ref);
+ DecrementRef(Source->Send[values[1]].Slot->ref);
Source->Send[values[1]].Slot = slot;
/* We must force an update if the auxiliary slot changed on an
@@ -1489,9 +1489,9 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co
}
else
{
- if(slot) IncrementRef(&slot->ref);
+ if(slot) IncrementRef(slot->ref);
if(Source->Send[values[1]].Slot)
- DecrementRef(&Source->Send[values[1]].Slot->ref);
+ DecrementRef(Source->Send[values[1]].Slot->ref);
Source->Send[values[1]].Slot = slot;
UpdateSourceProps(Source, Context);
}
@@ -3249,7 +3249,7 @@ START_API_FUNC
BufferList->mBuffers[0] = buffer;
if(!buffer) continue;
- IncrementRef(&buffer->ref);
+ IncrementRef(buffer->ref);
if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT))
{
@@ -3274,7 +3274,7 @@ START_API_FUNC
ALbufferlistitem *next = BufferListStart->mNext.load(std::memory_order_relaxed);
std::for_each(BufferListStart->begin(), BufferListStart->end(),
[](ALbuffer *buffer) -> void
- { if(buffer) DecrementRef(&buffer->ref); });
+ { if(buffer) DecrementRef(buffer->ref); });
al_free(BufferListStart);
BufferListStart = next;
}
@@ -3350,7 +3350,7 @@ START_API_FUNC
BufferList->mBuffers[BufferList->mNumBuffers++] = buffer;
if(!buffer) continue;
- IncrementRef(&buffer->ref);
+ IncrementRef(buffer->ref);
BufferList->mMaxSamples = maxu(BufferList->mMaxSamples, buffer->SampleLen);
@@ -3377,7 +3377,7 @@ START_API_FUNC
ALbufferlistitem *next{BufferListStart->mNext.load(std::memory_order_relaxed)};
std::for_each(BufferListStart->begin(), BufferListStart->end(),
[](ALbuffer *buffer) -> void
- { if(buffer) DecrementRef(&buffer->ref); });
+ { if(buffer) DecrementRef(buffer->ref); });
al_free(BufferListStart);
BufferListStart = next;
}
@@ -3460,7 +3460,7 @@ START_API_FUNC
else
{
*(buffers++) = buffer->id;
- DecrementRef(&buffer->ref);
+ DecrementRef(buffer->ref);
}
}
if(i < head->mNumBuffers)
@@ -3574,7 +3574,7 @@ ALsource::~ALsource()
ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)};
std::for_each(BufferList->begin(), BufferList->end(),
[](ALbuffer *buffer) -> void
- { if(buffer) DecrementRef(&buffer->ref); });
+ { if(buffer) DecrementRef(buffer->ref); });
al_free(BufferList);
BufferList = next;
}
@@ -3584,7 +3584,7 @@ ALsource::~ALsource()
[](ALsource::SendData &send) -> void
{
if(send.Slot)
- DecrementRef(&send.Slot->ref);
+ DecrementRef(send.Slot->ref);
send.Slot = nullptr;
}
);
diff --git a/alc/alc.cpp b/alc/alc.cpp
index 240aca6d..73723f26 100644
--- a/alc/alc.cpp
+++ b/alc/alc.cpp
@@ -79,6 +79,7 @@
#include "fpu_modes.h"
#include "hrtf.h"
#include "inprogext.h"
+#include "intrusive_ptr.h"
#include "logging.h"
#include "mastering.h"
#include "opthelpers.h"
@@ -832,9 +833,9 @@ std::atomic<ALCenum> LastNullDeviceError{ALC_NO_ERROR};
/* Thread-local current context */
void ReleaseThreadCtx(ALCcontext *context)
{
- auto ref = DecrementRef(&context->mRef);
- TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref);
- ERR("Context %p current for thread being destroyed, possible leak!\n", context);
+ const bool result{context->releaseIfNoDelete()};
+ ERR("Context %p current for thread being destroyed%s!\n", context,
+ result ? "" : ", leak detected");
}
std::atomic<void(*)(ALCcontext*)> ThreadCtxProc{ReleaseThreadCtx};
@@ -907,19 +908,6 @@ constexpr ALCint alcEFXMinorVersion = 0;
al::FlexArray<ALCcontext*> EmptyContextArray{0u};
-void ALCdevice_IncRef(ALCdevice *device)
-{
- auto ref = IncrementRef(&device->ref);
- TRACEREF("ALCdevice %p increasing refcount to %u\n", device, ref);
-}
-
-void ALCdevice_DecRef(ALCdevice *device)
-{
- auto ref = DecrementRef(&device->ref);
- TRACEREF("ALCdevice %p decreasing refcount to %u\n", device, ref);
- if(UNLIKELY(ref == 0)) delete device;
-}
-
/* Simple RAII device reference. Takes the reference of the provided ALCdevice,
* and decrements it when leaving scope. Movable (transfer reference) but not
* copyable (no new references).
@@ -930,7 +918,7 @@ class DeviceRef {
void reset() noexcept
{
if(mDev)
- ALCdevice_DecRef(mDev);
+ mDev->release();
mDev = nullptr;
}
@@ -1658,10 +1646,10 @@ static std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device,
*/
static inline void UpdateClockBase(ALCdevice *device)
{
- IncrementRef(&device->MixCount);
+ IncrementRef(device->MixCount);
device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
device->SamplesDone = 0;
- IncrementRef(&device->MixCount);
+ IncrementRef(device->MixCount);
}
/* UpdateDeviceParams
@@ -2205,7 +2193,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
for(s = device->NumAuxSends;s < old_sends;s++)
{
if(source->Send[s].Slot)
- DecrementRef(&source->Send[s].Slot->ref);
+ DecrementRef(source->Send[s].Slot->ref);
source->Send[s].Slot = nullptr;
}
source->Send.resize(device->NumAuxSends);
@@ -2360,7 +2348,7 @@ static DeviceRef VerifyDevice(ALCdevice *device)
auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device);
if(iter != DeviceList.cend() && *iter == device)
{
- ALCdevice_IncRef(iter->get());
+ (*iter)->add_ref();
return DeviceRef{iter->get()};
}
return DeviceRef{};
@@ -2459,7 +2447,7 @@ ALCcontext::~ALCcontext()
while(eprops)
{
ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)};
- if(eprops->State) eprops->State->DecRef();
+ if(eprops->State) eprops->State->release();
al_free(eprops);
eprops = next;
++count;
@@ -2528,7 +2516,7 @@ ALCcontext::~ALCcontext()
mAsyncEvents->readAdvance(count);
}
- ALCdevice_DecRef(mDevice);
+ mDevice->release();
}
/* ReleaseContext
@@ -2543,12 +2531,12 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device)
{
WARN("%p released while current on thread\n", context);
LocalContext.set(nullptr);
- context->decRef();
+ context->release();
}
ALCcontext *origctx{context};
if(GlobalContext.compare_exchange_strong(origctx, nullptr))
- context->decRef();
+ context->release();
bool ret{};
{
@@ -2594,18 +2582,6 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device)
return ret;
}
-static void ALCcontext_IncRef(ALCcontext *context)
-{
- auto ref = IncrementRef(&context->mRef);
- TRACEREF("ALCcontext %p increasing refcount to %u\n", context, ref);
-}
-
-void ALCcontext::decRef() noexcept
-{
- auto ref = DecrementRef(&mRef);
- TRACEREF("ALCcontext %p decreasing refcount to %u\n", this, ref);
- if(UNLIKELY(ref == 0)) delete this;
-}
/* VerifyContext
*
@@ -2617,7 +2593,7 @@ static ContextRef VerifyContext(ALCcontext *context)
auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context);
if(iter != ContextList.cend() && *iter == context)
{
- ALCcontext_IncRef(iter->get());
+ (*iter)->add_ref();
return ContextRef{iter->get()};
}
return ContextRef{};
@@ -2632,12 +2608,12 @@ ContextRef GetContextRef(void)
{
ALCcontext *context{LocalContext.get()};
if(context)
- ALCcontext_IncRef(context);
+ context->add_ref();
else
{
std::lock_guard<std::recursive_mutex> _{ListLock};
context = GlobalContext.load(std::memory_order_acquire);
- if(context) ALCcontext_IncRef(context);
+ if(context) context->add_ref();
}
return ContextRef{context};
}
@@ -3278,11 +3254,11 @@ START_API_FUNC
ALuint samplecount;
ALuint refcount;
do {
- while(((refcount=ReadRef(&dev->MixCount))&1) != 0)
+ while(((refcount=ReadRef(dev->MixCount))&1) != 0)
std::this_thread::yield();
basecount = dev->ClockBase;
samplecount = dev->SamplesDone;
- } while(refcount != ReadRef(&dev->MixCount));
+ } while(refcount != ReadRef(dev->MixCount));
basecount += nanoseconds{seconds{samplecount}} / dev->Frequency;
*values = basecount.count();
}
@@ -3426,7 +3402,7 @@ START_API_FUNC
dev->LastError.store(ALC_NO_ERROR);
ContextRef context{new ALCcontext{dev.get()}};
- ALCdevice_IncRef(context->mDevice);
+ dev->add_ref();
ALCenum err{UpdateDeviceParams(dev.get(), attrList)};
if(err != ALC_NO_ERROR)
@@ -3502,7 +3478,7 @@ START_API_FUNC
{
std::lock_guard<std::recursive_mutex> _{ListLock};
auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get());
- ALCcontext_IncRef(context.get());
+ context->add_ref();
ContextList.insert(iter, ContextRef{context.get()});
}
@@ -3850,7 +3826,7 @@ START_API_FUNC
{
std::lock_guard<std::recursive_mutex> _{ListLock};
auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
- ALCdevice_IncRef(device.get());
+ device->add_ref();
DeviceList.insert(iter, DeviceRef{device.get()});
}
@@ -3976,7 +3952,7 @@ START_API_FUNC
{
std::lock_guard<std::recursive_mutex> _{ListLock};
auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
- ALCdevice_IncRef(device.get());
+ device->add_ref();
DeviceList.insert(iter, DeviceRef{device.get()});
}
@@ -4145,7 +4121,7 @@ START_API_FUNC
{
std::lock_guard<std::recursive_mutex> _{ListLock};
auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get());
- ALCdevice_IncRef(device.get());
+ device->add_ref();
DeviceList.insert(iter, DeviceRef{device.get()});
}
diff --git a/alc/alcmain.h b/alc/alcmain.h
index f69dc755..5b4e4a2b 100644
--- a/alc/alcmain.h
+++ b/alc/alcmain.h
@@ -24,6 +24,7 @@
#include "atomic.h"
#include "hrtf.h"
#include "inprogext.h"
+#include "intrusive_ptr.h"
#include "vector.h"
class BFormatDec;
@@ -310,9 +311,7 @@ enum {
DeviceFlagsCount
};
-struct ALCdevice {
- RefCount ref{1u};
-
+struct ALCdevice : public al::intrusive_ref<ALCdevice> {
std::atomic<bool> Connected{true};
const DeviceType Type{};
diff --git a/alc/alcontext.h b/alc/alcontext.h
index 43b9c08f..53da10dc 100644
--- a/alc/alcontext.h
+++ b/alc/alcontext.h
@@ -18,6 +18,7 @@
#include "alu.h"
#include "atomic.h"
#include "inprogext.h"
+#include "intrusive_ptr.h"
#include "logging.h"
#include "threads.h"
#include "vector.h"
@@ -84,9 +85,7 @@ struct EffectSlotSubList {
{ std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
};
-struct ALCcontext {
- RefCount mRef{1u};
-
+struct ALCcontext : public al::intrusive_ref<ALCcontext> {
al::vector<SourceSubList> mSourceList;
ALuint mNumSources{0};
std::mutex mSourceLock;
@@ -156,8 +155,6 @@ struct ALCcontext {
ALCcontext& operator=(const ALCcontext&) = delete;
~ALCcontext();
- void decRef() noexcept;
-
void allocVoices(size_t num_voices);
/**
@@ -194,7 +191,7 @@ class ContextRef {
void reset() noexcept
{
if(mCtx)
- mCtx->decRef();
+ mCtx->release();
mCtx = nullptr;
}
diff --git a/alc/alu.cpp b/alc/alu.cpp
index 2469d08d..8d627b97 100644
--- a/alc/alu.cpp
+++ b/alc/alu.cpp
@@ -373,20 +373,10 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force)
EffectState *oldstate{slot->Params.mEffectState};
slot->Params.mEffectState = state;
- /* Manually decrement the old effect state's refcount if it's greater
- * than 1. We need to be a bit clever here to avoid the refcount
- * reaching 0 since it can't be deleted in the mixer.
+ /* Only decrement the old state if it won't get deleted, since we can't
+ * be deleting/freeing anything in the mixer.
*/
- ALuint oldval{oldstate->mRef.load(std::memory_order_acquire)};
- while(oldval > 1 && !oldstate->mRef.compare_exchange_weak(oldval, oldval-1,
- std::memory_order_acq_rel, std::memory_order_acquire))
- {
- /* oldval was updated with the current value on failure, so just
- * try again.
- */
- }
-
- if(oldval < 2)
+ if(!oldstate->releaseIfNoDelete())
{
/* Otherwise, if it would be deleted, send it off with a release
* event.
@@ -1355,7 +1345,7 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force)
void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots)
{
- IncrementRef(&ctx->mUpdateCount);
+ IncrementRef(ctx->mUpdateCount);
if(LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire)))
{
bool cforce{CalcContextParams(ctx)};
@@ -1374,7 +1364,7 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots)
}
);
}
- IncrementRef(&ctx->mUpdateCount);
+ IncrementRef(ctx->mUpdateCount);
}
void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo)
@@ -1676,7 +1666,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
);
/* Increment the mix count at the start (lsb should now be 1). */
- IncrementRef(&device->MixCount);
+ IncrementRef(device->MixCount);
/* For each context on this device, process and mix its sources and
* effects.
@@ -1694,7 +1684,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
device->SamplesDone %= device->Frequency;
/* Increment the mix count at the end (lsb should now be 0). */
- IncrementRef(&device->MixCount);
+ IncrementRef(device->MixCount);
/* Apply any needed post-process for finalizing the Dry mix to the
* RealOut (Ambisonic decode, UHJ encode, etc).
diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp
index 78b9196e..095990b7 100644
--- a/alc/backends/base.cpp
+++ b/alc/backends/base.cpp
@@ -43,11 +43,11 @@ ClockLatency BackendBase::getClockLatency()
ALuint refcount;
do {
- while(((refcount=mDevice->MixCount.load(std::memory_order_acquire))&1))
+ while(((refcount=ReadRef(mDevice->MixCount))&1) != 0)
std::this_thread::yield();
ret.ClockTime = GetDeviceClockTime(mDevice);
std::atomic_thread_fence(std::memory_order_acquire);
- } while(refcount != mDevice->MixCount.load(std::memory_order_relaxed));
+ } while(refcount != ReadRef(mDevice->MixCount));
/* NOTE: The device will generally have about all but one periods filled at
* any given time during playback. Without a more accurate measurement from
diff --git a/alc/effects/base.h b/alc/effects/base.h
index 4f48de22..89a9e8e4 100644
--- a/alc/effects/base.h
+++ b/alc/effects/base.h
@@ -5,7 +5,7 @@
#include "almalloc.h"
#include "alspan.h"
#include "atomic.h"
-
+#include "intrusive_ptr.h"
struct ALeffectslot;
@@ -149,9 +149,7 @@ struct EffectTarget {
RealMixParams *RealOut;
};
-struct EffectState {
- RefCount mRef{1u};
-
+struct EffectState : public al::intrusive_ref<EffectState> {
al::span<FloatBufferLine> mOutTarget;
@@ -160,9 +158,6 @@ struct EffectState {
virtual ALboolean deviceUpdate(const ALCdevice *device) = 0;
virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0;
virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span<FloatBufferLine> samplesOut) = 0;
-
- void IncRef() noexcept;
- void DecRef() noexcept;
};
diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp
index 124707c5..a8b56019 100644
--- a/alc/hrtf.cpp
+++ b/alc/hrtf.cpp
@@ -484,7 +484,7 @@ std::unique_ptr<HrtfEntry> CreateHrtfStore(ALuint rate, ALsizei irSize, const AL
ERR("Out of memory allocating storage for %s.\n", filename);
else
{
- InitRef(&Hrtf->ref, 1u);
+ InitRef(Hrtf->ref, 1u);
Hrtf->sampleRate = rate;
Hrtf->irSize = irSize;
Hrtf->fdCount = fdCount;
@@ -1373,13 +1373,13 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle)
void HrtfEntry::IncRef()
{
- auto ref = IncrementRef(&this->ref);
+ auto ref = IncrementRef(this->ref);
TRACEREF("HrtfEntry %p increasing refcount to %u\n", this, ref);
}
void HrtfEntry::DecRef()
{
- auto ref = DecrementRef(&this->ref);
+ auto ref = DecrementRef(this->ref);
TRACEREF("HrtfEntry %p decreasing refcount to %u\n", this, ref);
if(ref == 0)
{
@@ -1389,7 +1389,7 @@ void HrtfEntry::DecRef()
auto delete_unused = [](HrtfHandlePtr &handle) -> void
{
HrtfEntry *entry{handle->entry.get()};
- if(entry && ReadRef(&entry->ref) == 0)
+ if(entry && ReadRef(entry->ref) == 0)
{
TRACE("Unloading unused HRTF %s\n", handle->filename.data());
handle->entry = nullptr;
diff --git a/common/atomic.h b/common/atomic.h
index e34f35bb..5e9b04c6 100644
--- a/common/atomic.h
+++ b/common/atomic.h
@@ -6,14 +6,14 @@
using RefCount = std::atomic<unsigned int>;
-inline void InitRef(RefCount *ptr, unsigned int value)
-{ ptr->store(value, std::memory_order_relaxed); }
-inline unsigned int ReadRef(RefCount *ptr)
-{ return ptr->load(std::memory_order_acquire); }
-inline unsigned int IncrementRef(RefCount *ptr)
-{ return ptr->fetch_add(1u, std::memory_order_acq_rel)+1u; }
-inline unsigned int DecrementRef(RefCount *ptr)
-{ return ptr->fetch_sub(1u, std::memory_order_acq_rel)-1u; }
+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)
+{ return ref.fetch_add(1u, std::memory_order_acq_rel)+1u; }
+inline unsigned int DecrementRef(RefCount &ref)
+{ return ref.fetch_sub(1u, std::memory_order_acq_rel)-1u; }
/* WARNING: A livelock is theoretically possible if another thread keeps
diff --git a/common/intrusive_ptr.h b/common/intrusive_ptr.h
new file mode 100644
index 00000000..8f34aeac
--- /dev/null
+++ b/common/intrusive_ptr.h
@@ -0,0 +1,48 @@
+#ifndef INTRUSIVE_PTR_H
+#define INTRUSIVE_PTR_H
+
+#include "atomic.h"
+#include "opthelpers.h"
+
+
+namespace al {
+
+template<typename T>
+class intrusive_ref {
+ RefCount mRef{1u};
+
+public:
+ unsigned int add_ref() noexcept { return IncrementRef(mRef); }
+ unsigned int release() noexcept
+ {
+ auto ref = DecrementRef(mRef);
+ if(UNLIKELY(ref == 0))
+ delete static_cast<T*>(this);
+ return ref;
+ }
+
+ /**
+ * Release only if doing so would not bring the object to 0 references and
+ * delete it. Returns false if the object could not be released.
+ *
+ * NOTE: The caller is responsible for handling a failed release, as it
+ * means the object has no other references and needs to be be deleted
+ * somehow.
+ */
+ bool releaseIfNoDelete() noexcept
+ {
+ auto val = mRef.load(std::memory_order_acquire);
+ while(val > 1 && !mRef.compare_exchange_strong(val, val-1, std::memory_order_acq_rel))
+ {
+ /* val was updated with the current value on failure, so just try
+ * again.
+ */
+ }
+
+ return val >= 2;
+ }
+};
+
+} // namespace al
+
+#endif /* INTRUSIVE_PTR_H */