atomic.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. do \
  46. { \
  47. typeof (val) val_ = (val); \
  48. if (sizeof (*(place)) == sizeof (uint64_t)) \
  49. atomic_store_64 ((place), &val_, (mo)); \
  50. else \
  51. __atomic_store_n ((place), val_, (mo)); \
  52. } \
  53. while (0)
  54. #endif
  55. #define atomic_op(place, op, ...) __atomic_##op (place, ##__VA_ARGS__)
  56. // Needed since we use different names.
  57. #define __atomic_swap __atomic_exchange_n
  58. #define __atomic_read __atomic_load_n
  59. #define __atomic_write __atomic_store_n
  60. #ifndef atomic_load
  61. #define atomic_load(place, mo) atomic_op (place, read, mo)
  62. #endif
  63. #ifndef atomic_store
  64. #define atomic_store(place, val, mo) atomic_op (place, write, val, mo)
  65. #endif
  66. #define atomic_add(place, val, mo) atomic_op (place, fetch_add, val, mo)
  67. #define atomic_sub(place, val, mo) atomic_op (place, fetch_sub, val, mo)
  68. #define atomic_and(place, val, mo) atomic_op (place, fetch_and, val, mo)
  69. #define atomic_or(place, val, mo) atomic_op (place, fetch_or, val, mo)
  70. #define atomic_xor(place, val, mo) atomic_op (place, fetch_xor, val, mo)
  71. #define atomic_swap(place, val, mo) atomic_op (place, swap, val, mo)
  72. #define atomic_cas(place, exp, val, mo) atomic_op (place, cas, exp, val, mo)
  73. #define atomic_cas_bool(place, exp, val, mo) \
  74. ({ \
  75. typeof (*(place)) sexp_ = (exp); \
  76. atomic_cas (place, sexp_, val, mo) == sexp_; \
  77. })
  78. #define atomic_fence(mo) __atomic_thread_fence (mo)
  79. // Common shortcuts.
  80. #define atomic_load_rlx(place) atomic_load ((place), ATOMIC_RELAXED)
  81. #define atomic_load_acq(place) atomic_load ((place), ATOMIC_ACQUIRE)
  82. #define atomic_load_seq(place) atomic_load ((place), ATOMIC_SEQ_CST)
  83. #define atomic_store_rlx(place, val) \
  84. atomic_store ((place), (val), ATOMIC_RELAXED)
  85. #define atomic_store_rel(place, val) \
  86. atomic_store ((place), (val), ATOMIC_RELEASE)
  87. #define atomic_store_seq(place, val) \
  88. atomic_store ((place), (val), ATOMIC_SEQ_CST)
  89. #define atomic_add_rlx(place, val) \
  90. atomic_add ((place), (val), ATOMIC_RELAXED)
  91. #define atomic_add_rel(place, val) \
  92. atomic_add ((place), (val), ATOMIC_RELEASE)
  93. #define atomic_sub_rlx(place, val) \
  94. atomic_sub ((place), (val), ATOMIC_RELAXED)
  95. #define atomic_sub_rel(place, val) \
  96. atomic_sub ((place), (val), ATOMIC_RELEASE)
  97. #define atomic_sub_acq_rel(place, val) \
  98. atomic_sub ((place), (val), ATOMIC_ACQ_REL)
  99. #define atomic_and_rlx(place, val) \
  100. atomic_and ((place), (val), ATOMIC_RELAXED)
  101. #define atomic_and_rel(place, val) \
  102. atomic_and ((place), (val), ATOMIC_RELEASE)
  103. #define atomic_or_rlx(place, val) \
  104. atomic_or ((place), (val), ATOMIC_RELAXED)
  105. #define atomic_or_rel(place, val) \
  106. atomic_or ((place), (val), ATOMIC_RELEASE)
  107. #define atomic_xor_rlx(place, val) \
  108. atomic_xor ((place), (val), ATOMIC_RELAXED)
  109. #define atomic_xor_rel(place, val) \
  110. atomic_xor ((place), (val), ATOMIC_RELEASE)
  111. #define atomic_cas_rlx(place, exp, val) \
  112. atomic_cas ((place), (exp), (val), ATOMIC_RELAXED)
  113. #define atomic_cas_acq(place, exp, val) \
  114. atomic_cas ((place), (exp), (val), ATOMIC_ACQUIRE)
  115. #define atomic_cas_rel(place, exp, val) \
  116. atomic_cas ((place), (exp), (val), ATOMIC_RELEASE)
  117. #define atomic_cas_acq_rel(place, exp, val) \
  118. atomic_cas ((place), (exp), (val), ATOMIC_ACQ_REL)
  119. #define atomic_cas_bool_rlx(place, exp, val) \
  120. atomic_cas_bool ((place), (exp), (val), ATOMIC_RELAXED)
  121. #define atomic_cas_bool_acq(place, exp, val) \
  122. atomic_cas_bool ((place), (exp), (val), ATOMIC_ACQUIRE)
  123. #define atomic_cas_bool_rel(place, exp, val) \
  124. atomic_cas_bool ((place), (exp), (val), ATOMIC_RELEASE)
  125. #define atomic_swap_rlx(place, val) \
  126. atomic_swap ((place), (val), ATOMIC_RELAXED)
  127. #define atomic_swap_rel(place, val) \
  128. atomic_swap ((place), (val), ATOMIC_RELEASE)
  129. #define atomic_fence_acq() atomic_fence (ATOMIC_ACQUIRE)
  130. #define atomic_fence_rel() atomic_fence (ATOMIC_RELEASE)
  131. #define atomic_fence_acq_rel() atomic_fence (ATOMIC_ACQ_REL)
  132. #define atomic_fence_seq() atomic_fence (ATOMIC_SEQ_CST)
  133. #endif