test_atomic.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (c) 2018 Richard Braun.
  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. * This test makes sure that atomic operations behave at least as their
  19. * non-atomic counterpart. It doesn't actually test the atomicity of the
  20. * operations, but rather helps check that the generated code matches
  21. * expectations for the target configuration.
  22. */
  23. #include <errno.h>
  24. #include <stdbool.h>
  25. #include <stdint.h>
  26. #include <stdio.h>
  27. #include <kern/atomic.h>
  28. #include <kern/error.h>
  29. #include <kern/init.h>
  30. #include <kern/log.h>
  31. #include <kern/macros.h>
  32. #include <test/test.h>
  33. #ifdef CONFIG_TEST_MODULE_ATOMIC_64
  34. typedef uint64_t test_int_t;
  35. #else
  36. typedef unsigned long test_int_t;
  37. #endif
  38. /*
  39. * Don't make this variable private, so that the compiler may not assume
  40. * that all accesses are known, which forces it to generate access
  41. * instructions for it. This only works when building without LTO.
  42. */
  43. test_int_t test_n;
  44. /*
  45. * Prevent these functions from being inlined in order to make the generated
  46. * code easy to find and review.
  47. */
  48. static __noinline test_int_t
  49. test_atomic_load (test_int_t *n)
  50. {
  51. return (atomic_load_rlx (n));
  52. }
  53. static __noinline void
  54. test_atomic_store (test_int_t *n, test_int_t val)
  55. {
  56. atomic_store_rlx (n, val);
  57. }
  58. static __noinline test_int_t
  59. test_atomic_cas (test_int_t *n, test_int_t oval, test_int_t nval)
  60. {
  61. return (atomic_cas_rlx (n, oval, nval));
  62. }
  63. static __noinline test_int_t
  64. test_atomic_swap (test_int_t *n, test_int_t val)
  65. {
  66. return (atomic_swap_rlx (n, val));
  67. }
  68. static __noinline test_int_t
  69. test_atomic_fetch_add (test_int_t *n, test_int_t val)
  70. {
  71. return (atomic_add_rlx (n, val));
  72. }
  73. static __noinline test_int_t
  74. test_atomic_fetch_sub (test_int_t *n, test_int_t val)
  75. {
  76. return (atomic_sub_rlx (n, val));
  77. }
  78. static __noinline test_int_t
  79. test_atomic_fetch_and (test_int_t *n, test_int_t val)
  80. {
  81. return (atomic_and_rlx (n, val));
  82. }
  83. static __noinline test_int_t
  84. test_atomic_fetch_or (test_int_t *n, test_int_t val)
  85. {
  86. return (atomic_or_rlx (n, val));
  87. }
  88. static __noinline test_int_t
  89. test_atomic_fetch_xor (test_int_t *n, test_int_t val)
  90. {
  91. return (atomic_xor_rlx (n, val));
  92. }
  93. static void
  94. test_check_n (test_int_t val, const char *fn)
  95. {
  96. volatile test_int_t *ptr = &test_n;
  97. int error = val == *ptr ? 0 : EINVAL;
  98. error_check (error, fn);
  99. }
  100. static void
  101. test_load (void)
  102. {
  103. test_int_t n = test_atomic_load (&test_n);
  104. test_check_n (n, __func__);
  105. }
  106. static void
  107. test_store (void)
  108. {
  109. test_int_t val = 0x123;
  110. test_atomic_store (&test_n, val);
  111. test_check_n (val, __func__);
  112. }
  113. static void
  114. test_cas_match (void)
  115. {
  116. test_int_t oval = 0, nval = 0x123;
  117. test_n = oval;
  118. test_int_t prev = test_atomic_cas (&test_n, oval, nval);
  119. int error = prev == oval ? 0 : EINVAL;
  120. error_check (error, __func__);
  121. test_check_n (nval, __func__);
  122. }
  123. static void
  124. test_cas_nomatch (void)
  125. {
  126. test_int_t oval = 0, nval = 0x123;
  127. test_n = oval;
  128. test_int_t prev = test_atomic_cas (&test_n, oval + 1, nval);
  129. int error = prev == oval ? 0 : EINVAL;
  130. error_check (error, __func__);
  131. test_check_n (oval, __func__);
  132. }
  133. static void
  134. test_swap (void)
  135. {
  136. test_int_t oval = 0, nval = 0x123;
  137. test_n = oval;
  138. test_int_t prev = test_atomic_swap (&test_n, nval);
  139. int error = prev == oval ? 0 : EINVAL;
  140. error_check (error, __func__);
  141. test_check_n (nval, __func__);
  142. }
  143. static void
  144. test_fetch_add (void)
  145. {
  146. test_int_t oval = 0x123, delta = 0x456;
  147. test_n = oval;
  148. test_int_t prev = test_atomic_fetch_add (&test_n, delta);
  149. int error = prev == oval ? 0 : EINVAL;
  150. error_check (error, __func__);
  151. test_check_n (oval + delta, __func__);
  152. }
  153. static void
  154. test_fetch_sub (void)
  155. {
  156. test_int_t oval = 0x123, delta = 0x456;
  157. test_n = oval;
  158. test_int_t prev = test_atomic_fetch_sub (&test_n, delta);
  159. int error = prev == oval ? 0 : EINVAL;
  160. error_check (error, __func__);
  161. test_check_n (oval - delta, __func__);
  162. }
  163. static void
  164. test_fetch_and (void)
  165. {
  166. test_int_t oval = 0x123, delta = 0x456;
  167. test_n = oval;
  168. test_int_t prev = test_atomic_fetch_and (&test_n, delta);
  169. int error = prev == oval ? 0 : EINVAL;
  170. error_check (error, __func__);
  171. test_check_n (oval & delta, __func__);
  172. }
  173. static void
  174. test_fetch_or (void)
  175. {
  176. test_int_t oval = 0x123, delta = 0x456;
  177. test_n = oval;
  178. test_int_t prev = test_atomic_fetch_or (&test_n, delta);
  179. int error = prev == oval ? 0 : EINVAL;
  180. error_check (error, __func__);
  181. test_check_n (oval | delta, __func__);
  182. }
  183. static void
  184. test_fetch_xor (void)
  185. {
  186. test_int_t oval = 0x123, delta = 0x456;
  187. test_n = oval;
  188. test_int_t prev = test_atomic_fetch_xor (&test_n, delta);
  189. int error = prev == oval ? 0 : EINVAL;
  190. error_check (error, __func__);
  191. test_check_n (oval ^ delta, __func__);
  192. }
  193. TEST_INLINE (atomic_ops)
  194. {
  195. test_load ();
  196. test_store ();
  197. test_cas_match ();
  198. test_cas_nomatch ();
  199. test_swap ();
  200. test_fetch_add ();
  201. test_fetch_sub ();
  202. test_fetch_and ();
  203. test_fetch_or ();
  204. test_fetch_xor ();
  205. return (TEST_OK);
  206. }