atomic.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #include "test/jemalloc_test.h"
  2. /*
  3. * We *almost* have consistent short names (e.g. "u32" for uint32_t, "b" for
  4. * bool, etc. The one exception is that the short name for void * is "p" in
  5. * some places and "ptr" in others. In the long run it would be nice to unify
  6. * these, but in the short run we'll use this shim.
  7. */
  8. #define expect_p_eq expect_ptr_eq
  9. /*
  10. * t: the non-atomic type, like "uint32_t".
  11. * ta: the short name for the type, like "u32".
  12. * val[1,2,3]: Values of the given type. The CAS tests use val2 for expected,
  13. * and val3 for desired.
  14. */
  15. #define DO_TESTS(t, ta, val1, val2, val3) do { \
  16. t val; \
  17. t expected; \
  18. bool success; \
  19. /* This (along with the load below) also tests ATOMIC_LOAD. */ \
  20. atomic_##ta##_t atom = ATOMIC_INIT(val1); \
  21. \
  22. /* ATOMIC_INIT and load. */ \
  23. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  24. expect_##ta##_eq(val1, val, "Load or init failed"); \
  25. \
  26. /* Store. */ \
  27. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  28. atomic_store_##ta(&atom, val2, ATOMIC_RELAXED); \
  29. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  30. expect_##ta##_eq(val2, val, "Store failed"); \
  31. \
  32. /* Exchange. */ \
  33. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  34. val = atomic_exchange_##ta(&atom, val2, ATOMIC_RELAXED); \
  35. expect_##ta##_eq(val1, val, "Exchange returned invalid value"); \
  36. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  37. expect_##ta##_eq(val2, val, "Exchange store invalid value"); \
  38. \
  39. /* \
  40. * Weak CAS. Spurious failures are allowed, so we loop a few \
  41. * times. \
  42. */ \
  43. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  44. success = false; \
  45. for (int retry = 0; retry < 10 && !success; retry++) { \
  46. expected = val2; \
  47. success = atomic_compare_exchange_weak_##ta(&atom, \
  48. &expected, val3, ATOMIC_RELAXED, ATOMIC_RELAXED); \
  49. expect_##ta##_eq(val1, expected, \
  50. "CAS should update expected"); \
  51. } \
  52. expect_b_eq(val1 == val2, success, \
  53. "Weak CAS did the wrong state update"); \
  54. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  55. if (success) { \
  56. expect_##ta##_eq(val3, val, \
  57. "Successful CAS should update atomic"); \
  58. } else { \
  59. expect_##ta##_eq(val1, val, \
  60. "Unsuccessful CAS should not update atomic"); \
  61. } \
  62. \
  63. /* Strong CAS. */ \
  64. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  65. expected = val2; \
  66. success = atomic_compare_exchange_strong_##ta(&atom, &expected, \
  67. val3, ATOMIC_RELAXED, ATOMIC_RELAXED); \
  68. expect_b_eq(val1 == val2, success, \
  69. "Strong CAS did the wrong state update"); \
  70. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  71. if (success) { \
  72. expect_##ta##_eq(val3, val, \
  73. "Successful CAS should update atomic"); \
  74. } else { \
  75. expect_##ta##_eq(val1, val, \
  76. "Unsuccessful CAS should not update atomic"); \
  77. } \
  78. \
  79. \
  80. } while (0)
  81. #define DO_INTEGER_TESTS(t, ta, val1, val2) do { \
  82. atomic_##ta##_t atom; \
  83. t val; \
  84. \
  85. /* Fetch-add. */ \
  86. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  87. val = atomic_fetch_add_##ta(&atom, val2, ATOMIC_RELAXED); \
  88. expect_##ta##_eq(val1, val, \
  89. "Fetch-add should return previous value"); \
  90. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  91. expect_##ta##_eq(val1 + val2, val, \
  92. "Fetch-add should update atomic"); \
  93. \
  94. /* Fetch-sub. */ \
  95. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  96. val = atomic_fetch_sub_##ta(&atom, val2, ATOMIC_RELAXED); \
  97. expect_##ta##_eq(val1, val, \
  98. "Fetch-sub should return previous value"); \
  99. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  100. expect_##ta##_eq(val1 - val2, val, \
  101. "Fetch-sub should update atomic"); \
  102. \
  103. /* Fetch-and. */ \
  104. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  105. val = atomic_fetch_and_##ta(&atom, val2, ATOMIC_RELAXED); \
  106. expect_##ta##_eq(val1, val, \
  107. "Fetch-and should return previous value"); \
  108. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  109. expect_##ta##_eq(val1 & val2, val, \
  110. "Fetch-and should update atomic"); \
  111. \
  112. /* Fetch-or. */ \
  113. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  114. val = atomic_fetch_or_##ta(&atom, val2, ATOMIC_RELAXED); \
  115. expect_##ta##_eq(val1, val, \
  116. "Fetch-or should return previous value"); \
  117. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  118. expect_##ta##_eq(val1 | val2, val, \
  119. "Fetch-or should update atomic"); \
  120. \
  121. /* Fetch-xor. */ \
  122. atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
  123. val = atomic_fetch_xor_##ta(&atom, val2, ATOMIC_RELAXED); \
  124. expect_##ta##_eq(val1, val, \
  125. "Fetch-xor should return previous value"); \
  126. val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
  127. expect_##ta##_eq(val1 ^ val2, val, \
  128. "Fetch-xor should update atomic"); \
  129. } while (0)
  130. #define TEST_STRUCT(t, ta) \
  131. typedef struct { \
  132. t val1; \
  133. t val2; \
  134. t val3; \
  135. } ta##_test_t;
  136. #define TEST_CASES(t) { \
  137. {(t)-1, (t)-1, (t)-2}, \
  138. {(t)-1, (t) 0, (t)-2}, \
  139. {(t)-1, (t) 1, (t)-2}, \
  140. \
  141. {(t) 0, (t)-1, (t)-2}, \
  142. {(t) 0, (t) 0, (t)-2}, \
  143. {(t) 0, (t) 1, (t)-2}, \
  144. \
  145. {(t) 1, (t)-1, (t)-2}, \
  146. {(t) 1, (t) 0, (t)-2}, \
  147. {(t) 1, (t) 1, (t)-2}, \
  148. \
  149. {(t)0, (t)-(1 << 22), (t)-2}, \
  150. {(t)0, (t)(1 << 22), (t)-2}, \
  151. {(t)(1 << 22), (t)-(1 << 22), (t)-2}, \
  152. {(t)(1 << 22), (t)(1 << 22), (t)-2} \
  153. }
  154. #define TEST_BODY(t, ta) do { \
  155. const ta##_test_t tests[] = TEST_CASES(t); \
  156. for (unsigned i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { \
  157. ta##_test_t test = tests[i]; \
  158. DO_TESTS(t, ta, test.val1, test.val2, test.val3); \
  159. } \
  160. } while (0)
  161. #define INTEGER_TEST_BODY(t, ta) do { \
  162. const ta##_test_t tests[] = TEST_CASES(t); \
  163. for (unsigned i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { \
  164. ta##_test_t test = tests[i]; \
  165. DO_TESTS(t, ta, test.val1, test.val2, test.val3); \
  166. DO_INTEGER_TESTS(t, ta, test.val1, test.val2); \
  167. } \
  168. } while (0)
  169. TEST_STRUCT(uint64_t, u64);
  170. TEST_BEGIN(test_atomic_u64) {
  171. #if !(LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
  172. test_skip("64-bit atomic operations not supported");
  173. #else
  174. INTEGER_TEST_BODY(uint64_t, u64);
  175. #endif
  176. }
  177. TEST_END
  178. TEST_STRUCT(uint32_t, u32);
  179. TEST_BEGIN(test_atomic_u32) {
  180. INTEGER_TEST_BODY(uint32_t, u32);
  181. }
  182. TEST_END
  183. TEST_STRUCT(void *, p);
  184. TEST_BEGIN(test_atomic_p) {
  185. TEST_BODY(void *, p);
  186. }
  187. TEST_END
  188. TEST_STRUCT(size_t, zu);
  189. TEST_BEGIN(test_atomic_zu) {
  190. INTEGER_TEST_BODY(size_t, zu);
  191. }
  192. TEST_END
  193. TEST_STRUCT(ssize_t, zd);
  194. TEST_BEGIN(test_atomic_zd) {
  195. INTEGER_TEST_BODY(ssize_t, zd);
  196. }
  197. TEST_END
  198. TEST_STRUCT(unsigned, u);
  199. TEST_BEGIN(test_atomic_u) {
  200. INTEGER_TEST_BODY(unsigned, u);
  201. }
  202. TEST_END
  203. int
  204. main(void) {
  205. return test(
  206. test_atomic_u64,
  207. test_atomic_u32,
  208. test_atomic_p,
  209. test_atomic_zu,
  210. test_atomic_zd,
  211. test_atomic_u);
  212. }