rtatomic.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-03-14 WangShun first version
  9. * 2023-05-20 Bernard add stdc atomic detection.
  10. */
  11. #ifndef __RT_ATOMIC_H__
  12. #define __RT_ATOMIC_H__
  13. #include <rthw.h>
  14. #if !defined(__cplusplus)
  15. rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr);
  16. void rt_hw_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val);
  17. rt_atomic_t rt_hw_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val);
  18. rt_atomic_t rt_hw_atomic_sub(volatile rt_atomic_t *ptr, rt_atomic_t val);
  19. rt_atomic_t rt_hw_atomic_and(volatile rt_atomic_t *ptr, rt_atomic_t val);
  20. rt_atomic_t rt_hw_atomic_or(volatile rt_atomic_t *ptr, rt_atomic_t val);
  21. rt_atomic_t rt_hw_atomic_xor(volatile rt_atomic_t *ptr, rt_atomic_t val);
  22. rt_atomic_t rt_hw_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val);
  23. void rt_hw_atomic_flag_clear(volatile rt_atomic_t *ptr);
  24. rt_atomic_t rt_hw_atomic_flag_test_and_set(volatile rt_atomic_t *ptr);
  25. rt_atomic_t rt_hw_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr, rt_atomic_t *expected, rt_atomic_t desired);
  26. /* To detect stdatomic */
  27. #if !defined(RT_USING_HW_ATOMIC) && !defined(RT_USING_STDC_ATOMIC)
  28. #if defined(__GNUC__) && defined(RT_USING_LIBC) && !defined(__STDC_NO_ATOMICS__)
  29. #define RT_USING_STDC_ATOMIC
  30. #endif /* __GNUC__ && .. */
  31. #endif /* !RT_USING_HW_ATOMIC && !RT_USING_STDC_ATOMIC */
  32. #if defined(RT_USING_HW_ATOMIC)
  33. #define rt_atomic_load(ptr) rt_hw_atomic_load(ptr)
  34. #define rt_atomic_store(ptr, v) rt_hw_atomic_store(ptr, v)
  35. #define rt_atomic_add(ptr, v) rt_hw_atomic_add(ptr, v)
  36. #define rt_atomic_sub(ptr, v) rt_hw_atomic_sub(ptr, v)
  37. #define rt_atomic_and(ptr, v) rt_hw_atomic_and(ptr, v)
  38. #define rt_atomic_or(ptr, v) rt_hw_atomic_or(ptr, v)
  39. #define rt_atomic_xor(ptr, v) rt_hw_atomic_xor(ptr, v)
  40. #define rt_atomic_exchange(ptr, v) rt_hw_atomic_exchange(ptr, v)
  41. #define rt_atomic_flag_clear(ptr) rt_hw_atomic_flag_clear(ptr)
  42. #define rt_atomic_flag_test_and_set(ptr) rt_hw_atomic_flag_test_and_set(ptr)
  43. #define rt_atomic_compare_exchange_strong(ptr, v,des) rt_hw_atomic_compare_exchange_strong(ptr, v ,des)
  44. #elif defined(RT_USING_STDC_ATOMIC)
  45. #ifndef __STDC_NO_ATOMICS__
  46. #define rt_atomic_load(ptr) atomic_load(ptr)
  47. #define rt_atomic_store(ptr, v) atomic_store(ptr, v)
  48. #define rt_atomic_add(ptr, v) atomic_fetch_add(ptr, v)
  49. #define rt_atomic_sub(ptr, v) atomic_fetch_sub(ptr, v)
  50. #define rt_atomic_and(ptr, v) atomic_fetch_and(ptr, v)
  51. #define rt_atomic_or(ptr, v) atomic_fetch_or(ptr, v)
  52. #define rt_atomic_xor(ptr, v) atomic_fetch_xor(ptr, v)
  53. #define rt_atomic_exchange(ptr, v) atomic_exchange(ptr, v)
  54. #define rt_atomic_flag_clear(ptr) atomic_flag_clear(ptr)
  55. #define rt_atomic_flag_test_and_set(ptr) atomic_flag_test_and_set(ptr)
  56. #define rt_atomic_compare_exchange_strong(ptr, v,des) atomic_compare_exchange_strong(ptr, v ,des)
  57. #else
  58. #error "The standard library C doesn't support the atomic operation"
  59. #endif /* __STDC_NO_ATOMICS__ */
  60. #else
  61. #include <rthw.h>
  62. #define rt_atomic_load(ptr) rt_soft_atomic_load(ptr)
  63. #define rt_atomic_store(ptr, v) rt_soft_atomic_store(ptr, v)
  64. #define rt_atomic_add(ptr, v) rt_soft_atomic_add(ptr, v)
  65. #define rt_atomic_sub(ptr, v) rt_soft_atomic_sub(ptr, v)
  66. #define rt_atomic_and(ptr, v) rt_soft_atomic_and(ptr, v)
  67. #define rt_atomic_or(ptr, v) rt_soft_atomic_or(ptr, v)
  68. #define rt_atomic_xor(ptr, v) rt_soft_atomic_xor(ptr, v)
  69. #define rt_atomic_exchange(ptr, v) rt_soft_atomic_exchange(ptr, v)
  70. #define rt_atomic_flag_clear(ptr) rt_soft_atomic_flag_clear(ptr)
  71. #define rt_atomic_flag_test_and_set(ptr) rt_soft_atomic_flag_test_and_set(ptr)
  72. #define rt_atomic_compare_exchange_strong(ptr, v,des) rt_soft_atomic_compare_exchange_strong(ptr, v ,des)
  73. rt_inline rt_atomic_t rt_soft_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val)
  74. {
  75. rt_base_t level;
  76. rt_atomic_t temp;
  77. level = rt_hw_interrupt_disable();
  78. temp = *ptr;
  79. *ptr = val;
  80. rt_hw_interrupt_enable(level);
  81. return temp;
  82. }
  83. rt_inline rt_atomic_t rt_soft_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val)
  84. {
  85. rt_base_t level;
  86. rt_atomic_t temp;
  87. level = rt_hw_interrupt_disable();
  88. temp = *ptr;
  89. *ptr += val;
  90. rt_hw_interrupt_enable(level);
  91. return temp;
  92. }
  93. rt_inline rt_atomic_t rt_soft_atomic_sub(volatile rt_atomic_t *ptr, rt_atomic_t val)
  94. {
  95. rt_base_t level;
  96. rt_atomic_t temp;
  97. level = rt_hw_interrupt_disable();
  98. temp = *ptr;
  99. *ptr -= val;
  100. rt_hw_interrupt_enable(level);
  101. return temp;
  102. }
  103. rt_inline rt_atomic_t rt_soft_atomic_xor(volatile rt_atomic_t *ptr, rt_atomic_t val)
  104. {
  105. rt_base_t level;
  106. rt_atomic_t temp;
  107. level = rt_hw_interrupt_disable();
  108. temp = *ptr;
  109. *ptr = (*ptr) ^ val;
  110. rt_hw_interrupt_enable(level);
  111. return temp;
  112. }
  113. rt_inline rt_atomic_t rt_soft_atomic_and(volatile rt_atomic_t *ptr, rt_atomic_t val)
  114. {
  115. rt_base_t level;
  116. rt_atomic_t temp;
  117. level = rt_hw_interrupt_disable();
  118. temp = *ptr;
  119. *ptr = (*ptr) & val;
  120. rt_hw_interrupt_enable(level);
  121. return temp;
  122. }
  123. rt_inline rt_atomic_t rt_soft_atomic_or(volatile rt_atomic_t *ptr, rt_atomic_t val)
  124. {
  125. rt_base_t level;
  126. rt_atomic_t temp;
  127. level = rt_hw_interrupt_disable();
  128. temp = *ptr;
  129. *ptr = (*ptr) | val;
  130. rt_hw_interrupt_enable(level);
  131. return temp;
  132. }
  133. rt_inline rt_atomic_t rt_soft_atomic_load(volatile rt_atomic_t *ptr)
  134. {
  135. rt_base_t level;
  136. rt_atomic_t temp;
  137. level = rt_hw_interrupt_disable();
  138. temp = *ptr;
  139. rt_hw_interrupt_enable(level);
  140. return temp;
  141. }
  142. rt_inline void rt_soft_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val)
  143. {
  144. rt_base_t level;
  145. level = rt_hw_interrupt_disable();
  146. *ptr = val;
  147. rt_hw_interrupt_enable(level);
  148. }
  149. rt_inline rt_atomic_t rt_soft_atomic_flag_test_and_set(volatile rt_atomic_t *ptr)
  150. {
  151. rt_base_t level;
  152. rt_atomic_t temp;
  153. level = rt_hw_interrupt_disable();
  154. if (*ptr == 0)
  155. {
  156. temp = 0;
  157. *ptr = 1;
  158. }
  159. else
  160. temp = 1;
  161. rt_hw_interrupt_enable(level);
  162. return temp;
  163. }
  164. rt_inline void rt_soft_atomic_flag_clear(volatile rt_atomic_t *ptr)
  165. {
  166. rt_base_t level;
  167. level = rt_hw_interrupt_disable();
  168. *ptr = 0;
  169. rt_hw_interrupt_enable(level);
  170. }
  171. rt_inline rt_atomic_t rt_soft_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr1, rt_atomic_t *ptr2,
  172. rt_atomic_t desired)
  173. {
  174. rt_base_t level;
  175. rt_atomic_t temp;
  176. level = rt_hw_interrupt_disable();
  177. if ((*ptr1) != (*ptr2))
  178. {
  179. *ptr2 = *ptr1;
  180. temp = 0;
  181. }
  182. else
  183. {
  184. *ptr1 = desired;
  185. temp = 1;
  186. }
  187. rt_hw_interrupt_enable(level);
  188. return temp;
  189. }
  190. #endif /* RT_USING_STDC_ATOMIC */
  191. rt_inline rt_bool_t rt_atomic_dec_and_test(volatile rt_atomic_t *ptr)
  192. {
  193. return rt_atomic_sub(ptr, 1) == 0;
  194. }
  195. rt_inline rt_atomic_t rt_atomic_fetch_add_unless(volatile rt_atomic_t *ptr, rt_atomic_t a, rt_atomic_t u)
  196. {
  197. rt_atomic_t c = rt_atomic_load(ptr);
  198. do {
  199. if (c == u)
  200. {
  201. break;
  202. }
  203. } while (!rt_atomic_compare_exchange_strong(ptr, &c, c + a));
  204. return c;
  205. }
  206. rt_inline rt_bool_t rt_atomic_add_unless(volatile rt_atomic_t *ptr, rt_atomic_t a, rt_atomic_t u)
  207. {
  208. return rt_atomic_fetch_add_unless(ptr, a, u) != u;
  209. }
  210. rt_inline rt_bool_t rt_atomic_inc_not_zero(volatile rt_atomic_t *ptr)
  211. {
  212. return rt_atomic_add_unless(ptr, 1, 0);
  213. }
  214. #endif /* __cplusplus */
  215. #endif /* __RT_ATOMIC_H__ */