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