Properly destroy contexts that are left on the device when it's closed

This commit is contained in:
Chris Robinson 2011-09-10 07:35:48 -07:00
parent 419294cddd
commit 3dcd1e793e

View File

@ -1485,6 +1485,43 @@ static ALCvoid FreeContext(ALCcontext *context)
free(context); free(context);
} }
static void ReleaseContext(ALCcontext *context, ALCdevice *device)
{
ALCcontext *volatile*tmp_ctx;
tmp_ctx = &device->ContextList;
while(*tmp_ctx)
{
if(*tmp_ctx == context)
{
*tmp_ctx = context->next;
break;
}
tmp_ctx = &(*tmp_ctx)->next;
}
LockDevice(device);
/* Lock the device to make sure the mixer is not using the contexts in the
* list before we go about deleting this one. There should be a more
* efficient way of doing this. */
UnlockDevice(device);
if(pthread_getspecific(LocalContext) == context)
{
WARN("Context %p released while current on thread\n", context);
pthread_setspecific(LocalContext, NULL);
ALCcontext_DecRef(context);
}
if(CompExchangePtr((void**)&GlobalContext, context, NULL))
{
WARN("Context %p released while globally current\n", context);
ALCcontext_DecRef(context);
}
ALCcontext_DecRef(context);
}
void ALCcontext_IncRef(ALCcontext *context) void ALCcontext_IncRef(ALCcontext *context)
{ {
RefCount ref; RefCount ref;
@ -2260,7 +2297,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
{ {
ALCdevice *Device; ALCdevice *Device;
ALCcontext *volatile*tmp_ctx;
LockLists(); LockLists();
Device = alcGetContextsDevice(context); Device = alcGetContextsDevice(context);
@ -2270,35 +2306,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
return; return;
} }
tmp_ctx = &Device->ContextList; ReleaseContext(context, Device);
while(*tmp_ctx)
{
if(*tmp_ctx == context)
{
*tmp_ctx = context->next;
break;
}
tmp_ctx = &(*tmp_ctx)->next;
}
LockDevice(Device);
/* Lock the device to make sure the mixer is not using the contexts in the
* list before we go about deleting this one. There should be a more
* efficient way of doing this. */
UnlockDevice(Device);
if(pthread_getspecific(LocalContext) == context)
{
WARN("Context %p destroyed while current on thread\n", context);
pthread_setspecific(LocalContext, NULL);
ALCcontext_DecRef(context);
}
if(CompExchangePtr((void**)&GlobalContext, context, NULL))
{
WARN("Context %p destroyed while globally current\n", context);
ALCcontext_DecRef(context);
}
if(!Device->ContextList) if(!Device->ContextList)
{ {
@ -2306,8 +2314,6 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
Device->Flags &= ~DEVICE_RUNNING; Device->Flags &= ~DEVICE_RUNNING;
} }
UnlockLists(); UnlockLists();
ALCcontext_DecRef(context);
} }
@ -2605,14 +2611,17 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *pDevice)
*list = (*list)->next; *list = (*list)->next;
g_ulDeviceCount--; g_ulDeviceCount--;
UnlockLists(); UnlockLists();
while((ctx=pDevice->ContextList) != NULL) if((ctx=pDevice->ContextList) != NULL)
{ {
WARN("Destroying context %p\n", ctx); do {
alcDestroyContext(ctx); WARN("Destroying context %p\n", ctx);
} ReleaseContext(ctx, pDevice);
} while((ctx=pDevice->ContextList) != NULL);
ALCdevice_StopPlayback(pDevice);
pDevice->Flags &= ~DEVICE_RUNNING;
};
ALCdevice_ClosePlayback(pDevice); ALCdevice_ClosePlayback(pDevice);
ALCdevice_DecRef(pDevice); ALCdevice_DecRef(pDevice);