Add a common base for auto-deleting ref-counted objects
Which will also work as the basis for a future intrusive_ptrmaster
parent
380f3dc11d
commit
65f7fc610e
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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] ||
|
||||
|
|
|
@ -64,7 +64,7 @@ static int EventThread(ALCcontext *context)
|
|||
|
||||
if(evt.EnumType == EventType_ReleaseEffectState)
|
||||
{
|
||||
evt.u.mEffectState->DecRef();
|
||||
evt.u.mEffectState->release();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
);
|
||||
|
|
70
alc/alc.cpp
70
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()});
|
||||
}
|
||||
|
||||
|
|
|
@ -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{};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
24
alc/alu.cpp
24
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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue