Mirror of :pserver:cvs@cvs.fefe.de:/cvs libowfat https://www.fefe.de/libowfat/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

155 lines
4.3 KiB

  1. #ifndef _CAS_H
  2. #define _CAS_H
  3. #include <stddef.h>
  4. /* Atomic operations for lock-free data structures.
  5. * We operate on machine words and use size_t as a type.
  6. * CAS stands for Compare And Swap, the most common operation. */
  7. /* The API was inspired by the Linux kernel */
  8. #if defined(__INTEL_COMPILER) || (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1))
  9. #define USE_BUILTINS
  10. #endif
  11. /* if (*x == oldval) { *x=newval; return 1; } else return 0; */
  12. static inline int compare_and_swap(volatile size_t* x,size_t oldval,size_t newval) {
  13. #ifdef USE_BUILTINS
  14. __sync_bool_compare_and_swap(x,oldval,newval);
  15. #elif defined(__i386__)
  16. char result;
  17. asm volatile ("lock; cmpxchgl %3, %0; setz %1" : "=m"(*x), "=q" (result) : "m" (*x), "r" (newval), "a" (oldval) : "memory");
  18. return result;
  19. #elif defined(__x86_64__)
  20. char result;
  21. asm volatile ("lock; cmpxchgq %3, %0; setz %1" : "=m"(*x), "=q" (result) : "m" (*x), "r" (newval), "a" (oldval) : "memory");
  22. return result;
  23. #else
  24. #error architecture not supported and gcc too old, edit CAS.h
  25. #endif
  26. }
  27. /* *x += val; */
  28. static inline void atomic_add(size_t* x,size_t val) {
  29. #ifdef USE_BUILTINS
  30. __sync_add_and_fetch(x,val);
  31. #elif defined(__i386__)
  32. asm volatile ("lock; addl %1, %0" : "+m" (*x) : "ir" (val) );
  33. #elif defined(__x86_64__)
  34. asm volatile ("lock; addq %1, %0" : "+m" (*x) : "ir" (val) );
  35. #else
  36. #error architecture not supported and gcc too old, edit CAS.h
  37. #endif
  38. }
  39. /* return *x += val; */
  40. static inline size_t atomic_add_return(size_t* x,size_t val) {
  41. #ifdef USE_BUILTINS
  42. __sync_add_and_fetch(x,val);
  43. #elif defined(__i386__)
  44. size_t i = val;
  45. asm volatile ("lock; xaddl %1, %0" : "+m" (*x), "+r" (val) :: "memory" );
  46. return i + val;
  47. #elif defined(__x86_64__)
  48. size_t i = val;
  49. asm volatile ("lock; xaddq %1, %0" : "+m" (*x), "+r" (val) :: "memory" );
  50. return i + val;
  51. #else
  52. #error architecture not supported and gcc too old, edit CAS.h
  53. #endif
  54. }
  55. static inline void atomic_inc(size_t* x) {
  56. #ifdef __i386__
  57. asm volatile ("lock; incl %0" : "+m" (*x) );
  58. #elif defined(__x86_64__)
  59. asm volatile ("lock; incq %0" : "+m" (*x) );
  60. #else
  61. atomic_add(x,1);
  62. #endif
  63. }
  64. static inline size_t atomic_inc_return(size_t* x) {
  65. return atomic_add_return(x,1);
  66. }
  67. static inline void atomic_dec(size_t* x) {
  68. #ifdef __i386__
  69. asm volatile ("lock; decl %0" : "+m" (*x) );
  70. #elif defined(__x86_64__)
  71. asm volatile ("lock; decq %0" : "+m" (*x) );
  72. #else
  73. atomic_add(x,-1);
  74. #endif
  75. }
  76. static inline size_t atomic_dec_return(size_t* x) {
  77. return atomic_add_return(x,-1);
  78. }
  79. /* *x |= val; */
  80. static inline void atomic_or(volatile size_t* x,size_t val) {
  81. #ifdef USE_BUILTINS
  82. __sync_or_and_fetch(x,val);
  83. #elif defined(__i386__)
  84. asm volatile ("lock; orl %1, %0" : "+m" (*x) : "r" (val) );
  85. #elif defined(__x86_64__)
  86. asm volatile ("lock; orq %1, %0" : "+m" (*x) : "r" (val) );
  87. #else
  88. #error architecture not supported and gcc too old, edit CAS.h
  89. #endif
  90. }
  91. /* *x &= val; */
  92. static inline void atomic_and(volatile size_t* x,size_t val) {
  93. #ifdef USE_BUILTINS
  94. __sync_and_and_fetch(x,val);
  95. #elif defined(__i386__)
  96. asm volatile ("lock; andl %1, %0" : "+m" (*x) : "r" (val) );
  97. #elif defined(__x86_64__)
  98. asm volatile ("lock; andq %1, %0" : "+m" (*x) : "r" (val) );
  99. #else
  100. #error architecture not supported and gcc too old, edit CAS.h
  101. #endif
  102. }
  103. /* Optimization barrier */
  104. /* The "volatile" is due to gcc bugs */
  105. #define barrier() __asm__ __volatile__("": : :"memory")
  106. #if defined(__i386__) || defined(__x86_64__)
  107. #define mb() asm volatile("mfence":::"memory")
  108. #define rmb() asm volatile("lfence":::"memory")
  109. #define wmb() asm volatile("sfence":::"memory")
  110. /* Atomic operations are already serializing on x86 */
  111. #define smp_mb__before_atomic_dec() barrier()
  112. #define smp_mb__after_atomic_dec() barrier()
  113. #define smp_mb__before_atomic_inc() barrier()
  114. #define smp_mb__after_atomic_inc() barrier()
  115. #elif defined(__powerpc__)
  116. #define mb() asm volatile("sync":::"memory")
  117. #define rmb() asm volatile("sync":::"memory")
  118. #define wmb() asm volatile("sync":::"memory")
  119. #define smp_mb__before_atomic_dec() mb()
  120. #define smp_mb__after_atomic_dec() mb()
  121. #define smp_mb__before_atomic_inc() mb()
  122. #define smp_mb__after_atomic_inc() mb()
  123. #elif defined(USE_BUILTINS)
  124. #define mb() __sync_synchronize()
  125. #define rmb() __sync_synchronize()
  126. #define wmb() __sync_synchronize()
  127. #endif
  128. #undef USE_BUILTINS
  129. #endif