aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/ALc.c155
-rw-r--r--Alc/ALu.c4
-rw-r--r--OpenAL32/Include/alMain.h4
-rw-r--r--common/atomic.c1
-rw-r--r--include/atomic.h24
5 files changed, 112 insertions, 76 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index c07ada7f..b17742f3 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -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;
diff --git a/Alc/ALu.c b/Alc/ALu.c
index e33a756b..a85e1aa0 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -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;
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 623968d0..5a85421f 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -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;
diff --git a/common/atomic.c b/common/atomic.c
index d78fc60d..3cdb77f4 100644
--- a/common/atomic.c
+++ b/common/atomic.c
@@ -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);
diff --git a/include/atomic.h b/include/atomic.h
index bf00b813..5fd76252 100644
--- a/include/atomic.h
+++ b/include/atomic.h
@@ -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;