diff options
-rw-r--r-- | Alc/ALc.c | 155 | ||||
-rw-r--r-- | Alc/ALu.c | 4 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 4 | ||||
-rw-r--r-- | common/atomic.c | 1 | ||||
-rw-r--r-- | include/atomic.h | 24 |
5 files changed, 112 insertions, 76 deletions
@@ -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; 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; |