diff options
| author | Enji Cooper <ngie@FreeBSD.org> | 2026-02-15 01:45:16 +0000 |
|---|---|---|
| committer | Enji Cooper <ngie@FreeBSD.org> | 2026-02-15 01:45:16 +0000 |
| commit | 56a7ce8416d181a2060d7a428aed9c3c6a431e6d (patch) | |
| tree | 102efa260400b2c1ef36733c53fbe2e6b747405c /lib/libc/atomic | |
| parent | a339cc353658ca6abbf6ad2919a9269210475b41 (diff) | |
Diffstat (limited to 'lib/libc/atomic')
| -rw-r--r-- | lib/libc/atomic/t___sync_compare_and_swap.c | 148 | ||||
| -rw-r--r-- | lib/libc/atomic/t___sync_lock.c | 72 |
2 files changed, 198 insertions, 22 deletions
diff --git a/lib/libc/atomic/t___sync_compare_and_swap.c b/lib/libc/atomic/t___sync_compare_and_swap.c index b1b69e035ae9..67880cc30af1 100644 --- a/lib/libc/atomic/t___sync_compare_and_swap.c +++ b/lib/libc/atomic/t___sync_compare_and_swap.c @@ -1,4 +1,4 @@ -/* $NetBSD: t___sync_compare_and_swap.c,v 1.1 2019/02/26 10:01:41 isaki Exp $ */ +/* $NetBSD: t___sync_compare_and_swap.c,v 1.4 2025/12/24 20:37:03 andvar Exp $ */ /* * Copyright (C) 2019 Tetsuya Isaki. All rights reserved. @@ -26,12 +26,21 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t___sync_compare_and_swap.c,v 1.1 2019/02/26 10:01:41 isaki Exp $"); +__RCSID("$NetBSD: t___sync_compare_and_swap.c,v 1.4 2025/12/24 20:37:03 andvar Exp $"); #include <atf-c.h> #include <inttypes.h> #include <machine/types.h> // for __HAVE_ATOMIC64_OPS +#if defined __arm__ && __ARM_ARCH <= 5 +#define pr56839_xfail \ + atf_tc_expect_fail("PR port-arm/56839:" \ + "GCC emits wrong codes for compare_and_swap_1 builtins" \ + " on armv5 (el & eb)") +#else +#define pr56839_xfail __nothing +#endif + /* * These tests don't examine the atomicity. */ @@ -47,7 +56,7 @@ __RCSID("$NetBSD: t___sync_compare_and_swap.c,v 1.1 2019/02/26 10:01:41 isaki Ex #define OLDVAL (0x1122334455667788UL) #define NEWVAL (0x8090a0b0c0d0e0f0UL) -#define atf_sync_bool(NAME, TYPE, FMT) \ +#define atf_sync_bool(NAME, TYPE, FMT, XFAIL) \ ATF_TC(NAME); \ ATF_TC_HEAD(NAME, tc) \ { \ @@ -61,6 +70,7 @@ ATF_TC_BODY(NAME, tc) \ TYPE expval; \ bool expres; \ bool res; \ + XFAIL; \ /* If successful */ \ val = (TYPE)OLDVAL; \ oldval = (TYPE)OLDVAL; \ @@ -85,14 +95,68 @@ ATF_TC_BODY(NAME, tc) \ "failure case: res expects %d but %d", expres, res); \ } -atf_sync_bool(__sync_bool_compare_and_swap_1, uint8_t, PRIx8); -atf_sync_bool(__sync_bool_compare_and_swap_2, uint16_t, PRIx16); -atf_sync_bool(__sync_bool_compare_and_swap_4, uint32_t, PRIx32); +atf_sync_bool(__sync_bool_compare_and_swap_1, uint8_t, PRIx8, pr56839_xfail); +atf_sync_bool(__sync_bool_compare_and_swap_2, uint16_t, PRIx16, __nothing); +atf_sync_bool(__sync_bool_compare_and_swap_4, uint32_t, PRIx32, __nothing); #ifdef __HAVE_ATOMIC64_OPS -atf_sync_bool(__sync_bool_compare_and_swap_8, uint64_t, PRIx64); +atf_sync_bool(__sync_bool_compare_and_swap_8, uint64_t, PRIx64, __nothing); #endif -#define atf_sync_val(NAME, TYPE, FMT) \ +#if _BYTE_ORDER == _LITTLE_ENDIAN +# define LSB 0 +# define MSB 1 +#elif _BYTE_ORDER == _BIG_ENDIAN +# define LSB 1 +# define MSB 0 +#else +# error Unknown byte order! +#endif + +#define atf_sync_bool_subword(NAME, SUBWIDTH, SUBTYPE, TYPE, SUBFMT, FMT, XFAIL) \ +ATF_TC(NAME##_subword); \ +ATF_TC_HEAD(NAME##_subword, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", "subword " #NAME); \ +} \ +ATF_TC_BODY(NAME##_subword, tc) \ +{ \ + volatile union { \ + TYPE word; \ + SUBTYPE subword[2]; \ + } val; \ + XFAIL; \ + /* If successful */ \ + val.subword[LSB] = -1; \ + val.subword[MSB] = 123; \ + ATF_CHECK(NAME(&val.subword[LSB], /*old*/-1, /*new*/-2)); \ + ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-2, \ + "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \ + ATF_CHECK_EQ_MSG(val.subword[MSB], 123, \ + "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \ + ATF_CHECK_EQ_MSG(val.word, \ + ((TYPE)123 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-2, \ + "val.word = 0x%" FMT, val.word); \ + /* If failed */ \ + val.subword[LSB] = -3; \ + val.subword[MSB] = 45; \ + ATF_CHECK(!NAME(&val.subword[LSB], /*old*/-1, /*new*/-2)); \ + ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-3, \ + "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \ + ATF_CHECK_EQ_MSG(val.subword[MSB], 45, \ + "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \ + ATF_CHECK_EQ_MSG(val.word, \ + ((TYPE)45 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-3, \ + "val.word = 0x%" FMT, val.word); \ +} + +atf_sync_bool_subword(__sync_bool_compare_and_swap_1, 8, uint8_t, uint16_t, + PRIx8, PRIx16, pr56839_xfail); +atf_sync_bool_subword(__sync_bool_compare_and_swap_2, 16, uint16_t, uint32_t, + PRIx16, PRIx32, pr56839_xfail); +atf_sync_bool_subword(__sync_bool_compare_and_swap_4, 32, uint32_t, uint64_t, + PRIx32, PRIx64, __nothing); + +#define atf_sync_val(NAME, TYPE, FMT, XFAIL) \ ATF_TC(NAME); \ ATF_TC_HEAD(NAME, tc) \ { \ @@ -106,6 +170,7 @@ ATF_TC_BODY(NAME, tc) \ TYPE expval; \ TYPE expres; \ TYPE res; \ + XFAIL; \ /* If successful */ \ val = (TYPE)OLDVAL; \ oldval = (TYPE)OLDVAL; \ @@ -130,13 +195,64 @@ ATF_TC_BODY(NAME, tc) \ "failure case: res expects 0x%" FMT " but 0x%" FMT, expres, res); \ } -atf_sync_val(__sync_val_compare_and_swap_1, uint8_t, PRIx8); -atf_sync_val(__sync_val_compare_and_swap_2, uint16_t, PRIx16); -atf_sync_val(__sync_val_compare_and_swap_4, uint32_t, PRIx32); +atf_sync_val(__sync_val_compare_and_swap_1, uint8_t, PRIx8, pr56839_xfail); +atf_sync_val(__sync_val_compare_and_swap_2, uint16_t, PRIx16, __nothing); +atf_sync_val(__sync_val_compare_and_swap_4, uint32_t, PRIx32, __nothing); #ifdef __HAVE_ATOMIC64_OPS -atf_sync_val(__sync_val_compare_and_swap_8, uint64_t, PRIx64); +atf_sync_val(__sync_val_compare_and_swap_8, uint64_t, PRIx64, __nothing); #endif +#define atf_sync_val_subword(NAME, SUBWIDTH, SUBTYPE, TYPE, SUBFMT, FMT, XFAIL) \ +ATF_TC(NAME##_subword); \ +ATF_TC_HEAD(NAME##_subword, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", "subword " #NAME); \ +} \ +ATF_TC_BODY(NAME##_subword, tc) \ +{ \ + volatile union { \ + TYPE word; \ + SUBTYPE subword[2]; \ + } val; \ + SUBTYPE rval; \ + XFAIL; \ + /* If successful */ \ + val.subword[LSB] = -1; \ + val.subword[MSB] = 123; \ + ATF_CHECK_EQ_MSG((rval = NAME(&val.subword[LSB], \ + /*old*/-1, /*new*/-2)), (SUBTYPE)-1, \ + "expected 0x%" SUBFMT ", got 0x%" SUBFMT, \ + (SUBTYPE)-1, rval); \ + ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-2, \ + "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \ + ATF_CHECK_EQ_MSG(val.subword[MSB], 123, \ + "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \ + ATF_CHECK_EQ_MSG(val.word, \ + ((TYPE)123 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-2, \ + "val.word = 0x%" FMT, val.word); \ + /* If failed */ \ + val.subword[LSB] = -3; \ + val.subword[MSB] = 45; \ + ATF_CHECK_EQ_MSG((rval = NAME(&val.subword[LSB], \ + /*old*/-1, /*new*/-2)), (SUBTYPE)-3, \ + "expected 0x%" SUBFMT ", got 0x%" SUBFMT, \ + (SUBTYPE)-3, rval); \ + ATF_CHECK_EQ_MSG(val.subword[LSB], (SUBTYPE)-3, \ + "val.subword[LSB] = 0x%" SUBFMT, val.subword[LSB]); \ + ATF_CHECK_EQ_MSG(val.subword[MSB], 45, \ + "val.subword[MSB] = 0x%" SUBFMT, val.subword[MSB]); \ + ATF_CHECK_EQ_MSG(val.word, \ + ((TYPE)45 << (SUBWIDTH)) | (TYPE)(SUBTYPE)-3, \ + "val.word = 0x%" FMT, val.word); \ +} + +atf_sync_val_subword(__sync_val_compare_and_swap_1, 8, uint8_t, uint16_t, + PRIx8, PRIx16, pr56839_xfail); +atf_sync_val_subword(__sync_val_compare_and_swap_2, 16, uint16_t, uint32_t, + PRIx16, PRIx32, pr56839_xfail); +atf_sync_val_subword(__sync_val_compare_and_swap_4, 32, uint32_t, uint64_t, + PRIx32, PRIx64, __nothing); + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_1); @@ -146,6 +262,10 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_8); #endif + ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_1_subword); + ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_2_subword); + ATF_TP_ADD_TC(tp, __sync_bool_compare_and_swap_4_subword); + ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_1); ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_2); ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_4); @@ -153,5 +273,9 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_8); #endif + ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_1_subword); + ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_2_subword); + ATF_TP_ADD_TC(tp, __sync_val_compare_and_swap_4_subword); + return atf_no_error(); } diff --git a/lib/libc/atomic/t___sync_lock.c b/lib/libc/atomic/t___sync_lock.c index efad87cddfa2..c3aa5c3e8b8c 100644 --- a/lib/libc/atomic/t___sync_lock.c +++ b/lib/libc/atomic/t___sync_lock.c @@ -1,4 +1,4 @@ -/* $NetBSD: t___sync_lock.c,v 1.1 2019/02/26 10:01:41 isaki Exp $ */ +/* $NetBSD: t___sync_lock.c,v 1.2 2025/04/07 01:34:43 riastradh Exp $ */ /* * Copyright (C) 2019 Tetsuya Isaki. All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t___sync_lock.c,v 1.1 2019/02/26 10:01:41 isaki Exp $"); +__RCSID("$NetBSD: t___sync_lock.c,v 1.2 2025/04/07 01:34:43 riastradh Exp $"); #include <atf-c.h> #include <inttypes.h> @@ -44,8 +44,60 @@ __RCSID("$NetBSD: t___sync_lock.c,v 1.1 2019/02/26 10:01:41 isaki Exp $"); * It's better to run only when target is actually in libc. */ -#define OLDVAL (0x1122334455667788UL) -#define NEWVAL (0x8090a0b0c0d0e0f0UL) +#if defined __vax__ +/* + * On VAX, __sync_lock_test_and_set_* test and set the low-order bit + * with BBSSI, and __sync_lock_release_* clear the low-order bit with + * BBCCI, so the other bits are not relevant. + * + * It is possible that, by using values other than 0 and 1, we are + * relying on more than gcc guarantees about __sync_lock_test_and_set_* + * and __sync_lock_release_*. But, well, if so, we will be alerted by + * a failing test. + */ +#define INITVAL 0x1122334455667788 +#define LOCKVAL 1 +#define LOCKRET 0 +#define LOCKEDVAL 0x1122334455667789 +#define UNLOCKEDVAL 0x1122334455667788 +#elif 0 && defined __hppa__ +/* + * On HPPA, the native atomic r/m/w instruction, LDCW, atomically loads + * a word and clears it, so the obvious choice is for the unlocked + * state to be nonzero and the locked state to be zero. + * + * But gcc doesn't do that. + * + * Instead, it uses zero for unlocked and nonzero for locked. So for + * __sync_lock_test_and_set_* it issues an out-of-line call (which on + * NetBSD implements by atomic_swap_N), and for __sync_lock_release_*, + * it issues LDCW on a scratch stack location only as a barrier and + * then issues STW to store a zero. + * + * So we don't use this branch after all. But I'm leaving it here as a + * reminder to anyone who suspects something might be wrong on HPPA. + */ +#define INITVAL 0x1122334455667788 +#define LOCKVAL 0 +#define LOCKRET 0x1122334455667788 +#define LOCKEDVAL 0 +#define UNLOCKEDVAL 1 +#else +/* + * According to GCC documentation at + * <https://gcc.gnu.org/onlinedocs/gcc-12.4.0/gcc/_005f_005fsync-Builtins.html>, + * the only guaranteed supported value for LOCKVAL is 1, and it is not + * guaranteed that __sync_lock_release_* stores zero. But on many + * architectures other values work too, and __sync_lock_release_* does + * just store zero, so let's test these by default; the exceptions can + * be listed above. + */ +#define INITVAL 0x1122334455667788 +#define LOCKVAL 0x8090a0b0c0d0e0f0 +#define LOCKRET 0x1122334455667788 +#define LOCKEDVAL 0x8090a0b0c0d0e0f0 +#define UNLOCKEDVAL 0 +#endif #define atf_sync_tas(NAME, TYPE, FMT) \ ATF_TC(NAME); \ @@ -60,10 +112,10 @@ ATF_TC_BODY(NAME, tc) \ TYPE expval; \ TYPE expres; \ TYPE res; \ - val = (TYPE)OLDVAL; \ - newval = (TYPE)NEWVAL; \ - expval = (TYPE)NEWVAL; \ - expres = (TYPE)OLDVAL; \ + val = (TYPE)INITVAL; \ + newval = (TYPE)LOCKVAL; \ + expval = (TYPE)LOCKEDVAL; \ + expres = (TYPE)LOCKRET; \ res = NAME(&val, newval); \ ATF_REQUIRE_MSG(val == expval, \ "val expects 0x%" FMT " but 0x%" FMT, expval, val); \ @@ -88,8 +140,8 @@ ATF_TC_BODY(NAME, tc) \ { \ volatile TYPE val; \ TYPE expval; \ - val = (TYPE)OLDVAL; \ - expval = (TYPE)0; \ + val = (TYPE)LOCKEDVAL; \ + expval = (TYPE)UNLOCKEDVAL; \ NAME(&val); \ ATF_REQUIRE_MSG(val == expval, \ "val expects 0x%" FMT " but 0x%" FMT, expval, val); \ |
