Track all references for effect states

This allows us to not have to play around with trying to avoid duplicate state
pointers, since the reference count will ensure they're deleted as appropriate.
The only caveat is that the mixer is not allowed to decrement references, since
that can cause the object to be freed (which the mixer code is not allowed to
do).
This commit is contained in:
Chris Robinson
2016-08-25 04:57:58 -07:00
parent 0fbf34fb45
commit 4e4e597fa5
2 changed files with 53 additions and 30 deletions
+6 -9
View File
@@ -319,18 +319,15 @@ static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device)
slot->Params.DecayTime = 0.0f;
slot->Params.AirAbsorptionGainHF = 1.0f;
}
state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed);
/* If the state object is changed, exchange it with the current one so it
* remains in the freelist and isn't leaked.
/* Swap effect states. No need to play with the ref counts since they keep
* the same number of refs.
*/
if(state != slot->Params.EffectState)
{
ATOMIC_STORE(&props->State, slot->Params.EffectState, almemory_order_relaxed);
slot->Params.EffectState = state;
}
state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Params.EffectState,
almemory_order_relaxed);
slot->Params.EffectState = state;
V(slot->Params.EffectState,update)(device, slot, &props->Props);
V(state,update)(device, slot, &props->Props);
/* WARNING: A livelock is theoretically possible if another thread keeps
* changing the freelist head without giving this a chance to actually swap
+47 -21
View File
@@ -44,7 +44,6 @@ extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint
static void RemoveEffectSlotList(ALCcontext *Context, const ALeffectslot *slot);
static UIntMap EffectStateFactoryMap;
static inline ALeffectStateFactory *getFactoryByType(ALenum type)
{
@@ -54,6 +53,9 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type)
return NULL;
}
static void ALeffectState_IncRef(ALeffectState *state);
static void ALeffectState_DecRef(ALeffectState *state);
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
@@ -86,7 +88,9 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
if(err != AL_NO_ERROR)
{
FreeThunkEntry(slot->id);
DELETE_OBJ(slot->Params.EffectState);
ALeffectState_DecRef(slot->Effect.State);
if(slot->Params.EffectState)
ALeffectState_DecRef(slot->Params.EffectState);
al_free(slot);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
@@ -469,11 +473,12 @@ void DeinitEffectFactoryMap(void)
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
{
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
ALeffectStateFactory *factory;
struct ALeffectslotProps *props;
ALeffectState *State;
if(newtype != EffectSlot->Effect.Type)
{
ALeffectState *State;
ALeffectStateFactory *factory;
FPUCtl oldMode;
factory = getFactoryByType(newtype);
@@ -493,7 +498,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
{
almtx_unlock(&Device->BackendLock);
RestoreFPUMode(&oldMode);
DELETE_OBJ(State);
ALeffectState_DecRef(State);
return AL_OUT_OF_MEMORY;
}
almtx_unlock(&Device->BackendLock);
@@ -510,6 +515,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
EffectSlot->Effect.Props = effect->Props;
}
ALeffectState_DecRef(EffectSlot->Effect.State);
EffectSlot->Effect.State = State;
UpdateEffectSlotProps(EffectSlot);
}
@@ -519,10 +525,35 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
UpdateEffectSlotProps(EffectSlot);
}
/* Remove state references from old effect slot property updates. */
props = ATOMIC_LOAD(&EffectSlot->FreeList);
while(props)
{
State = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed);
if(State) ALeffectState_DecRef(State);
ATOMIC_LOAD(&props->next, almemory_order_relaxed);
}
return AL_NO_ERROR;
}
static void ALeffectState_IncRef(ALeffectState *state)
{
uint ref;
ref = IncrementRef(&state->Ref);
TRACEREF("%p increasing refcount to %u\n", state, ref);
}
static void ALeffectState_DecRef(ALeffectState *state)
{
uint ref;
ref = DecrementRef(&state->Ref);
TRACEREF("%p decreasing refcount to %u\n", state, ref);
if(ref == 0) DELETE_OBJ(state);
}
void ALeffectState_Construct(ALeffectState *state)
{
InitRef(&state->Ref, 1);
@@ -555,6 +586,7 @@ ALenum InitEffectSlot(ALeffectslot *slot)
slot->Params.Gain = 1.0f;
slot->Params.AuxSendAuto = AL_TRUE;
ALeffectState_IncRef(slot->Effect.State);
slot->Params.EffectState = slot->Effect.State;
slot->Params.RoomRolloff = 0.0f;
slot->Params.DecayTime = 0.0f;
@@ -575,8 +607,7 @@ void DeinitEffectSlot(ALeffectslot *slot)
if(props)
{
state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
if(state != slot->Params.EffectState)
DELETE_OBJ(state);
if(state) ALeffectState_DecRef(state);
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
al_free(props);
}
@@ -586,14 +617,16 @@ void DeinitEffectSlot(ALeffectslot *slot)
struct ALeffectslotProps *next;
state = ATOMIC_LOAD(&props->State, almemory_order_relaxed);
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
DELETE_OBJ(state);
if(state) ALeffectState_DecRef(state);
al_free(props);
props = next;
++count;
}
TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
DELETE_OBJ(slot->Params.EffectState);
ALeffectState_DecRef(slot->Effect.State);
if(slot->Params.EffectState)
ALeffectState_DecRef(slot->Params.EffectState);
}
void UpdateEffectSlotProps(ALeffectslot *slot)
@@ -602,17 +635,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot)
ALeffectState *oldstate;
props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL);
if(props)
{
/* If there was an unapplied update, check if its state object is the
* same as the current in-use one, or the one that will be set. If
* neither, delete it.
*/
oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed);
if(oldstate != slot->Params.EffectState && oldstate != slot->Effect.State)
DELETE_OBJ(oldstate);
}
else
if(!props)
{
/* Get an unused property container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
@@ -638,6 +661,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot)
/* Swap out any stale effect state object there may be in the container, to
* delete it.
*/
if(slot->Effect.State)
ALeffectState_IncRef(slot->Effect.State);
oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State,
almemory_order_relaxed);
@@ -656,7 +681,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot)
&slot->FreeList, &first, props) == 0);
}
DELETE_OBJ(oldstate);
if(oldstate)
ALeffectState_DecRef(oldstate);
}
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)