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