/*
* We *almost* have consistent short names (e.g. "u32" for uint32_t, "b" for
* bool, etc. The one exception is that the short name for void * is "p" in
* some places and "ptr" in others. In the long run it would be nice to unify
* these, but in the short run we'll use this shim.
*/
#define expect_p_eq expect_ptr_eq
/*
* t: the non-atomic type, like "uint32_t".
* ta: the short name for the type, like "u32".
* val[1,2,3]: Values of the given type. The CAS tests use val2 for expected,
* and val3 for desired.
*/
#define DO_TESTS(t, ta, val1, val2, val3) do { \
t val; \
t expected; \
bool success; \
/* This (along with the load below) also tests ATOMIC_LOAD. */ \
atomic_##ta##_t atom = ATOMIC_INIT(val1); \
\
/* ATOMIC_INIT and load. */ \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, val, "Load or init failed"); \
\
/* Store. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
atomic_store_##ta(&atom, val2, ATOMIC_RELAXED); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val2, val, "Store failed"); \
\
/* Exchange. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
val = atomic_exchange_##ta(&atom, val2, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, val, "Exchange returned invalid value"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val2, val, "Exchange store invalid value"); \
\
/* \
* Weak CAS. Spurious failures are allowed, so we loop a few \
* times. \
*/ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
success = false; \
for (int retry = 0; retry < 10 && !success; retry++) { \
expected = val2; \
success = atomic_compare_exchange_weak_##ta(&atom, \
&expected, val3, ATOMIC_RELAXED, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, expected, \
"CAS should update expected"); \
} \
expect_b_eq(val1 == val2, success, \
"Weak CAS did the wrong state update"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
if (success) { \
expect_##ta##_eq(val3, val, \
"Successful CAS should update atomic"); \
} else { \
expect_##ta##_eq(val1, val, \
"Unsuccessful CAS should not update atomic"); \
} \
\
/* Strong CAS. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
expected = val2; \
success = atomic_compare_exchange_strong_##ta(&atom, &expected, \
val3, ATOMIC_RELAXED, ATOMIC_RELAXED); \
expect_b_eq(val1 == val2, success, \
"Strong CAS did the wrong state update"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
if (success) { \
expect_##ta##_eq(val3, val, \
"Successful CAS should update atomic"); \
} else { \
expect_##ta##_eq(val1, val, \
"Unsuccessful CAS should not update atomic"); \
} \
\
\
} while (0)
#define DO_INTEGER_TESTS(t, ta, val1, val2) do { \
atomic_##ta##_t atom; \
t val; \
\
/* Fetch-add. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
val = atomic_fetch_add_##ta(&atom, val2, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, val, \
"Fetch-add should return previous value"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val1 + val2, val, \
"Fetch-add should update atomic"); \
\
/* Fetch-sub. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
val = atomic_fetch_sub_##ta(&atom, val2, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, val, \
"Fetch-sub should return previous value"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val1 - val2, val, \
"Fetch-sub should update atomic"); \
\
/* Fetch-and. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
val = atomic_fetch_and_##ta(&atom, val2, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, val, \
"Fetch-and should return previous value"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val1 & val2, val, \
"Fetch-and should update atomic"); \
\
/* Fetch-or. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
val = atomic_fetch_or_##ta(&atom, val2, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, val, \
"Fetch-or should return previous value"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val1 | val2, val, \
"Fetch-or should update atomic"); \
\
/* Fetch-xor. */ \
atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \
val = atomic_fetch_xor_##ta(&atom, val2, ATOMIC_RELAXED); \
expect_##ta##_eq(val1, val, \
"Fetch-xor should return previous value"); \
val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \
expect_##ta##_eq(val1 ^ val2, val, \
"Fetch-xor should update atomic"); \
} while (0)
#define TEST_STRUCT(t, ta) \
typedef struct { \
t val1; \
t val2; \
t val3; \
} ta##_test_t;