Add a common base for auto-deleting ref-counted objects

Which will also work as the basis for a future intrusive_ptr
master
Chris Robinson 2019-08-01 13:28:53 -07:00
parent 380f3dc11d
commit 65f7fc610e
14 changed files with 133 additions and 141 deletions

View File

@ -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

View File

@ -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)

View File

@ -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] ||

View File

@ -64,7 +64,7 @@ static int EventThread(ALCcontext *context)
if(evt.EnumType == EventType_ReleaseEffectState)
{
evt.u.mEffectState->DecRef();
evt.u.mEffectState->release();
continue;
}

View File

@ -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;
}
);

View File

@ -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()});
}

View File

@ -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{};

View File

@ -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;
}

View File

@ -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).

View File

@ -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

View File

@ -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;
};

View File

@ -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;

View File

@ -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

48
common/intrusive_ptr.h Normal file
View File

@ -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 */