rtatomic.h 7.0 KB

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