Home | History | Annotate | Line # | Download | only in atomic
t___sync_compare_and_swap.c revision 1.2
      1 /*	$NetBSD: t___sync_compare_and_swap.c,v 1.2 2025/03/13 14:00:50 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2019 Tetsuya Isaki. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __RCSID("$NetBSD: t___sync_compare_and_swap.c,v 1.2 2025/03/13 14:00:50 riastradh Exp $");
     30 
     31 #include <atf-c.h>
     32 #include <inttypes.h>
     33 #include <machine/types.h>	// for __HAVE_ATOMIC64_OPS
     34 
     35 /*
     36  * These tests don't examine the atomicity.
     37  */
     38 
     39 /* XXX
     40  * Depending on a combination of arch and compiler, __sync_* is
     41  * implemented as compiler's builtin function.  In that case, even
     42  * if libc exports the function symbol, it is not used.  As a result
     43  * this tests will examine compiler's builtin functions.
     44  * It's better to run only when target is actually in libc.
     45  */
     46 
     47 #define OLDVAL (0x1122334455667788UL)
     48 #define NEWVAL (0x8090a0b0c0d0e0f0UL)
     49 
     50 #define atf_sync_bool(NAME, TYPE, FMT) \
     51 ATF_TC(NAME); \
     52 ATF_TC_HEAD(NAME, tc) \
     53 { \
     54 	atf_tc_set_md_var(tc, "descr", #NAME); \
     55 } \
     56 ATF_TC_BODY(NAME, tc) \
     57 { \
     58 	volatile TYPE val; \
     59 	TYPE oldval; \
     60 	TYPE newval; \
     61 	TYPE expval; \
     62 	bool expres; \
     63 	bool res; \
     64 	/* If successful */ \
     65 	val = (TYPE)OLDVAL; \
     66 	oldval = (TYPE)OLDVAL; \
     67 	newval = (TYPE)NEWVAL; \
     68 	expval = (TYPE)NEWVAL; \
     69 	expres = true; \
     70 	res = NAME(&val, oldval, newval); \
     71 	ATF_REQUIRE_MSG(val == expval, \
     72 	    "successful case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
     73 	ATF_REQUIRE_MSG(res == expres, \
     74 	    "successful case: res expects %d but %d", expres, res); \
     75 	/* If failure */ \
     76 	val = (TYPE)OLDVAL; \
     77 	oldval = (TYPE)(OLDVAL + 1); \
     78 	newval = (TYPE)NEWVAL; \
     79 	expval = (TYPE)OLDVAL; \
     80 	expres = false; \
     81 	res = NAME(&val, oldval, newval); \
     82 	ATF_REQUIRE_MSG(val == expval, \
     83 	    "failure case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
     84 	ATF_REQUIRE_MSG(res == expres, \
     85 	    "failure case: res expects %d but %d", expres, res); \
     86 }
     87 
     88 atf_sync_bool(__sync_bool_compare_and_swap_1, uint8_t,  PRIx8);
     89 atf_sync_bool(__sync_bool_compare_and_swap_2, uint16_t, PRIx16);
     90 atf_sync_bool(__sync_bool_compare_and_swap_4, uint32_t, PRIx32);
     91 #ifdef __HAVE_ATOMIC64_OPS
     92 atf_sync_bool(__sync_bool_compare_and_swap_8, uint64_t, PRIx64);
     93 #endif
     94 
     95 #if _BYTE_ORDER == _LITTLE_ENDIAN
     96 #  define LSB	0
     97 #  define MSB	1
     98 #elif _BYTE_ORDER == _BIG_ENDIAN
     99 #  define LSB	1
    100 #  define MSB	0
    101 #else
    102 #  error Unknown byte order!
    103 #endif
    104 
    105 #define atf_sync_bool_subword(NAME, SUBWIDTH, SUBTYPE, TYPE, SUBFMT, FMT) \
    106 ATF_TC(NAME##_subword); \
    107 ATF_TC_HEAD(NAME##_subword, tc) \
    108 { \
    109 	atf_tc_set_md_var(tc, "descr", "subword " #NAME); \
    110 } \
    111 ATF_TC_BODY(NAME##_subword, tc) \
    112 { \
    113 	volatile union { \
    114 		TYPE word; \
    115 		SUBTYPE subword[2]; \
    116 	} val; \
    117 	/* If successful */ \
    118 	val.subword[LSB] = -1; \
    119 	val.subword[MSB] = 123; \
    120 	ATF_CHECK(NAME(&val.subword[LSB], /*old*/-1, /*new*/-2)); \
    121 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-2, \
    122 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    123 	ATF_CHECK_EQ_MSG(val.subword[MSB], 123, \
    124 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    125 	ATF_CHECK_EQ_MSG(val.word, \
    126 	    ((TYPE)123 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-2, \
    127 	    "val.word = 0x%" FMT, val.word); \
    128 	/* If failed */ \
    129 	val.subword[LSB] = -3; \
    130 	val.subword[MSB] = 45; \
    131 	ATF_CHECK(!NAME(&val.subword[LSB], /*old*/-1, /*new*/-2)); \
    132 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-3, \
    133 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    134 	ATF_CHECK_EQ_MSG(val.subword[MSB], 45, \
    135 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    136 	ATF_CHECK_EQ_MSG(val.word, \
    137 	    ((TYPE)45 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-3, \
    138 	    "val.word = 0x%" FMT, val.word); \
    139 }
    140 
    141 atf_sync_bool_subword(__sync_bool_compare_and_swap_1, 8, uint8_t, uint16_t,
    142     PRIx8, PRIx16);
    143 atf_sync_bool_subword(__sync_bool_compare_and_swap_2, 16, uint16_t, uint32_t,
    144     PRIx16, PRIx32);
    145 atf_sync_bool_subword(__sync_bool_compare_and_swap_4, 32, uint32_t, uint64_t,
    146     PRIx32, PRIx64);
    147 
    148 #define atf_sync_val(NAME, TYPE, FMT) \
    149 ATF_TC(NAME); \
    150 ATF_TC_HEAD(NAME, tc) \
    151 { \
    152 	atf_tc_set_md_var(tc, "descr", #NAME); \
    153 } \
    154 ATF_TC_BODY(NAME, tc) \
    155 { \
    156 	volatile TYPE val; \
    157 	TYPE oldval; \
    158 	TYPE newval; \
    159 	TYPE expval; \
    160 	TYPE expres; \
    161 	TYPE res; \
    162 	/* If successful */ \
    163 	val = (TYPE)OLDVAL; \
    164 	oldval = (TYPE)OLDVAL; \
    165 	newval = (TYPE)NEWVAL; \
    166 	expval = (TYPE)NEWVAL; \
    167 	expres = (TYPE)OLDVAL; \
    168 	res = NAME(&val, oldval, newval); \
    169 	ATF_REQUIRE_MSG(val == expval, \
    170 	    "successful case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
    171 	ATF_REQUIRE_MSG(res == expres, \
    172 	    "successful case: res expects 0x%" FMT " but 0x%" FMT, expres, res); \
    173 	/* If failure */ \
    174 	val = (TYPE)OLDVAL; \
    175 	oldval = (TYPE)(OLDVAL + 1); \
    176 	newval = (TYPE)NEWVAL; \
    177 	expval = (TYPE)OLDVAL; \
    178 	expres = (TYPE)OLDVAL; \
    179 	res = NAME(&val, oldval, newval); \
    180 	ATF_REQUIRE_MSG(val == expval, \
    181 	    "failure case: val expects 0x%" FMT " but 0x%" FMT, expval, val); \
    182 	ATF_REQUIRE_MSG(res == expres, \
    183 	    "failure case: res expects 0x%" FMT " but 0x%" FMT, expres, res); \
    184 }
    185 
    186 atf_sync_val(__sync_val_compare_and_swap_1, uint8_t,  PRIx8);
    187 atf_sync_val(__sync_val_compare_and_swap_2, uint16_t, PRIx16);
    188 atf_sync_val(__sync_val_compare_and_swap_4, uint32_t, PRIx32);
    189 #ifdef __HAVE_ATOMIC64_OPS
    190 atf_sync_val(__sync_val_compare_and_swap_8, uint64_t, PRIx64);
    191 #endif
    192 
    193 #define atf_sync_val_subword(NAME, SUBWIDTH, SUBTYPE, TYPE, SUBFMT, FMT) \
    194 ATF_TC(NAME##_subword); \
    195 ATF_TC_HEAD(NAME##_subword, tc) \
    196 { \
    197 	atf_tc_set_md_var(tc, "descr", "subword " #NAME); \
    198 } \
    199 ATF_TC_BODY(NAME##_subword, tc) \
    200 { \
    201 	volatile union { \
    202 		TYPE word; \
    203 		SUBTYPE subword[2]; \
    204 	} val; \
    205 	SUBTYPE rval; \
    206 	/* If successful */ \
    207 	val.subword[LSB] = -1; \
    208 	val.subword[MSB] = 123; \
    209 	ATF_CHECK_EQ_MSG((rval = NAME(&val.subword[LSB], \
    210 		/*old*/-1, /*new*/-2)), (SUBTYPE)-1, \
    211 	    "expected 0x%" SUBFMT ", got 0x%" SUBFMT, \
    212 	    (SUBTYPE)-1, rval); \
    213 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-2, \
    214 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    215 	ATF_CHECK_EQ_MSG(val.subword[MSB], 123, \
    216 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    217 	ATF_CHECK_EQ_MSG(val.word, \
    218 	    ((TYPE)123 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-2, \
    219 	    "val.word = 0x%" FMT, val.word); \
    220 	/* If failed */ \
    221 	val.subword[LSB] = -3; \
    222 	val.subword[MSB] = 45; \
    223 	ATF_CHECK_EQ_MSG((rval = NAME(&val.subword[LSB], \
    224 		/*old*/-1, /*new*/-2)), (SUBTYPE)-3, \
    225 	    "expected 0x%" SUBFMT ", got 0x%" SUBFMT, \
    226 	    (SUBTYPE)-3, rval); \
    227 	ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-3, \
    228 	    "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \
    229 	ATF_CHECK_EQ_MSG(val.subword[MSB], 45, \
    230 	    "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \
    231 	ATF_CHECK_EQ_MSG(val.word, \
    232 	    ((TYPE)45 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-3, \
    233 	    "val.word = 0x%" FMT, val.word); \
    234 }
    235 
    236 atf_sync_val_subword(__sync_val_compare_and_swap_1, 8, uint8_t, uint16_t,
    237     PRIx8, PRIx16);
    238 atf_sync_val_subword(__sync_val_compare_and_swap_2, 16, uint16_t, uint32_t,
    239     PRIx16, PRIx32);
    240 atf_sync_val_subword(__sync_val_compare_and_swap_4, 32, uint32_t, uint64_t,
    241     PRIx32, PRIx64);
    242 
    243 ATF_TP_ADD_TCS(tp)
    244 {
    245 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_1);
    246 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_2);
    247 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_4);
    248 #ifdef __HAVE_ATOMIC64_OPS
    249 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_8);
    250 #endif
    251 
    252 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_1_subword);
    253 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_2_subword);
    254 	ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_4_subword);
    255 
    256 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_1);
    257 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_2);
    258 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_4);
    259 #ifdef __HAVE_ATOMIC64_OPS
    260 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_8);
    261 #endif
    262 
    263 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_1_subword);
    264 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_2_subword);
    265 	ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_4_subword);
    266 
    267 	return atf_no_error();
    268 }
    269