atomic.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * Copyright (c) 2022 Agustina Arzille.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. *
  18. * Type-generic, memory-model-aware atomic operations.
  19. */
  20. #ifndef KERN_ATOMIC_H
  21. #define KERN_ATOMIC_H 1
  22. #include <assert.h>
  23. #include <stdbool.h>
  24. #include <machine/atomic.h>
  25. // Supported memory orders.
  26. #define ATOMIC_RELAXED __ATOMIC_RELAXED
  27. #define ATOMIC_CONSUME __ATOMIC_CONSUME
  28. #define ATOMIC_ACQUIRE __ATOMIC_ACQUIRE
  29. #define ATOMIC_RELEASE __ATOMIC_RELEASE
  30. #define ATOMIC_ACQ_REL __ATOMIC_ACQ_REL
  31. #define ATOMIC_SEQ_CST __ATOMIC_SEQ_CST
  32. #define __atomic_cas(place, exp, nval, mo) \
  33. ({ \
  34. typeof (*(place)) exp_ = (exp); \
  35. __atomic_compare_exchange_n ((place), &exp_, (nval), true, \
  36. (mo), ATOMIC_RELAXED); \
  37. exp_; \
  38. })
  39. #if !defined (__LP64__) && defined (ATOMIC_HAVE_64B_OPS)
  40. #define atomic_load(place, mo) \
  41. __builtin_choose_expr (sizeof (*(place)) == sizeof (uint64_t), \
  42. atomic_load_64 ((place), (mo)), \
  43. __atomic_load_n ((place), (mo)))
  44. #define atomic_store(place, val, mo) \
  45. ({ \
  46. typeof (val) val_ = (val); \
  47. if (sizeof (*(place)) == sizeof (uint64_t)) \
  48. atomic_store_64 ((place), &val_, (mo)); \
  49. else \
  50. __atomic_store_n ((place), val_, (mo)); \
  51. (void)0; \
  52. })
  53. #endif
  54. #define atomic_op(place, op, ...) __atomic_##op (place, ##__VA_ARGS__)
  55. // Needed since we use different names.
  56. #define __atomic_swap __atomic_exchange_n
  57. #define __atomic_read __atomic_load_n
  58. #define __atomic_write __atomic_store_n
  59. #ifndef atomic_load
  60. #define atomic_load(place, mo) atomic_op (place, read, mo)
  61. #endif
  62. #ifndef atomic_store
  63. #define atomic_store(place, val, mo) atomic_op (place, write, val, mo)
  64. #endif
  65. #define atomic_add(place, val, mo) atomic_op (place, fetch_add, val, mo)
  66. #define atomic_sub(place, val, mo) atomic_op (place, fetch_sub, val, mo)
  67. #define atomic_and(place, val, mo) atomic_op (place, fetch_and, val, mo)
  68. #define atomic_or(place, val, mo) atomic_op (place, fetch_or, val, mo)
  69. #define atomic_xor(place, val, mo) atomic_op (place, fetch_xor, val, mo)
  70. #define atomic_swap(place, val, mo) atomic_op (place, swap, val, mo)
  71. #define atomic_cas(place, exp, val, mo) atomic_op (place, cas, exp, val, mo)
  72. #define atomic_cas_bool(place, exp, val, mo) \
  73. ({ \
  74. typeof (*(place)) sexp_ = (exp); \
  75. atomic_cas (place, sexp_, val, mo) == sexp_; \
  76. })
  77. #define atomic_fence(mo) __atomic_thread_fence (mo)
  78. #ifndef atomic_spin_nop
  79. #define atomic_spin_nop() atomic_fence (ATOMIC_SEQ_CST)
  80. #endif
  81. // Common shortcuts.
  82. #define atomic_load_rlx(place) atomic_load ((place), ATOMIC_RELAXED)
  83. #define atomic_load_acq(place) atomic_load ((place), ATOMIC_ACQUIRE)
  84. #define atomic_load_seq(place) atomic_load ((place), ATOMIC_SEQ_CST)
  85. #define atomic_store_rlx(...) atomic_store (__VA_ARGS__, ATOMIC_RELAXED)
  86. #define atomic_store_rel(...) atomic_store (__VA_ARGS__, ATOMIC_RELEASE)
  87. #define atomic_store_seq(...) atomic_store (__VA_ARGS__, ATOMIC_SEQ_CST)
  88. #define atomic_add_rlx(...) atomic_add (__VA_ARGS__, ATOMIC_RELAXED)
  89. #define atomic_add_rel(...) atomic_add (__VA_ARGS__, ATOMIC_RELEASE)
  90. #define atomic_sub_rlx(...) atomic_sub (__VA_ARGS__, ATOMIC_RELAXED)
  91. #define atomic_sub_rel(...) atomic_sub (__VA_ARGS__, ATOMIC_RELEASE)
  92. #define atomic_sub_acq_rel(...) atomic_sub (__VA_ARGS__, ATOMIC_ACQ_REL)
  93. #define atomic_and_rlx(...) atomic_and (__VA_ARGS__, ATOMIC_RELAXED)
  94. #define atomic_and_rel(...) atomic_and (__VA_ARGS__, ATOMIC_RELEASE)
  95. #define atomic_or_rlx(...) atomic_or (__VA_ARGS__, ATOMIC_RELAXED)
  96. #define atomic_or_rel(...) atomic_or (__VA_ARGS__, ATOMIC_RELEASE)
  97. #define atomic_xor_rlx(...) atomic_xor (__VA_ARGS__, ATOMIC_RELAXED)
  98. #define atomic_xor_rel(...) atomic_xor (__VA_ARGS__, ATOMIC_RELEASE)
  99. #define atomic_cas_rlx(...) atomic_cas (__VA_ARGS__, ATOMIC_RELAXED)
  100. #define atomic_cas_acq(...) atomic_cas (__VA_ARGS__, ATOMIC_ACQUIRE)
  101. #define atomic_cas_rel(...) atomic_cas (__VA_ARGS__, ATOMIC_RELEASE)
  102. #define atomic_cas_acq_rel(...) atomic_cas (__VA_ARGS__, ATOMIC_ACQ_REL)
  103. #define atomic_cas_bool_rlx(...) \
  104. atomic_cas_bool (__VA_ARGS__, ATOMIC_RELAXED)
  105. #define atomic_cas_bool_acq(...) \
  106. atomic_cas_bool (__VA_ARGS__, ATOMIC_ACQUIRE)
  107. #define atomic_cas_bool_rel(...) \
  108. atomic_cas_bool (__VA_ARGS__, ATOMIC_RELEASE)
  109. #define atomic_cas_bool_acq_rel(...) \
  110. atomic_cas_bool (__VA_ARGS__, ATOMIC_ACQ_REL)
  111. #define atomic_swap_rlx(...) atomic_swap (__VA_ARGS__, ATOMIC_RELAXED)
  112. #define atomic_swap_rel(...) atomic_swap (__VA_ARGS__, ATOMIC_RELEASE)
  113. #define atomic_fence_acq() atomic_fence (ATOMIC_ACQUIRE)
  114. #define atomic_fence_rel() atomic_fence (ATOMIC_RELEASE)
  115. #define atomic_fence_acq_rel() atomic_fence (ATOMIC_ACQ_REL)
  116. #define atomic_fence_seq() atomic_fence (ATOMIC_SEQ_CST)
  117. /*
  118. * Try to increment a counter from a non-zero value.
  119. * Evaluates to true on success.
  120. */
  121. #define atomic_try_inc(place, mo) \
  122. ({ \
  123. bool done_ = true; \
  124. _Auto place_ = (place); \
  125. while (1) \
  126. { \
  127. _Auto tmp_ = atomic_load_rlx (place_); \
  128. if (!tmp_) \
  129. { \
  130. done_ = false; \
  131. break; \
  132. } \
  133. else if (atomic_cas_bool (place_, tmp_, tmp_ + 1, (mo))) \
  134. break; \
  135. \
  136. atomic_spin_nop (); \
  137. } \
  138. done_; \
  139. })
  140. #endif