test_atomic.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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(n, ATOMIC_RELAXED);
  52. }
  53. static __noinline void
  54. test_atomic_store(test_int_t *n, test_int_t val)
  55. {
  56. atomic_store(n, val, ATOMIC_RELAXED);
  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(n, oval, nval, ATOMIC_RELAXED);
  62. }
  63. static __noinline test_int_t
  64. test_atomic_swap(test_int_t *n, test_int_t val)
  65. {
  66. return atomic_swap(n, val, ATOMIC_RELAXED);
  67. }
  68. static __noinline test_int_t
  69. test_atomic_fetch_add(test_int_t *n, test_int_t val)
  70. {
  71. return atomic_fetch_add(n, val, ATOMIC_RELAXED);
  72. }
  73. static __noinline test_int_t
  74. test_atomic_fetch_sub(test_int_t *n, test_int_t val)
  75. {
  76. return atomic_fetch_sub(n, val, ATOMIC_RELAXED);
  77. }
  78. static __noinline test_int_t
  79. test_atomic_fetch_and(test_int_t *n, test_int_t val)
  80. {
  81. return atomic_fetch_and(n, val, ATOMIC_RELAXED);
  82. }
  83. static __noinline test_int_t
  84. test_atomic_fetch_or(test_int_t *n, test_int_t val)
  85. {
  86. return atomic_fetch_or(n, val, ATOMIC_RELAXED);
  87. }
  88. static __noinline test_int_t
  89. test_atomic_fetch_xor(test_int_t *n, test_int_t val)
  90. {
  91. return atomic_fetch_xor(n, val, ATOMIC_RELAXED);
  92. }
  93. static __noinline void
  94. test_atomic_add(test_int_t *n, test_int_t val)
  95. {
  96. atomic_add(n, val, ATOMIC_RELAXED);
  97. }
  98. static __noinline void
  99. test_atomic_sub(test_int_t *n, test_int_t val)
  100. {
  101. atomic_sub(n, val, ATOMIC_RELAXED);
  102. }
  103. static __noinline void
  104. test_atomic_and(test_int_t *n, test_int_t val)
  105. {
  106. atomic_and(n, val, ATOMIC_RELAXED);
  107. }
  108. static __noinline void
  109. test_atomic_or(test_int_t *n, test_int_t val)
  110. {
  111. atomic_or(n, val, ATOMIC_RELAXED);
  112. }
  113. static __noinline void
  114. test_atomic_xor(test_int_t *n, test_int_t val)
  115. {
  116. atomic_xor(n, val, ATOMIC_RELAXED);
  117. }
  118. static void
  119. test_check_n(test_int_t val, const char *fn)
  120. {
  121. volatile test_int_t *ptr;
  122. int error;
  123. ptr = &test_n;
  124. error = (val == *ptr) ? 0 : EINVAL;
  125. error_check(error, fn);
  126. }
  127. static void
  128. test_load(void)
  129. {
  130. test_int_t n;
  131. n = test_atomic_load(&test_n);
  132. test_check_n(n, __func__);
  133. }
  134. static void
  135. test_store(void)
  136. {
  137. test_int_t val;
  138. val = 0x123;
  139. test_atomic_store(&test_n, val);
  140. test_check_n(val, __func__);
  141. }
  142. static void
  143. test_cas_match(void)
  144. {
  145. test_int_t prev, oval, nval;
  146. int error;
  147. oval = 0;
  148. nval = 0x123;
  149. test_n = oval;
  150. prev = test_atomic_cas(&test_n, oval, nval);
  151. error = (prev == oval) ? 0 : EINVAL;
  152. error_check(error, __func__);
  153. test_check_n(nval, __func__);
  154. }
  155. static void
  156. test_cas_nomatch(void)
  157. {
  158. test_int_t prev, oval, nval;
  159. int error;
  160. oval = 0;
  161. nval = 0x123;
  162. test_n = oval;
  163. prev = test_atomic_cas(&test_n, oval + 1, nval);
  164. error = (prev == oval) ? 0 : EINVAL;
  165. error_check(error, __func__);
  166. test_check_n(oval, __func__);
  167. }
  168. static void
  169. test_swap(void)
  170. {
  171. test_int_t prev, oval, nval;
  172. int error;
  173. oval = 0;
  174. nval = 0x123;
  175. test_n = oval;
  176. prev = test_atomic_swap(&test_n, nval);
  177. error = (prev == oval) ? 0 : EINVAL;
  178. error_check(error, __func__);
  179. test_check_n(nval, __func__);
  180. }
  181. static void
  182. test_fetch_add(void)
  183. {
  184. test_int_t prev, oval, delta;
  185. int error;
  186. oval = 0x123;
  187. delta = 0x456;
  188. test_n = oval;
  189. prev = test_atomic_fetch_add(&test_n, delta);
  190. error = (prev == oval) ? 0 : EINVAL;
  191. error_check(error, __func__);
  192. test_check_n(oval + delta, __func__);
  193. }
  194. static void
  195. test_fetch_sub(void)
  196. {
  197. test_int_t prev, oval, delta;
  198. int error;
  199. oval = 0x123;
  200. delta = 0x456;
  201. test_n = oval;
  202. prev = test_atomic_fetch_sub(&test_n, delta);
  203. error = (prev == oval) ? 0 : EINVAL;
  204. error_check(error, __func__);
  205. test_check_n(oval - delta, __func__);
  206. }
  207. static void
  208. test_fetch_and(void)
  209. {
  210. test_int_t prev, oval, delta;
  211. int error;
  212. oval = 0x123;
  213. delta = 0x456;
  214. test_n = oval;
  215. prev = test_atomic_fetch_and(&test_n, delta);
  216. error = (prev == oval) ? 0 : EINVAL;
  217. error_check(error, __func__);
  218. test_check_n(oval & delta, __func__);
  219. }
  220. static void
  221. test_fetch_or(void)
  222. {
  223. test_int_t prev, oval, delta;
  224. int error;
  225. oval = 0x123;
  226. delta = 0x456;
  227. test_n = oval;
  228. prev = test_atomic_fetch_or(&test_n, delta);
  229. error = (prev == oval) ? 0 : EINVAL;
  230. error_check(error, __func__);
  231. test_check_n(oval | delta, __func__);
  232. }
  233. static void
  234. test_fetch_xor(void)
  235. {
  236. test_int_t prev, oval, delta;
  237. int error;
  238. oval = 0x123;
  239. delta = 0x456;
  240. test_n = oval;
  241. prev = test_atomic_fetch_xor(&test_n, delta);
  242. error = (prev == oval) ? 0 : EINVAL;
  243. error_check(error, __func__);
  244. test_check_n(oval ^ delta, __func__);
  245. }
  246. static void
  247. test_add(void)
  248. {
  249. test_int_t oval, delta;
  250. oval = 0x123;
  251. delta = 0x456;
  252. test_n = oval;
  253. test_atomic_add(&test_n, delta);
  254. test_check_n(oval + delta, __func__);
  255. }
  256. static void
  257. test_sub(void)
  258. {
  259. test_int_t oval, delta;
  260. oval = 0x123;
  261. delta = 0x456;
  262. test_n = oval;
  263. test_atomic_sub(&test_n, delta);
  264. test_check_n(oval - delta, __func__);
  265. }
  266. static void
  267. test_and(void)
  268. {
  269. test_int_t oval, delta;
  270. oval = 0x123;
  271. delta = 0x456;
  272. test_n = oval;
  273. test_atomic_and(&test_n, delta);
  274. test_check_n(oval & delta, __func__);
  275. }
  276. static void
  277. test_or(void)
  278. {
  279. test_int_t oval, delta;
  280. oval = 0x123;
  281. delta = 0x456;
  282. test_n = oval;
  283. test_atomic_or(&test_n, delta);
  284. test_check_n(oval | delta, __func__);
  285. }
  286. static void
  287. test_xor(void)
  288. {
  289. test_int_t oval, delta;
  290. oval = 0x123;
  291. delta = 0x456;
  292. test_n = oval;
  293. test_atomic_xor(&test_n, delta);
  294. test_check_n(oval ^ delta, __func__);
  295. }
  296. void __init
  297. test_setup(void)
  298. {
  299. test_load();
  300. test_store();
  301. test_cas_match();
  302. test_cas_nomatch();
  303. test_swap();
  304. test_fetch_add();
  305. test_fetch_sub();
  306. test_fetch_and();
  307. test_fetch_or();
  308. test_fetch_xor();
  309. test_add();
  310. test_sub();
  311. test_and();
  312. test_or();
  313. test_xor();
  314. log_info("test: done");
  315. }