diff options
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/atomic.h | 180 | ||||
-rw-r--r-- | Alc/rwlock.h | 21 | ||||
-rw-r--r-- | Alc/uintmap.h | 34 |
3 files changed, 235 insertions, 0 deletions
diff --git a/Alc/atomic.h b/Alc/atomic.h new file mode 100644 index 00000000..9c249808 --- /dev/null +++ b/Alc/atomic.h @@ -0,0 +1,180 @@ +#ifndef AL_ATOMIC_H +#define AL_ATOMIC_H + + +typedef void *volatile XchgPtr; + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__) +typedef unsigned int RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return __sync_add_and_fetch(ptr, 1); } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return __sync_sub_and_fetch(ptr, 1); } + +static inline int ExchangeInt(volatile int *ptr, int newval) +{ + return __sync_lock_test_and_set(ptr, newval); +} +static inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + return __sync_lock_test_and_set(ptr, newval); +} +static inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +static inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +static inline unsigned int xaddl(volatile unsigned int *dest, int incr) +{ + unsigned int ret; + __asm__ __volatile__("lock; xaddl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (incr) + : "memory"); + return ret; +} + +typedef unsigned int RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return xaddl(ptr, 1)+1; } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return xaddl(ptr, -1)-1; } + +static inline int ExchangeInt(volatile int *dest, int newval) +{ + int ret; + __asm__ __volatile__("lock; xchgl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (newval) + : "memory"); + return ret; +} + +static inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int newval) +{ + int ret; + __asm__ __volatile__("lock; cmpxchgl %2,(%1)" + : "=a" (ret) + : "r" (dest), "r" (newval), "0" (oldval) + : "memory"); + return ret == oldval; +} + +static inline void *ExchangePtr(XchgPtr *dest, void *newval) +{ + void *ret; + __asm__ __volatile__( +#ifdef __i386__ + "lock; xchgl %0,(%1)" +#else + "lock; xchgq %0,(%1)" +#endif + : "=r" (ret) + : "r" (dest), "0" (newval) + : "memory" + ); + return ret; +} + +static inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval) +{ + void *ret; + __asm__ __volatile__( +#ifdef __i386__ + "lock; cmpxchgl %2,(%1)" +#else + "lock; cmpxchgq %2,(%1)" +#endif + : "=a" (ret) + : "r" (dest), "r" (newval), "0" (oldval) + : "memory" + ); + return ret == oldval; +} + +#elif defined(_WIN32) + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +typedef LONG RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return InterlockedIncrement(ptr); } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return InterlockedDecrement(ptr); } + +extern ALbyte LONG_size_does_not_match_int[(sizeof(LONG)==sizeof(int))?1:-1]; + +static inline int ExchangeInt(volatile int *ptr, int newval) +{ + union { + volatile int *i; + volatile LONG *l; + } u = { ptr }; + return InterlockedExchange(u.l, newval); +} +static inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + return InterlockedExchangePointer(ptr, newval); +} +static inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + union { + volatile int *i; + volatile LONG *l; + } u = { ptr }; + return InterlockedCompareExchange(u.l, newval, oldval) == oldval; +} +static inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval; +} + +#elif defined(__APPLE__) + +#include <libkern/OSAtomic.h> + +typedef int32_t RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return OSAtomicIncrement32Barrier(ptr); } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return OSAtomicDecrement32Barrier(ptr); } + +static inline int ExchangeInt(volatile int *ptr, int newval) +{ + /* Really? No regular old atomic swap? */ + int oldval; + do { + oldval = *ptr; + } while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr)); + return oldval; +} +static inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + void *oldval; + do { + oldval = *ptr; + } while(!OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr)); + return oldval; +} +static inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr); +} +static inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr); +} + +#else +#error "No atomic functions available on this platform!" +typedef ALuint RefCount; +#endif + +#endif /* AL_ATOMIC_H */ diff --git a/Alc/rwlock.h b/Alc/rwlock.h new file mode 100644 index 00000000..efbab4e8 --- /dev/null +++ b/Alc/rwlock.h @@ -0,0 +1,21 @@ +#ifndef AL_RWLOCK_H +#define AL_RWLOCK_H + +#include "AL/al.h" +#include "atomic.h" + +typedef struct { + volatile RefCount read_count; + volatile RefCount write_count; + volatile ALenum read_lock; + volatile ALenum read_entry_lock; + volatile ALenum write_lock; +} RWLock; + +void RWLockInit(RWLock *lock); +void ReadLock(RWLock *lock); +void ReadUnlock(RWLock *lock); +void WriteLock(RWLock *lock); +void WriteUnlock(RWLock *lock); + +#endif /* AL_RWLOCK_H */ diff --git a/Alc/uintmap.h b/Alc/uintmap.h new file mode 100644 index 00000000..d692e878 --- /dev/null +++ b/Alc/uintmap.h @@ -0,0 +1,34 @@ +#ifndef AL_UINTMAP_H +#define AL_UINTMAP_H + +#include "AL/al.h" +#include "rwlock.h" + +typedef struct UIntMap { + struct { + ALuint key; + ALvoid *value; + } *array; + ALsizei size; + ALsizei maxsize; + ALsizei limit; + RWLock lock; +} UIntMap; +extern UIntMap TlsDestructor; + +void InitUIntMap(UIntMap *map, ALsizei limit); +void ResetUIntMap(UIntMap *map); +ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); +ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); +ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key); + +static inline void LockUIntMapRead(UIntMap *map) +{ ReadLock(&map->lock); } +static inline void UnlockUIntMapRead(UIntMap *map) +{ ReadUnlock(&map->lock); } +static inline void LockUIntMapWrite(UIntMap *map) +{ WriteLock(&map->lock); } +static inline void UnlockUIntMapWrite(UIntMap *map) +{ WriteUnlock(&map->lock); } + +#endif /* AL_UINTMAP_H */ |