Use atomics for the device and context list heads
This commit is contained in:
@@ -766,7 +766,7 @@ static const ALCint alcEFXMinorVersion = 0;
|
||||
/************************************************
|
||||
* Device lists
|
||||
************************************************/
|
||||
static ALCdevice *volatile DeviceList = NULL;
|
||||
static ATOMIC(ALCdevice*) DeviceList = ATOMIC_INIT_STATIC(NULL);
|
||||
|
||||
static almtx_t ListLock;
|
||||
static inline void LockLists(void)
|
||||
@@ -1165,7 +1165,7 @@ static void alc_cleanup(void)
|
||||
free(alcCaptureDefaultDeviceSpecifier);
|
||||
alcCaptureDefaultDeviceSpecifier = NULL;
|
||||
|
||||
if((dev=ExchangePtr((XchgPtr*)&DeviceList, NULL)) != NULL)
|
||||
if((dev=ATOMIC_EXCHANGE(ALCdevice*, &DeviceList, NULL)) != NULL)
|
||||
{
|
||||
ALCuint num = 0;
|
||||
do {
|
||||
@@ -1877,7 +1877,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
|
||||
SetMixerFPUMode(&oldMode);
|
||||
ALCdevice_Lock(device);
|
||||
context = device->ContextList;
|
||||
context = ATOMIC_LOAD(&device->ContextList);
|
||||
while(context)
|
||||
{
|
||||
ALsizei pos;
|
||||
@@ -2067,7 +2067,7 @@ static ALCdevice *VerifyDevice(ALCdevice *device)
|
||||
return NULL;
|
||||
|
||||
LockLists();
|
||||
tmpDevice = DeviceList;
|
||||
tmpDevice = ATOMIC_LOAD(&DeviceList);
|
||||
while(tmpDevice && tmpDevice != device)
|
||||
tmpDevice = tmpDevice->next;
|
||||
|
||||
@@ -2180,7 +2180,7 @@ static ALCvoid FreeContext(ALCcontext *context)
|
||||
*/
|
||||
static void ReleaseContext(ALCcontext *context, ALCdevice *device)
|
||||
{
|
||||
ALCcontext *volatile*tmp_ctx;
|
||||
ALCcontext *nextctx;
|
||||
ALCcontext *origctx;
|
||||
|
||||
if(altss_get(LocalContext) == context)
|
||||
@@ -2195,12 +2195,15 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device)
|
||||
ALCcontext_DecRef(context);
|
||||
|
||||
ALCdevice_Lock(device);
|
||||
tmp_ctx = &device->ContextList;
|
||||
while(*tmp_ctx)
|
||||
origctx = context;
|
||||
nextctx = context->next;
|
||||
if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &device->ContextList, &origctx, nextctx))
|
||||
{
|
||||
if(CompExchangePtr((XchgPtr*)tmp_ctx, context, context->next) == context)
|
||||
break;
|
||||
tmp_ctx = &(*tmp_ctx)->next;
|
||||
ALCcontext *list;
|
||||
do {
|
||||
list = origctx;
|
||||
origctx = context;
|
||||
} while(!COMPARE_EXCHANGE(&list->next, &origctx, nextctx));
|
||||
}
|
||||
ALCdevice_Unlock(device);
|
||||
|
||||
@@ -2237,19 +2240,19 @@ static ALCcontext *VerifyContext(ALCcontext *context)
|
||||
ALCdevice *dev;
|
||||
|
||||
LockLists();
|
||||
dev = DeviceList;
|
||||
dev = ATOMIC_LOAD(&DeviceList);
|
||||
while(dev)
|
||||
{
|
||||
ALCcontext *tmp_ctx = dev->ContextList;
|
||||
while(tmp_ctx)
|
||||
ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList);
|
||||
while(ctx)
|
||||
{
|
||||
if(tmp_ctx == context)
|
||||
if(ctx == context)
|
||||
{
|
||||
ALCcontext_IncRef(tmp_ctx);
|
||||
ALCcontext_IncRef(ctx);
|
||||
UnlockLists();
|
||||
return tmp_ctx;
|
||||
return ctx;
|
||||
}
|
||||
tmp_ctx = tmp_ctx->next;
|
||||
ctx = ctx->next;
|
||||
}
|
||||
dev = dev->next;
|
||||
}
|
||||
@@ -2886,7 +2889,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
|
||||
}
|
||||
if(!ALContext || !ALContext->ActiveSources)
|
||||
{
|
||||
if(!device->ContextList)
|
||||
if(!ATOMIC_LOAD(&device->ContextList))
|
||||
{
|
||||
V0(device->Backend,stop)();
|
||||
device->Flags &= ~DEVICE_RUNNING;
|
||||
@@ -2913,9 +2916,12 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
|
||||
ALCdevice_IncRef(device);
|
||||
InitContext(ALContext);
|
||||
|
||||
do {
|
||||
ALContext->next = device->ContextList;
|
||||
} while(CompExchangePtr((XchgPtr*)&device->ContextList, ALContext->next, ALContext) != ALContext->next);
|
||||
{
|
||||
ALCcontext *head = ATOMIC_LOAD(&device->ContextList);
|
||||
do {
|
||||
ALContext->next = head;
|
||||
} while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCcontext*, &device->ContextList, &head, ALContext));
|
||||
}
|
||||
UnlockLists();
|
||||
|
||||
ALCdevice_DecRef(device);
|
||||
@@ -2938,7 +2944,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
|
||||
if(Device)
|
||||
{
|
||||
ReleaseContext(context, Device);
|
||||
if(!Device->ContextList)
|
||||
if(!ATOMIC_LOAD(&Device->ContextList))
|
||||
{
|
||||
V0(Device->Backend,stop)();
|
||||
Device->Flags &= ~DEVICE_RUNNING;
|
||||
@@ -3077,7 +3083,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
|
||||
device->Bs2bLevel = 0;
|
||||
AL_STRING_INIT(device->DeviceName);
|
||||
|
||||
device->ContextList = NULL;
|
||||
ATOMIC_STORE_UNSAFE(&device->ContextList, NULL);
|
||||
|
||||
device->ClockBase = 0;
|
||||
device->SamplesDone = 0;
|
||||
@@ -3287,9 +3293,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
device->next = DeviceList;
|
||||
} while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
|
||||
{
|
||||
ALCdevice *head = ATOMIC_LOAD(&DeviceList);
|
||||
do {
|
||||
device->next = head;
|
||||
} while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device));
|
||||
}
|
||||
|
||||
TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName));
|
||||
return device;
|
||||
@@ -3299,36 +3308,48 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
|
||||
*
|
||||
* Closes the given device.
|
||||
*/
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *Device)
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
|
||||
{
|
||||
ALCdevice *volatile*list;
|
||||
ALCdevice *list, *origdev, *nextdev;
|
||||
ALCcontext *ctx;
|
||||
|
||||
LockLists();
|
||||
list = &DeviceList;
|
||||
while(*list && *list != Device)
|
||||
list = &(*list)->next;
|
||||
|
||||
if(!*list || (*list)->Type == Capture)
|
||||
list = ATOMIC_LOAD(&DeviceList);
|
||||
do {
|
||||
if(list == device)
|
||||
break;
|
||||
} while((list=list->next) != NULL);
|
||||
if(!list || list->Type == Capture)
|
||||
{
|
||||
alcSetError(*list, ALC_INVALID_DEVICE);
|
||||
alcSetError(list, ALC_INVALID_DEVICE);
|
||||
UnlockLists();
|
||||
return ALC_FALSE;
|
||||
}
|
||||
|
||||
*list = (*list)->next;
|
||||
origdev = device;
|
||||
nextdev = device->next;
|
||||
if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, nextdev))
|
||||
{
|
||||
do {
|
||||
list = origdev;
|
||||
origdev = device;
|
||||
} while(!COMPARE_EXCHANGE(&list->next, &origdev, nextdev));
|
||||
}
|
||||
UnlockLists();
|
||||
|
||||
while((ctx=Device->ContextList) != NULL)
|
||||
ctx = ATOMIC_LOAD(&device->ContextList);
|
||||
while(ctx != NULL)
|
||||
{
|
||||
ALCcontext *next = ctx->next;
|
||||
WARN("Releasing context %p\n", ctx);
|
||||
ReleaseContext(ctx, Device);
|
||||
ReleaseContext(ctx, device);
|
||||
ctx = next;
|
||||
}
|
||||
if((Device->Flags&DEVICE_RUNNING))
|
||||
V0(Device->Backend,stop)();
|
||||
Device->Flags &= ~DEVICE_RUNNING;
|
||||
if((device->Flags&DEVICE_RUNNING))
|
||||
V0(device->Backend,stop)();
|
||||
device->Flags &= ~DEVICE_RUNNING;
|
||||
|
||||
ALCdevice_DecRef(Device);
|
||||
ALCdevice_DecRef(device);
|
||||
|
||||
return ALC_TRUE;
|
||||
}
|
||||
@@ -3416,34 +3437,46 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
device->next = DeviceList;
|
||||
} while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
|
||||
{
|
||||
ALCdevice *head = ATOMIC_LOAD(&DeviceList);
|
||||
do {
|
||||
device->next = head;
|
||||
} while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device));
|
||||
}
|
||||
|
||||
TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName));
|
||||
return device;
|
||||
}
|
||||
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *Device)
|
||||
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
|
||||
{
|
||||
ALCdevice *volatile*list;
|
||||
ALCdevice *list, *next, *nextdev;
|
||||
|
||||
LockLists();
|
||||
list = &DeviceList;
|
||||
while(*list && *list != Device)
|
||||
list = &(*list)->next;
|
||||
|
||||
if(!*list || (*list)->Type != Capture)
|
||||
list = ATOMIC_LOAD(&DeviceList);
|
||||
do {
|
||||
if(list == device)
|
||||
break;
|
||||
} while((list=list->next) != NULL);
|
||||
if(!list || list->Type != Capture)
|
||||
{
|
||||
alcSetError(*list, ALC_INVALID_DEVICE);
|
||||
alcSetError(list, ALC_INVALID_DEVICE);
|
||||
UnlockLists();
|
||||
return ALC_FALSE;
|
||||
}
|
||||
|
||||
*list = (*list)->next;
|
||||
next = device;
|
||||
nextdev = device->next;
|
||||
if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &next, nextdev))
|
||||
{
|
||||
do {
|
||||
list = next;
|
||||
next = device;
|
||||
} while(!COMPARE_EXCHANGE(&list->next, &next, nextdev));
|
||||
}
|
||||
UnlockLists();
|
||||
|
||||
ALCdevice_DecRef(Device);
|
||||
ALCdevice_DecRef(device);
|
||||
|
||||
return ALC_TRUE;
|
||||
}
|
||||
@@ -3543,7 +3576,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
|
||||
device->Bs2bLevel = 0;
|
||||
AL_STRING_INIT(device->DeviceName);
|
||||
|
||||
device->ContextList = NULL;
|
||||
ATOMIC_STORE_UNSAFE(&device->ContextList, NULL);
|
||||
|
||||
device->ClockBase = 0;
|
||||
device->SamplesDone = 0;
|
||||
@@ -3599,9 +3632,13 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
|
||||
|
||||
// Open the "backend"
|
||||
V(device->Backend,open)("Loopback");
|
||||
do {
|
||||
device->next = DeviceList;
|
||||
} while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
|
||||
|
||||
{
|
||||
ALCdevice *head = ATOMIC_LOAD(&DeviceList);
|
||||
do {
|
||||
device->next = head;
|
||||
} while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device));
|
||||
}
|
||||
|
||||
TRACE("Created device %p\n", device);
|
||||
return device;
|
||||
@@ -3686,7 +3723,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
|
||||
if((device->Flags&DEVICE_PAUSED))
|
||||
{
|
||||
device->Flags &= ~DEVICE_PAUSED;
|
||||
if(device->ContextList != NULL)
|
||||
if(ATOMIC_LOAD(&device->ContextList) != NULL)
|
||||
{
|
||||
if(V0(device->Backend,start)() != ALC_FALSE)
|
||||
device->Flags |= DEVICE_RUNNING;
|
||||
|
||||
@@ -1160,7 +1160,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
|
||||
ALCdevice_Lock(device);
|
||||
V(device->Synth,process)(SamplesToDo, device->DryBuffer);
|
||||
|
||||
ctx = device->ContextList;
|
||||
ctx = ATOMIC_LOAD(&device->ContextList);
|
||||
while(ctx)
|
||||
{
|
||||
ALenum DeferUpdates = ctx->DeferUpdates;
|
||||
@@ -1295,7 +1295,7 @@ ALvoid aluHandleDisconnect(ALCdevice *device)
|
||||
|
||||
device->Connected = ALC_FALSE;
|
||||
|
||||
Context = device->ContextList;
|
||||
Context = ATOMIC_LOAD(&device->ContextList);
|
||||
while(Context)
|
||||
{
|
||||
ALactivesource **src, **src_end;
|
||||
|
||||
@@ -694,11 +694,11 @@ struct ALCdevice_struct
|
||||
struct ALeffectslot *DefaultSlot;
|
||||
|
||||
// Contexts created on this device
|
||||
ALCcontext *volatile ContextList;
|
||||
ATOMIC(ALCcontext*) ContextList;
|
||||
|
||||
struct ALCbackend *Backend;
|
||||
|
||||
void *ExtraData; // For the backend's use
|
||||
void *ExtraData; // For the backend's use
|
||||
|
||||
ALCdevice *volatile next;
|
||||
|
||||
|
||||
@@ -11,4 +11,3 @@ extern inline uint DecrementRef(RefCount *ptr);
|
||||
|
||||
extern inline int ExchangeInt(volatile int *ptr, int newval);
|
||||
extern inline void *ExchangePtr(XchgPtr *ptr, void *newval);
|
||||
extern inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval);
|
||||
|
||||
+12
-12
@@ -19,8 +19,6 @@ inline int ExchangeInt(volatile int *ptr, int newval)
|
||||
{ return atomic_exchange(ptr, newval); }
|
||||
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
|
||||
{ return atomic_exchange(ptr, newval); }
|
||||
inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
|
||||
{ atomic_compare_exchange_strong(ptr, &oldval, newval); return oldval; }
|
||||
|
||||
|
||||
#define ATOMIC(T) struct { T _Atomic value; }
|
||||
@@ -39,6 +37,8 @@ inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
|
||||
#define ATOMIC_EXCHANGE(T, _val, _newval) atomic_exchange(&(_val)->value, (_newval))
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) \
|
||||
atomic_compare_exchange_strong(&(_val)->value, (_oldval), (_newval))
|
||||
#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _oldval, _newval) \
|
||||
atomic_compare_exchange_weak(&(_val)->value, (_oldval), (_newval))
|
||||
|
||||
/* Atomics using GCC intrinsics */
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
|
||||
@@ -47,8 +47,6 @@ inline int ExchangeInt(volatile int *ptr, int newval)
|
||||
{ return __sync_lock_test_and_set(ptr, newval); }
|
||||
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
|
||||
{ return __sync_lock_test_and_set(ptr, newval); }
|
||||
inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
|
||||
{ return __sync_val_compare_and_swap(ptr, oldval, newval); }
|
||||
|
||||
|
||||
#define ATOMIC(T) struct { T volatile value; }
|
||||
@@ -126,13 +124,9 @@ inline int ExchangeInt(volatile int *dest, int newval)
|
||||
#ifdef __i386__
|
||||
inline void *ExchangePtr(XchgPtr *dest, void *newval)
|
||||
{ void *ret; WRAP_XCHG("l", ret, dest, newval); return ret; }
|
||||
inline void *CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
|
||||
{ void *ret; WRAP_CMPXCHG("l", ret, dest, oldval, newval); return ret; }
|
||||
#else
|
||||
inline void *ExchangePtr(XchgPtr *dest, void *newval)
|
||||
{ void *ret; WRAP_XCHG("q", ret, dest, newval); return ret; }
|
||||
inline void *CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
|
||||
{ void *ret; WRAP_CMPXCHG("q", ret, dest, oldval, newval); return ret; }
|
||||
#endif
|
||||
|
||||
|
||||
@@ -244,13 +238,9 @@ inline int ExchangeInt(volatile int *ptr, int newval)
|
||||
#ifdef _WIN64
|
||||
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
|
||||
{ return WRAP_XCHG(void*,AtomicSwap64,ptr,newval); }
|
||||
inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
|
||||
{ WRAP_CMPXCHG(void*,CompareAndSwap64,ptr,newval,&oldval); return oldval; }
|
||||
#else
|
||||
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
|
||||
{ return WRAP_XCHG(void*,AtomicSwap32,ptr,newval); }
|
||||
inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
|
||||
{ WRAP_CMPXCHG(void*,CompareAndSwap32,ptr,newval,&oldval); return oldval; }
|
||||
#endif
|
||||
|
||||
|
||||
@@ -307,6 +297,16 @@ int _al_invalid_atomic_size(); /* not defined */
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) (0)
|
||||
#endif
|
||||
|
||||
/* If no weak cmpxchg is provided (not all systems will have one), substitute a
|
||||
* strong cmpxchg. */
|
||||
#ifndef ATOMIC_COMPARE_EXCHANGE_WEAK
|
||||
#define ATOMIC_COMPARE_EXCHANGE_WEAK(a, b, c, d) ATOMIC_COMPARE_EXCHANGE_STRONG(a, b, c, d)
|
||||
#endif
|
||||
|
||||
/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non-
|
||||
* atomic variables. */
|
||||
#define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false))
|
||||
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef ATOMIC(uint) RefCount;
|
||||
|
||||
Reference in New Issue
Block a user