atomic.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #ifndef AL_ATOMIC_H
  2. #define AL_ATOMIC_H
  3. typedef void *volatile XchgPtr;
  4. #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
  5. typedef unsigned int RefCount;
  6. inline RefCount IncrementRef(volatile RefCount *ptr)
  7. { return __sync_add_and_fetch(ptr, 1); }
  8. inline RefCount DecrementRef(volatile RefCount *ptr)
  9. { return __sync_sub_and_fetch(ptr, 1); }
  10. inline int ExchangeInt(volatile int *ptr, int newval)
  11. {
  12. return __sync_lock_test_and_set(ptr, newval);
  13. }
  14. inline void *ExchangePtr(XchgPtr *ptr, void *newval)
  15. {
  16. return __sync_lock_test_and_set(ptr, newval);
  17. }
  18. inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
  19. {
  20. return __sync_bool_compare_and_swap(ptr, oldval, newval);
  21. }
  22. inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
  23. {
  24. return __sync_bool_compare_and_swap(ptr, oldval, newval);
  25. }
  26. #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
  27. inline unsigned int xaddl(volatile unsigned int *dest, int incr)
  28. {
  29. unsigned int ret;
  30. __asm__ __volatile__("lock; xaddl %0,(%1)"
  31. : "=r" (ret)
  32. : "r" (dest), "0" (incr)
  33. : "memory");
  34. return ret;
  35. }
  36. typedef unsigned int RefCount;
  37. inline RefCount IncrementRef(volatile RefCount *ptr)
  38. { return xaddl(ptr, 1)+1; }
  39. inline RefCount DecrementRef(volatile RefCount *ptr)
  40. { return xaddl(ptr, -1)-1; }
  41. inline int ExchangeInt(volatile int *dest, int newval)
  42. {
  43. int ret;
  44. __asm__ __volatile__("lock; xchgl %0,(%1)"
  45. : "=r" (ret)
  46. : "r" (dest), "0" (newval)
  47. : "memory");
  48. return ret;
  49. }
  50. inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int newval)
  51. {
  52. int ret;
  53. __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
  54. : "=a" (ret)
  55. : "r" (dest), "r" (newval), "0" (oldval)
  56. : "memory");
  57. return ret == oldval;
  58. }
  59. inline void *ExchangePtr(XchgPtr *dest, void *newval)
  60. {
  61. void *ret;
  62. __asm__ __volatile__(
  63. #ifdef __i386__
  64. "lock; xchgl %0,(%1)"
  65. #else
  66. "lock; xchgq %0,(%1)"
  67. #endif
  68. : "=r" (ret)
  69. : "r" (dest), "0" (newval)
  70. : "memory"
  71. );
  72. return ret;
  73. }
  74. inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
  75. {
  76. void *ret;
  77. __asm__ __volatile__(
  78. #ifdef __i386__
  79. "lock; cmpxchgl %2,(%1)"
  80. #else
  81. "lock; cmpxchgq %2,(%1)"
  82. #endif
  83. : "=a" (ret)
  84. : "r" (dest), "r" (newval), "0" (oldval)
  85. : "memory"
  86. );
  87. return ret == oldval;
  88. }
  89. #elif defined(_WIN32)
  90. #define WIN32_LEAN_AND_MEAN
  91. #include <windows.h>
  92. typedef LONG RefCount;
  93. inline RefCount IncrementRef(volatile RefCount *ptr)
  94. { return InterlockedIncrement(ptr); }
  95. inline RefCount DecrementRef(volatile RefCount *ptr)
  96. { return InterlockedDecrement(ptr); }
  97. extern ALbyte LONG_size_does_not_match_int[(sizeof(LONG)==sizeof(int))?1:-1];
  98. inline int ExchangeInt(volatile int *ptr, int newval)
  99. {
  100. union {
  101. volatile int *i;
  102. volatile LONG *l;
  103. } u = { ptr };
  104. return InterlockedExchange(u.l, newval);
  105. }
  106. inline void *ExchangePtr(XchgPtr *ptr, void *newval)
  107. {
  108. return InterlockedExchangePointer(ptr, newval);
  109. }
  110. inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
  111. {
  112. union {
  113. volatile int *i;
  114. volatile LONG *l;
  115. } u = { ptr };
  116. return InterlockedCompareExchange(u.l, newval, oldval) == oldval;
  117. }
  118. inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
  119. {
  120. return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval;
  121. }
  122. #elif defined(__APPLE__)
  123. #include <libkern/OSAtomic.h>
  124. typedef int32_t RefCount;
  125. inline RefCount IncrementRef(volatile RefCount *ptr)
  126. { return OSAtomicIncrement32Barrier(ptr); }
  127. inline RefCount DecrementRef(volatile RefCount *ptr)
  128. { return OSAtomicDecrement32Barrier(ptr); }
  129. inline int ExchangeInt(volatile int *ptr, int newval)
  130. {
  131. /* Really? No regular old atomic swap? */
  132. int oldval;
  133. do {
  134. oldval = *ptr;
  135. } while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr));
  136. return oldval;
  137. }
  138. inline void *ExchangePtr(XchgPtr *ptr, void *newval)
  139. {
  140. void *oldval;
  141. do {
  142. oldval = *ptr;
  143. } while(!OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr));
  144. return oldval;
  145. }
  146. inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval)
  147. {
  148. return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr);
  149. }
  150. inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
  151. {
  152. return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr);
  153. }
  154. #else
  155. #error "No atomic functions available on this platform!"
  156. typedef ALuint RefCount;
  157. #endif
  158. #endif /* AL_ATOMIC_H */