latomic.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * Copyright (c) 2018 Agustina Arzille.
  3. * Copyright (c) 2018 Richard Braun.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. *
  19. * CPU-local atomic operations.
  20. *
  21. * The latomic module provides operations that are "atomic on the local
  22. * processor", i.e. interrupt-safe. Its interface is similar in spirit
  23. * and purpose to that of the atomic module, and it can transparently
  24. * replace it on single-processor configurations.
  25. *
  26. * Note that the only operations guaranteed to be truely atomic, i.e.
  27. * to completely execute in a single atomic instruction, are loads and
  28. * stores. All other operations may be implemented with multiple
  29. * instructions, possibly disabling interrupts. The rationale is that
  30. * atomic loads and stores are required for some types of access, such
  31. * as memory-mapped device registers, while other operations only require
  32. * interrupt safety.
  33. *
  34. * Also note that interrupts are considered to strictly match the definition
  35. * of signals as described in the specification of program execution in
  36. * the C language. This defines the forms of communication allowed with
  37. * interrupts handlers.
  38. *
  39. * This header provides a generic implementation. Architectures can
  40. * individually override any of the operations provided by this module.
  41. */
  42. #ifndef KERN_LATOMIC_H
  43. #define KERN_LATOMIC_H
  44. #include <assert.h>
  45. #include <kern/macros.h>
  46. /*
  47. * Memory orders for local atomic operations.
  48. *
  49. * These work like those in the atomic module, but are implemented
  50. * with simple compiler barriers instead of full memory fences.
  51. */
  52. #define LATOMIC_RELAXED __ATOMIC_RELAXED
  53. #define LATOMIC_ACQUIRE __ATOMIC_ACQUIRE
  54. #define LATOMIC_RELEASE __ATOMIC_RELEASE
  55. #define LATOMIC_ACQ_REL __ATOMIC_ACQ_REL
  56. #define LATOMIC_SEQ_CST __ATOMIC_SEQ_CST
  57. #include <kern/latomic_i.h>
  58. #define latomic_load(ptr, memorder) \
  59. MACRO_BEGIN \
  60. assert(latomic_ptr_aligned(ptr)); \
  61. ((typeof(*(ptr)))latomic_select(ptr, load)(ptr, memorder)); \
  62. MACRO_END
  63. #define latomic_store(ptr, val, memorder) \
  64. MACRO_BEGIN \
  65. assert(latomic_ptr_aligned(ptr)); \
  66. latomic_select(ptr, store)(ptr, val, memorder); \
  67. MACRO_END
  68. #define latomic_swap(ptr, val, memorder) \
  69. MACRO_BEGIN \
  70. assert(latomic_ptr_aligned(ptr)); \
  71. ((typeof(*(ptr)))latomic_select(ptr, swap)(ptr, val, memorder)); \
  72. MACRO_END
  73. #define latomic_cas(ptr, oval, nval, memorder) \
  74. MACRO_BEGIN \
  75. assert(latomic_ptr_aligned(ptr)); \
  76. ((typeof(*(ptr)))latomic_select(ptr, cas)(ptr, oval, nval, memorder)); \
  77. MACRO_END
  78. #define latomic_fetch_add(ptr, val, memorder) \
  79. MACRO_BEGIN \
  80. assert(latomic_ptr_aligned(ptr)); \
  81. ((typeof(*(ptr)))latomic_select(ptr, fetch_add)(ptr, val, memorder)); \
  82. MACRO_END
  83. #define latomic_fetch_sub(ptr, val, memorder) \
  84. MACRO_BEGIN \
  85. assert(latomic_ptr_aligned(ptr)); \
  86. ((typeof(*(ptr)))latomic_select(ptr, fetch_sub)(ptr, val, memorder)); \
  87. MACRO_END
  88. #define latomic_fetch_and(ptr, val, memorder) \
  89. MACRO_BEGIN \
  90. assert(latomic_ptr_aligned(ptr)); \
  91. ((typeof(*(ptr)))latomic_select(ptr, fetch_and)(ptr, val, memorder)); \
  92. MACRO_END
  93. #define latomic_fetch_or(ptr, val, memorder) \
  94. MACRO_BEGIN \
  95. assert(latomic_ptr_aligned(ptr)); \
  96. ((typeof(*(ptr)))latomic_select(ptr, fetch_or)(ptr, val, memorder)); \
  97. MACRO_END
  98. #define latomic_fetch_xor(ptr, val, memorder) \
  99. MACRO_BEGIN \
  100. assert(latomic_ptr_aligned(ptr)); \
  101. ((typeof(*(ptr)))latomic_select(ptr, fetch_xor)(ptr, val, memorder)); \
  102. MACRO_END
  103. #define latomic_add(ptr, val, memorder) \
  104. MACRO_BEGIN \
  105. assert(latomic_ptr_aligned(ptr)); \
  106. latomic_select(ptr, add)(ptr, val, memorder); \
  107. MACRO_END
  108. #define latomic_sub(ptr, val, memorder) \
  109. MACRO_BEGIN \
  110. assert(latomic_ptr_aligned(ptr)); \
  111. latomic_select(ptr, sub)(ptr, val, memorder); \
  112. MACRO_END
  113. #define latomic_and(ptr, val, memorder) \
  114. MACRO_BEGIN \
  115. assert(latomic_ptr_aligned(ptr)); \
  116. latomic_select(ptr, and)(ptr, val, memorder); \
  117. MACRO_END
  118. #define latomic_or(ptr, val, memorder) \
  119. MACRO_BEGIN \
  120. assert(latomic_ptr_aligned(ptr)); \
  121. latomic_select(ptr, or)(ptr, val, memorder); \
  122. MACRO_END
  123. #define latomic_xor(ptr, val, memorder) \
  124. MACRO_BEGIN \
  125. assert(latomic_ptr_aligned(ptr)); \
  126. latomic_select(ptr, xor)(ptr, val, memorder); \
  127. MACRO_END
  128. #define latomic_fence(memorder) __atomic_signal_fence(memorder)
  129. #endif /* KERN_LATOMIC_H */