diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | al/auxeffectslot.cpp | 44 | ||||
-rw-r--r-- | al/buffer.cpp | 8 | ||||
-rw-r--r-- | al/event.cpp | 2 | ||||
-rw-r--r-- | al/source.cpp | 26 | ||||
-rw-r--r-- | alc/alc.cpp | 70 | ||||
-rw-r--r-- | alc/alcmain.h | 5 | ||||
-rw-r--r-- | alc/alcontext.h | 9 | ||||
-rw-r--r-- | alc/alu.cpp | 24 | ||||
-rw-r--r-- | alc/backends/base.cpp | 4 | ||||
-rw-r--r-- | alc/effects/base.h | 9 | ||||
-rw-r--r-- | alc/hrtf.cpp | 8 | ||||
-rw-r--r-- | common/atomic.h | 16 | ||||
-rw-r--r-- | common/intrusive_ptr.h | 48 |
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 */ |