atomic.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /* Copyright (C) 2010-2012 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library. If not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #ifndef _KVX_BITS_ATOMIC_H
  16. #define _KVX_BITS_ATOMIC_H
  17. #include <stdint.h>
  18. typedef int8_t atomic8_t;
  19. typedef uint8_t uatomic8_t;
  20. typedef int_fast8_t atomic_fast8_t;
  21. typedef uint_fast8_t uatomic_fast8_t;
  22. typedef int16_t atomic16_t;
  23. typedef uint16_t uatomic16_t;
  24. typedef int_fast16_t atomic_fast16_t;
  25. typedef uint_fast16_t uatomic_fast16_t;
  26. typedef int32_t atomic32_t;
  27. typedef uint32_t uatomic32_t;
  28. typedef int_fast32_t atomic_fast32_t;
  29. typedef uint_fast32_t uatomic_fast32_t;
  30. typedef int64_t atomic64_t;
  31. typedef uint64_t uatomic64_t;
  32. typedef int_fast64_t atomic_fast64_t;
  33. typedef uint_fast64_t uatomic_fast64_t;
  34. typedef intptr_t atomicptr_t;
  35. typedef uintptr_t uatomicptr_t;
  36. typedef intmax_t atomic_max_t;
  37. typedef uintmax_t uatomic_max_t;
  38. #ifndef atomic_full_barrier
  39. # define atomic_full_barrier() do { atomic_read_barrier(); \
  40. atomic_write_barrier(); } while(0)
  41. #endif
  42. #ifndef atomic_read_barrier
  43. # define atomic_read_barrier() __builtin_kvx_dinval()
  44. #endif
  45. #ifndef atomic_write_barrier
  46. # define atomic_write_barrier() __builtin_kvx_fence()
  47. #endif
  48. /*
  49. * On kvx, we have a boolean compare and swap which means that the operation
  50. * returns only the success of operation.
  51. * If operation succeeds, this is simple, we just need to return the provided
  52. * old value. However, if it fails, we need to load the value to return it for
  53. * the caller. If the loaded value is different from the "old" provided by the
  54. * caller, we can return it since it will mean it failed.
  55. * However, if for some reason the value we read is equal to the old value
  56. * provided by the caller, we can't simply return it or the caller will think it
  57. * succeeded. So if the value we read is the same as the "old" provided by
  58. * the caller, we try again until either we succeed or we fail with a different
  59. * value than the provided one.
  60. */
  61. #define __cmpxchg(ptr, old, new, op_suffix, load_suffix) \
  62. ({ \
  63. register unsigned long __rn __asm__("r62"); \
  64. register unsigned long __ro __asm__("r63"); \
  65. __asm__ __volatile__ ( \
  66. /* Fence to guarantee previous store to be committed */ \
  67. "fence\n" \
  68. /* Init "expect" with previous value */ \
  69. "copyd $r63 = %[rOld]\n" \
  70. ";;\n" \
  71. "1:\n" \
  72. /* Init "update" value with new */ \
  73. "copyd $r62 = %[rNew]\n" \
  74. ";;\n" \
  75. "acswap" #op_suffix " 0[%[rPtr]], $r62r63\n" \
  76. ";;\n" \
  77. /* if acswap succeeds, simply return */ \
  78. "cb.dnez $r62? 2f\n" \
  79. ";;\n" \
  80. /* We failed, load old value */ \
  81. "l" #op_suffix #load_suffix" $r63 = 0[%[rPtr]]\n" \
  82. ";;\n" \
  83. /* Check if equal to "old" one */ \
  84. "compd.ne $r62 = $r63, %[rOld]\n" \
  85. ";;\n" \
  86. /* If different from "old", return it to caller */ \
  87. "cb.deqz $r62? 1b\n" \
  88. ";;\n" \
  89. "2:\n" \
  90. : "+r" (__rn), "+r" (__ro) \
  91. : [rPtr] "r" (ptr), [rOld] "r" (old), [rNew] "r" (new) \
  92. : "memory"); \
  93. (__ro); \
  94. })
  95. #define cmpxchg(ptr, o, n) \
  96. ({ \
  97. unsigned long __cmpxchg__ret; \
  98. switch (sizeof(*(ptr))) { \
  99. case 4: \
  100. __cmpxchg__ret = __cmpxchg((ptr), (o), (n), w, s); \
  101. break; \
  102. case 8: \
  103. __cmpxchg__ret = __cmpxchg((ptr), (o), (n), d, ); \
  104. break; \
  105. } \
  106. (__typeof(*(ptr))) (__cmpxchg__ret); \
  107. })
  108. #define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
  109. cmpxchg((mem), (oldval), (newval))
  110. #define atomic_exchange_acq(mem, newval) \
  111. ({ \
  112. unsigned long __aea__ret, __aea__old; \
  113. volatile __typeof((mem)) __aea__m = (mem); \
  114. do { \
  115. __aea__old = *__aea__m; \
  116. __aea__ret = atomic_compare_and_exchange_val_acq((mem), \
  117. (newval), (__aea__old));\
  118. } while (__aea__old != __aea__ret); \
  119. (__aea__old); \
  120. })
  121. #endif