From b669bf98aeef6a1fd576bbbe98e90fee67d629b3 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 02:22:03 +0000 Subject: [PATCH 01/54] GHI #35 Add config check for alignof function --- cmake/check/HasFunction.cmake | 92 +++++++++++++++++++++++++++ cmake/in/_config.h.in | 113 ++++++++++++++++++++++++++++++++++ src/include/patomic/config.h | 112 +++++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) diff --git a/cmake/check/HasFunction.cmake b/cmake/check/HasFunction.cmake index ac29a419b..309caeaf1 100644 --- a/cmake/check/HasFunction.cmake +++ b/cmake/check/HasFunction.cmake @@ -7,6 +7,14 @@ # | COMPILER_HAS_BUILTIN_UNREACHABLE | '__builtin_unreachable(void)' is available as a function | # | COMPILER_HAS_WCHAR_FWIDE | '' header is available and makes 'fwide(FILE*, int)' available as a function | # | COMPILER_HAS_WCHAR_FWPRINTF | '' header is available and makes 'fwprintf(FILE*, const wchar_t*, ...)' available as a function | +# | COMPILER_HAS_C23_ALIGNOF | 'alignof(T)' is available as a function | +# | COMPILER_HAS_C23_ALIGNOF_EXTN | '__extension__ alignof(T)' is available as a function | +# | COMPILER_HAS_C11_ALIGNOF | '_Alignof(T)' is available as a function | +# | COMPILER_HAS_C11_ALIGNOF_EXTN | '__extension__ _Alignof(T)' is available as a function | +# | COMPILER_HAS_MS_ALIGNOF | '__alignof(T)' is available as a function | +# | COMPILER_HAS_MS_ALIGNOF_EXTN | '__extension__ __alignof(T)' is available as a function | +# | COMPILER_HAS_GNU_ALIGNOF | '__alignof__(T)' is available as a function | +# | COMPILER_HAS_GNU_ALIGNOF_EXTN | '__extension__ __alignof__(T)' is available as a function | # ----------------------------------------------------------------------------------------------------------------------------------------------- @@ -55,3 +63,87 @@ check_c_source_compiles_or_zero( WILL_FAIL_IF_ANY_NOT ${COMPILER_HAS_WCHAR_H} ) + +# 'alignof(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) alignof(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_C23_ALIGNOF +) + +# '__extension__ alignof(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) __extension__ alignof(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_C23_ALIGNOF_EXTN + WILL_SUCCEED_IF_ALL + ${COMPILER_HAS_C23_ALIGNOF} + ${COMPILER_HAS_EXTN} + WILL_FAIL_IF_ANY_NOT + ${COMPILER_HAS_EXTN} +) + +# '_Alignof(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) _Alignof(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_C11_ALIGNOF +) + +# '__extension__ _Alignof(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) __extension__ _Alignof(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_C11_ALIGNOF_EXTN + WILL_SUCCEED_IF_ALL + ${COMPILER_HAS_C11_ALIGNOF} + ${COMPILER_HAS_EXTN} + WILL_FAIL_IF_ANY_NOT + ${COMPILER_HAS_EXTN} +) + +# '__alignof(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) __alignof(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_MS_ALIGNOF +) + +# '__extension__ __alignof(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) __extension__ __alignof(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_MS_ALIGNOF_EXTN + WILL_SUCCEED_IF_ALL + ${COMPILER_HAS_MS_ALIGNOF} + ${COMPILER_HAS_EXTN} + WILL_FAIL_IF_ANY_NOT + ${COMPILER_HAS_EXTN} +) + +# '__alignof__(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) __alignof__(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_GNU_ALIGNOF +) + +# '__extension__ __alignof__(T)' is available as a function +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { return (int) __extension__ __alignof__(int); }" + OUTPUT_VARIABLE + COMPILER_HAS_GNU_ALIGNOF_EXTN + WILL_SUCCEED_IF_ALL + ${COMPILER_HAS_GNU_ALIGNOF} + ${COMPILER_HAS_EXTN} + WILL_FAIL_IF_ANY_NOT + ${COMPILER_HAS_EXTN} +) diff --git a/cmake/in/_config.h.in b/cmake/in/_config.h.in index f1c0fae81..bd0603482 100644 --- a/cmake/in/_config.h.in +++ b/cmake/in/_config.h.in @@ -345,4 +345,117 @@ #endif +#ifndef PATOMIC_HAS_C23_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * 'alignof(T)' is available as a function. + * + * @note + * Usually requires: C23. + */ + #define PATOMIC_HAS_C23_ALIGNOF @COMPILER_HAS_C23_ALIGNOF@ +#endif + + +#ifndef PATOMIC_HAS_C23_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ alignof(T)' is available as a function. + * + * @note + * Usually requires: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_C23_ALIGNOF_EXTN @COMPILER_HAS_C23_ALIGNOF_EXTN@ +#endif + + +#ifndef PATOMIC_HAS_C11_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * '_Alignof(T)' is available as a function. + * + * @note + * Usually requires: C11. + */ + #define PATOMIC_HAS_C11_ALIGNOF @COMPILER_HAS_C11_ALIGNOF@ +#endif + + +#ifndef PATOMIC_HAS_C11_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ _Alignof(T)' is available as a function. + * + * @note + * Usually requires: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_C11_ALIGNOF_EXTN @COMPILER_HAS_C11_ALIGNOF_EXTN@ +#endif + + +#ifndef PATOMIC_HAS_MS_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * '__alignof(T)' is available as a function. + * + * @note + * Usually required: Microsoft compatible(-ish) compiler. + */ + #define PATOMIC_HAS_MS_ALIGNOF @COMPILER_HAS_MS_ALIGNOF@ +#endif + + +#ifndef PATOMIC_HAS_MS_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ __alignof(T)' is available as a function. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_MS_ALIGNOF_EXTN @COMPILER_HAS_MS_ALIGNOF_EXTN@ +#endif + + +#ifndef PATOMIC_HAS_GNU_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * '__alignof__(T)' is available as a function. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_GNU_ALIGNOF @COMPILER_HAS_GNU_ALIGNOF@ +#endif + + +#ifndef PATOMIC_HAS_GNU_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ __alignof__(T)' is available as a function. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_GNU_ALIGNOF_EXTN @COMPILER_HAS_GNU_ALIGNOF_EXTN@ +#endif + + + #endif /* PATOMIC_GENERATED_CONFIG_H */ diff --git a/src/include/patomic/config.h b/src/include/patomic/config.h index 2d23a5c1b..7f70d29e5 100644 --- a/src/include/patomic/config.h +++ b/src/include/patomic/config.h @@ -372,6 +372,118 @@ #endif +#ifndef PATOMIC_HAS_C23_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * 'alignof(T)' is available as a function. + * + * @note + * Usually requires: C23. + */ + #define PATOMIC_HAS_C23_ALIGNOF 0 +#endif + + +#ifndef PATOMIC_HAS_C23_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ alignof(T)' is available as a function. + * + * @note + * Usually requires: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_C23_ALIGNOF_EXTN 0 +#endif + + +#ifndef PATOMIC_HAS_C11_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * '_Alignof(T)' is available as a function. + * + * @note + * Usually requires: C11. + */ + #define PATOMIC_HAS_C11_ALIGNOF 0 +#endif + + +#ifndef PATOMIC_HAS_C11_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ _Alignof(T)' is available as a function. + * + * @note + * Usually requires: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_C11_ALIGNOF_EXTN 0 +#endif + + +#ifndef PATOMIC_HAS_MS_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * '__alignof(T)' is available as a function. + * + * @note + * Usually required: Microsoft compatible(-ish) compiler. + */ + #define PATOMIC_HAS_MS_ALIGNOF 0 +#endif + + +#ifndef PATOMIC_HAS_MS_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ __alignof(T)' is available as a function. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_MS_ALIGNOF_EXTN 0 +#endif + + +#ifndef PATOMIC_HAS_GNU_ALIGNOF + /** + * @addtogroup config.safe + * + * @brief + * '__alignof__(T)' is available as a function. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_GNU_ALIGNOF 0 +#endif + + +#ifndef PATOMIC_HAS_GNU_ALIGNOF_EXTN + /** + * @addtogroup config.safe + * + * @brief + * '__extension__ __alignof__(T)' is available as a function. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_GNU_ALIGNOF_EXTN 0 +#endif + + /* * UNSAFE CONSTANTS * ================ From ba7901d2fd313bf300f830d08e148488e36071d0 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 02:45:20 +0000 Subject: [PATCH 02/54] GHI #35 Implement stdalign.h/c --- cmake/in/_config.h.in | 1 - src/include/patomic/stdlib/CMakeLists.txt | 1 + src/include/patomic/stdlib/stdalign.h | 100 ++++++++++++++++++++++ src/stdlib/CMakeLists.txt | 1 + src/stdlib/assert.c | 12 +-- src/stdlib/sort.c | 8 +- src/stdlib/stdalign.c | 30 +++++++ 7 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 src/include/patomic/stdlib/stdalign.h create mode 100644 src/stdlib/stdalign.c diff --git a/cmake/in/_config.h.in b/cmake/in/_config.h.in index bd0603482..db0a17e45 100644 --- a/cmake/in/_config.h.in +++ b/cmake/in/_config.h.in @@ -457,5 +457,4 @@ #endif - #endif /* PATOMIC_GENERATED_CONFIG_H */ diff --git a/src/include/patomic/stdlib/CMakeLists.txt b/src/include/patomic/stdlib/CMakeLists.txt index 07899238d..3f9555d06 100644 --- a/src/include/patomic/stdlib/CMakeLists.txt +++ b/src/include/patomic/stdlib/CMakeLists.txt @@ -4,5 +4,6 @@ target_sources(${target_name} PRIVATE assert.h math.h sort.h + stdalign.h stdint.h ) diff --git a/src/include/patomic/stdlib/stdalign.h b/src/include/patomic/stdlib/stdalign.h new file mode 100644 index 000000000..5d322aa23 --- /dev/null +++ b/src/include/patomic/stdlib/stdalign.h @@ -0,0 +1,100 @@ +#ifndef PATOMIC_STDLIB_STDALIGN_H +#define PATOMIC_STDLIB_STDALIGN_H + +#include + +#include + + +/** + * @addtogroup stdlib + * + * @brief + * Calculates the alignment of an imaginary struct which contains the largest + * possible single object with natural alignment. + * + * @warning + * This will return incorrect values if the actual struct contains members of + * over-aligned types, which may result in undefined behaviour if used. + * + * @param size + * The size of an object or type as returned by sizeof. + * + * @return + * The largest power of 2 which divides 'size', or the value 0 if 'size' is 0. + */ +size_t +patomic_alignment_from_size( + size_t size +); + + +/** + * @addtogroup stdlib + * + * @brief + * Checks if the address has a suitable runtime alignment. + * + * @param ptr + * Pointer holding the address to check. + * + * @param alignment + * Minimum alignment to check for. + * + * @return + * The value 1 if the address held by 'ptr' is suitably aligned, otherwise + * the value 0. + */ +int +patomic_is_aligned( + const void *ptr, + size_t alignment +); + + +/* used internally */ +#undef patomic_alignof_type_ + +#if PATOMIC_HAS_C23_ALIGNOF + #define patomic_alignof_type_(type) alignof(type) +#elif PATOMIC_HAS_C23_ALIGNOF_EXTN + #define patomic_alignof_type_(type) __extension__ alignof(type) +#elif PATOMIC_HAS_C11_ALIGNOF + #define patomic_alignof_type_(type) _Alignof(type) +#elif PATOMIC_HAS_C11_ALIGNOF_EXTN + #define patomic_alignof_type_(type) __extension__ _Alignof(type) +#elif PATOMIC_HAS_GNU_ALIGNOF + #define patomic_alignof_type_(type) __alignof__(type) +#elif PATOMIC_HAS_GNU_ALIGNOF_EXTN + #define patomic_alignof_type_(type) __extension__ __alignof__(type) +#elif PATOMIC_HAS_MS_ALIGNOF + #define patomic_alignof_type_(type) __alignof(type) +#elif PATOMIC_HAS_MS_ALIGNOF_EXTN + #define patomic_alignof_type_(type) __extension__ __alignof__(type) +#else + #define patomic_alignof_type_(type) \ + patomic_alignment_from_size(sizeof(type)) +#endif + +/** + * @addtogroup stdlib + * + * @brief + * Gets the alignment requirement of a type. + * + * @warning + * The implementation for this function may fall back to using + * 'patomic_alignment_from_size' if no other implementation is available. + * This will return incorrect values for over-aligned types, which may + * result in undefined behaviour if used. + * + * @param type + * Type from which to get alignment. + * + * @return + * The alignment of the type 'type'. + */ +#define patomic_alignof_type(type) patomic_alignof_type_(type) + + +#endif /* PATOMIC_STDLIB_STDALIGN_H */ diff --git a/src/stdlib/CMakeLists.txt b/src/stdlib/CMakeLists.txt index a051df5fe..d3644d082 100644 --- a/src/stdlib/CMakeLists.txt +++ b/src/stdlib/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(${target_name} PRIVATE abort.c assert.c sort.c + stdalign.c ) diff --git a/src/stdlib/assert.c b/src/stdlib/assert.c index 82ed5d9fb..4844dea8a 100644 --- a/src/stdlib/assert.c +++ b/src/stdlib/assert.c @@ -26,9 +26,9 @@ static void patomic_assert_fxprint( FILE *stream, - const char *expr, - const char *file, - const char *func, + const char *const expr, + const char *const file, + const char *const func, const unsigned int line ) { @@ -66,9 +66,9 @@ patomic_assert_fxprint( void __patomic_assert_fail( - const char *expr, - const char *file, - const char *func, + const char *const expr, + const char *const file, + const char *const func, const unsigned int line ) { diff --git a/src/stdlib/sort.c b/src/stdlib/sort.c index 32d341660..b63b758b9 100644 --- a/src/stdlib/sort.c +++ b/src/stdlib/sort.c @@ -3,10 +3,10 @@ void patomic_array_sort( - void *ptr, - size_t count, - size_t size, - int (*comp)(const void*, const void*) + void *const ptr, + const size_t count, + const size_t size, + int (*const comp)(const void*, const void*) ) { qsort(ptr, count, size, comp); diff --git a/src/stdlib/stdalign.c b/src/stdlib/stdalign.c new file mode 100644 index 000000000..9ebc98ed4 --- /dev/null +++ b/src/stdlib/stdalign.c @@ -0,0 +1,30 @@ +#include +#include + + +size_t +patomic_alignment_from_size( + const size_t size +) +{ + /* early check for zero size */ + if (size == 0) + { + return 0; + } + + /* return largest power of 2 which divides size */ + return size & -size; +} + + +int +patomic_is_aligned( + const volatile void *const ptr, + const size_t alignment +) +{ + patomic_intptr_unsigned_t address = (patomic_intptr_unsigned_t) ptr; + address &= (alignment - 1u); + return address == 0; +} From e09f478036025243d7f0c47379e50ff59aa327e2 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:05:44 +0000 Subject: [PATCH 03/54] GHI #35 Add config checks for restrict keyword --- cmake/check/HasKeyword.cmake | 40 ++++++++++++++++++++++++++++----- cmake/in/_config.h.in | 43 ++++++++++++++++++++++++++++++++++++ src/include/patomic/config.h | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 5 deletions(-) diff --git a/cmake/check/HasKeyword.cmake b/cmake/check/HasKeyword.cmake index f723fa087..46e312585 100644 --- a/cmake/check/HasKeyword.cmake +++ b/cmake/check/HasKeyword.cmake @@ -1,10 +1,13 @@ # ---- Has Keyword ---- -# ---------------------------------------------------------------------- -# | Variable | Check | -# |========================|===========================================| -# | COMPILER_HAS_EXTN | '__extension__' is available as a keyword | -# ---------------------------------------------------------------------- +# ------------------------------------------------------------------------- +# | Variable | Check | +# |===========================|===========================================| +# | COMPILER_HAS_EXTN | '__extension__' is available as a keyword | +# | COMPILER_HAS_RESTRICT | 'restrict' is available as a keyword | +# | COMPILER_HAS_MS_RESTRICT | '__restrict' is available as a keyword | +# | COMPILER_HAS_GNU_RESTRICT | '__restrict__' is available as a keyword | +# ------------------------------------------------------------------------- # '__extension__' is available as a keyword @@ -14,3 +17,30 @@ check_c_source_compiles_or_zero( OUTPUT_VARIABLE COMPILER_HAS_EXTN ) + +# 'restrict' is available as a keyword +check_c_source_compiles_or_zero( + SOURCE + "static int get(const int *const restrict p) { return *p; } \n\ + int main(void) { int x = 0; return get(&x); }" + OUTPUT_VARIABLE + COMPILER_HAS_RESTRICT +) + +# '__restrict' is available as a keyword +check_c_source_compiles_or_zero( + SOURCE + "static int get(const int *const __restrict p) { return *p; } \n\ + int main(void) { int x = 0; return get(&x); }" + OUTPUT_VARIABLE + COMPILER_HAS_MS_RESTRICT +) + +# '__restrict__' is available as a keyword +check_c_source_compiles_or_zero( + SOURCE + "static int get(const int *const __restrict__ p) { return *p; } \n\ + int main(void) { int x = 0; return get(&x); }" + OUTPUT_VARIABLE + COMPILER_HAS_GNU_RESTRICT +) diff --git a/cmake/in/_config.h.in b/cmake/in/_config.h.in index db0a17e45..58be7a7dd 100644 --- a/cmake/in/_config.h.in +++ b/cmake/in/_config.h.in @@ -16,6 +16,49 @@ #endif +#ifndef PATOMIC_HAS_RESTRICT + /** + * @addtogroup config.safe + * + * @brief + * 'restrict' is available as a keyword. + * + * @note + * Usually required: C99. + */ + #define PATOMIC_HAS_RESTRICT @COMPILER_HAS_RESTRICT@ +#endif + + +#ifndef PATOMIC_HAS_MS_RESTRICT + /** + * @addtogroup config.safe + * + * @brief + * '__restrict' is available as a keyword. + * + * @note + * Usually required: Microsoft compatible(-ish) compiler. + */ + #define PATOMIC_HAS_MS_RESTRICT @COMPILER_HAS_MS_RESTRICT@ +#endif + + +#ifndef PATOMIC_HAS_GNU_RESTRICT + /** + * @addtogroup config.safe + * + * @brief + * '__restrict__' is available as a keyword. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_GNU_RESTRICT @COMPILER_HAS_GNU_RESTRICT@ +#endif + + + #ifndef PATOMIC_HAS_STDINT_H /** * @addtogroup config.safe diff --git a/src/include/patomic/config.h b/src/include/patomic/config.h index 7f70d29e5..1cfcdec23 100644 --- a/src/include/patomic/config.h +++ b/src/include/patomic/config.h @@ -43,6 +43,48 @@ #endif +#ifndef PATOMIC_HAS_RESTRICT + /** + * @addtogroup config.safe + * + * @brief + * 'restrict' is available as a keyword. + * + * @note + * Usually required: C99. + */ + #define PATOMIC_HAS_RESTRICT 0 +#endif + + +#ifndef PATOMIC_HAS_MS_RESTRICT + /** + * @addtogroup config.safe + * + * @brief + * '__restrict' is available as a keyword. + * + * @note + * Usually required: Microsoft compatible(-ish) compiler. + */ + #define PATOMIC_HAS_MS_RESTRICT 0 +#endif + + +#ifndef PATOMIC_HAS_GNU_RESTRICT + /** + * @addtogroup config.safe + * + * @brief + * '__restrict__' is available as a keyword. + * + * @note + * Usually required: GNU compatible(-ish) compiler. + */ + #define PATOMIC_HAS_GNU_RESTRICT 0 +#endif + + #ifndef PATOMIC_HAS_STDINT_H /** * @addtogroup config.safe From 30592abc0a1b092c745602c4d2d185b8f9007781 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:12:11 +0000 Subject: [PATCH 04/54] GHI #35 Add restrict.h macro --- src/include/patomic/macros/CMakeLists.txt | 1 + src/include/patomic/macros/restrict.h | 27 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/include/patomic/macros/restrict.h diff --git a/src/include/patomic/macros/CMakeLists.txt b/src/include/patomic/macros/CMakeLists.txt index c84c8114e..bc631f179 100644 --- a/src/include/patomic/macros/CMakeLists.txt +++ b/src/include/patomic/macros/CMakeLists.txt @@ -3,5 +3,6 @@ target_sources(${target_name} PRIVATE func_name.h ignore_unused.h noreturn.h + restrict.h unreachable.h ) diff --git a/src/include/patomic/macros/restrict.h b/src/include/patomic/macros/restrict.h new file mode 100644 index 000000000..b9befd46e --- /dev/null +++ b/src/include/patomic/macros/restrict.h @@ -0,0 +1,27 @@ +#ifndef PATOMIC_RESTRICT + +#include + +/* used internally */ +#undef PATOMIC_RESTRICT_ + +#if PATOMIC_HAS_RESTRICT + #define PATOMIC_RESTRICT_ restrict +#elif PATOMIC_HAS_MS_RESTRICT + #define PATOMIC_RESTRICT_ __restrict +#elif PATOMIC_HAS_GNU_RESTRICT + #define PATOMIC_RESTRICT_ __restrict__ +#else + #define PATOMIC_RESTRICT_ +#endif + +/** + * @addtogroup macros + * + * @brief + * Object pointer qualifier to declare that a pointer will not alias with any + * other pointer. Behaves like C99's 'restrict' keyword. + */ +#define PATOMIC_RESTRICT PATOMIC_RESTRICT_ + +#endif /* PATOMIC_RESTRICT */ From 86b17da0ef3ae4cad97afe1942cf3323a71628ec Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:26:08 +0000 Subject: [PATCH 05/54] GHI #35 Add string.h/c in stdlib (just memcpy for now) --- src/include/patomic/stdlib/CMakeLists.txt | 1 + src/include/patomic/stdlib/string.h | 41 +++++++++++++++++++++++ src/stdlib/CMakeLists.txt | 1 + src/stdlib/string.c | 14 ++++++++ 4 files changed, 57 insertions(+) create mode 100644 src/include/patomic/stdlib/string.h create mode 100644 src/stdlib/string.c diff --git a/src/include/patomic/stdlib/CMakeLists.txt b/src/include/patomic/stdlib/CMakeLists.txt index 3f9555d06..5ae3199f4 100644 --- a/src/include/patomic/stdlib/CMakeLists.txt +++ b/src/include/patomic/stdlib/CMakeLists.txt @@ -6,4 +6,5 @@ target_sources(${target_name} PRIVATE sort.h stdalign.h stdint.h + string.h ) diff --git a/src/include/patomic/stdlib/string.h b/src/include/patomic/stdlib/string.h new file mode 100644 index 000000000..1498a1332 --- /dev/null +++ b/src/include/patomic/stdlib/string.h @@ -0,0 +1,41 @@ +#ifndef PATOMIC_STDLIB_STRING_H +#define PATOMIC_STDLIB_STRING_H + +#include + +#include + + +/** + * @addtogroup stdlib + * + * @brief + * Copies 'count' characters from the buffer pointed to by 'src' into the + * buffer pointed to by 'dest'. + * + * @note + * Functions identically to C's memcpy. + * + * @param count + * Number of characters to copy from one buffer to the other. + * + * @param src + * Source buffer from which to copy the characters, interpreted as an array + * of 'unsigned char'. + * + * @param dest + * Destination buffer into which to copy the characters, interpreted as an + * array of 'unsigned char'. + * + * @return + * A copy of 'dest'. + */ +void * +patomic_memcpy( + void *PATOMIC_RESTRICT dest, + const void *PATOMIC_RESTRICT src, + size_t count +); + + +#endif /* PATOMIC_STDLIB_STRING_H */ diff --git a/src/stdlib/CMakeLists.txt b/src/stdlib/CMakeLists.txt index d3644d082..e8f07b305 100644 --- a/src/stdlib/CMakeLists.txt +++ b/src/stdlib/CMakeLists.txt @@ -4,4 +4,5 @@ target_sources(${target_name} PRIVATE assert.c sort.c stdalign.c + string.c ) diff --git a/src/stdlib/string.c b/src/stdlib/string.c new file mode 100644 index 000000000..78cf5e734 --- /dev/null +++ b/src/stdlib/string.c @@ -0,0 +1,14 @@ +#include + +#include + + +void * +patomic_memcpy( + void *const PATOMIC_RESTRICT dest, + const void *const PATOMIC_RESTRICT src, + const size_t count +) +{ + return memcpy(dest, src, count); +} From 473947c3e88a3378cd9d22e1811af99a99dc8e01 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:30:20 +0000 Subject: [PATCH 06/54] GHI #35 Minor qualifier/comment fixes --- src/include/patomic/stdlib/stdalign.h | 2 +- src/stdlib/stdalign.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/include/patomic/stdlib/stdalign.h b/src/include/patomic/stdlib/stdalign.h index 5d322aa23..56ed0d9f3 100644 --- a/src/include/patomic/stdlib/stdalign.h +++ b/src/include/patomic/stdlib/stdalign.h @@ -47,7 +47,7 @@ patomic_alignment_from_size( */ int patomic_is_aligned( - const void *ptr, + const volatile void *ptr, size_t alignment ); diff --git a/src/stdlib/stdalign.c b/src/stdlib/stdalign.c index 9ebc98ed4..3813f070a 100644 --- a/src/stdlib/stdalign.c +++ b/src/stdlib/stdalign.c @@ -24,6 +24,7 @@ patomic_is_aligned( const size_t alignment ) { + /* check that our address is exactly divisible by the alignment */ patomic_intptr_unsigned_t address = (patomic_intptr_unsigned_t) ptr; address &= (alignment - 1u); return address == 0; From 397d113380f5816e6a3ef0e16922ff469cde4c59 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:49:16 +0000 Subject: [PATCH 07/54] GHI #35 Set up the base for wrapped --- src/include/patomic/CMakeLists.txt | 1 + src/include/patomic/wrapped/CMakeLists.txt | 4 + src/include/patomic/wrapped/base.h | 100 +++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 src/include/patomic/wrapped/CMakeLists.txt create mode 100644 src/include/patomic/wrapped/base.h diff --git a/src/include/patomic/CMakeLists.txt b/src/include/patomic/CMakeLists.txt index 787e688b6..2ec0b122f 100644 --- a/src/include/patomic/CMakeLists.txt +++ b/src/include/patomic/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(internal) add_subdirectory(macros) add_subdirectory(stdlib) +add_subdirectory(wrapped) # add directory files to target target_sources(${target_name} PRIVATE diff --git a/src/include/patomic/wrapped/CMakeLists.txt b/src/include/patomic/wrapped/CMakeLists.txt new file mode 100644 index 000000000..9ff839eea --- /dev/null +++ b/src/include/patomic/wrapped/CMakeLists.txt @@ -0,0 +1,4 @@ +# add directory files to target +target_sources(${target_name} PRIVATE + base.h +) diff --git a/src/include/patomic/wrapped/base.h b/src/include/patomic/wrapped/base.h new file mode 100644 index 000000000..cee0f56f1 --- /dev/null +++ b/src/include/patomic/wrapped/base.h @@ -0,0 +1,100 @@ +#ifndef PATOMIC_WRAPPED_BASE_H +#define PATOMIC_WRAPPED_BASE_H + +#include + +#include +#include +#include + + +/* redefined below */ +#undef HIDE +#undef HIDE_P +#undef SHOW +#undef SHOW_P +#undef PATOMIC_WRAPPED_DO_ASSERT +#undef PATOMIC_WRAPPED_DO_ASSERT_ALIGNED +#undef PATOMIC_WRAPPED_DO_MEMCPY + + +/** + * @addtogroup wrapped + * + * @brief + * Hides a token from the compiler. + */ +#define HIDE(token) + + +/** + * @addtogroup wrapped + * + * @brief + * Hides two comma-separated tokens from the compiler. + * + * @note + * Can be used for conditionally hiding a function parameter. + */ +#define HIDE_P(tokenA, tokenB) + + +/** + * @addtogroup wrapped + * + * @brief + * Makes a token visible to the compiler. + */ +#define SHOW(token) token + + +/** + * @addtogroup wrapped + * + * @brief + * Makes the second of two comma-separated tokens visible to the compiler, + * including the comma. + * + * @note + * Can be used for conditionally making a function parameter visible. + */ +#define SHOW_P(tokenA, tokenB) ,tokenB + + +/** + * @addtogroup wrapped + * + * @brief + * Asserts that an expression evaluates to a non-zero value. + */ +#define PATOMIC_WRAPPED_DO_ASSERT(expr) \ + patomic_assert_unreachable(expr) + + +/** + * @addtogroup wrapped + * + * @brief + * Asserts that an object meets a types alignment requirements. + */ +#define PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, type) \ + patomic_assert_unreachable( \ + patomic_is_aligned(obj, patomic_alignof_type(type)) \ + ) + + +/** + * @addtogroup wrapped + * + * @brief + * Acts as a transparent wrapper around memcpy. + * + * @note + * Necessary because some compiler options may cause an error if the return + * value of memcpy is not used. + */ +#define PATOMIC_WRAPPED_DO_MEMCPY(dest, src, count) \ + PATOMIC_IGNORE_UNUSED(patomic_memcpy(dest, src, count)) + + +#endif /* PATOMIC_WRAPPED_BASE_H */ From b69b3080f4f58686381d008d31cb67b668bee0cf Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:49:49 +0000 Subject: [PATCH 08/54] GHI #35 Minor comment fix --- src/include/patomic/wrapped/base.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/include/patomic/wrapped/base.h b/src/include/patomic/wrapped/base.h index cee0f56f1..8824ce2f6 100644 --- a/src/include/patomic/wrapped/base.h +++ b/src/include/patomic/wrapped/base.h @@ -87,7 +87,8 @@ * @addtogroup wrapped * * @brief - * Acts as a transparent wrapper around memcpy. + * Acts as a transparent wrapper around memcpy where the return value is + * discarded. * * @note * Necessary because some compiler options may cause an error if the return From 76fe688eb22cda726d6107e6654419fea9ba6fc7 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:54:30 +0000 Subject: [PATCH 09/54] GHI #35 Check to make sure commit signing works --- src/include/patomic/wrapped/base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/patomic/wrapped/base.h b/src/include/patomic/wrapped/base.h index 8824ce2f6..2c875379a 100644 --- a/src/include/patomic/wrapped/base.h +++ b/src/include/patomic/wrapped/base.h @@ -96,6 +96,6 @@ */ #define PATOMIC_WRAPPED_DO_MEMCPY(dest, src, count) \ PATOMIC_IGNORE_UNUSED(patomic_memcpy(dest, src, count)) - +/// #endif /* PATOMIC_WRAPPED_BASE_H */ From 8edabbf0dfffaf1aeffbe63366614143e649d8cd Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 03:54:51 +0000 Subject: [PATCH 10/54] GHI #35 It works. Undo last change --- src/include/patomic/wrapped/base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/patomic/wrapped/base.h b/src/include/patomic/wrapped/base.h index 2c875379a..8824ce2f6 100644 --- a/src/include/patomic/wrapped/base.h +++ b/src/include/patomic/wrapped/base.h @@ -96,6 +96,6 @@ */ #define PATOMIC_WRAPPED_DO_MEMCPY(dest, src, count) \ PATOMIC_IGNORE_UNUSED(patomic_memcpy(dest, src, count)) -/// + #endif /* PATOMIC_WRAPPED_BASE_H */ From 7cefb21ce906559f5de39973f876021ce50ecb98 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 05:21:52 +0000 Subject: [PATCH 11/54] GHI #35 Add empty std impl --- src/impl/CMakeLists.txt | 1 + src/impl/null/null.h | 2 - src/impl/register.h | 7 +-- src/impl/std/CMakeLists.txt | 5 +++ src/impl/std/std.c | 0 src/impl/std/std.h | 85 +++++++++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 src/impl/std/CMakeLists.txt create mode 100644 src/impl/std/std.c create mode 100644 src/impl/std/std.h diff --git a/src/impl/CMakeLists.txt b/src/impl/CMakeLists.txt index dd79bc131..e285d9648 100644 --- a/src/impl/CMakeLists.txt +++ b/src/impl/CMakeLists.txt @@ -1,5 +1,6 @@ # add all subdirectories add_subdirectory(null) +add_subdirectory(std) # add directory files to target target_sources(${target_name} PRIVATE diff --git a/src/impl/null/null.h b/src/impl/null/null.h index 719d1a969..b3742ec51 100644 --- a/src/impl/null/null.h +++ b/src/impl/null/null.h @@ -3,8 +3,6 @@ #include -#include - /** * @addtogroup impl.null diff --git a/src/impl/register.h b/src/impl/register.h index a77ac9f84..95644c7a3 100644 --- a/src/impl/register.h +++ b/src/impl/register.h @@ -2,6 +2,7 @@ #define PATOMIC_REGISTER_H #include "null/null.h" +#include "std/std.h" #include @@ -66,9 +67,9 @@ patomic_impl_register[] = { { patomic_id_STDC, patomic_kind_BLTN, - patomic_impl_create_null, - patomic_impl_create_explicit_null, - patomic_impl_create_transaction_null + patomic_impl_create_std, + patomic_impl_create_explicit_std, + patomic_impl_create_transaction_std } }; diff --git a/src/impl/std/CMakeLists.txt b/src/impl/std/CMakeLists.txt new file mode 100644 index 000000000..8f99c355a --- /dev/null +++ b/src/impl/std/CMakeLists.txt @@ -0,0 +1,5 @@ +# add directory files to target +target_sources(${target_name} PRIVATE + std.h + std.c +) diff --git a/src/impl/std/std.c b/src/impl/std/std.c new file mode 100644 index 000000000..e69de29bb diff --git a/src/impl/std/std.h b/src/impl/std/std.h new file mode 100644 index 000000000..1d77970ea --- /dev/null +++ b/src/impl/std/std.h @@ -0,0 +1,85 @@ +#ifndef PATOMIC_IMPL_STD_H +#define PATOMIC_IMPL_STD_H + +#include + + +/** + * @addtogroup impl.std + * + * @brief + * Support for operations depends on the availability of C11 atomics. If one + * operation is supported for a given width, all operations are supported for + * that width. + * + * @note + * Bitwise operations are implemented as a cmpxchg loop. + * + * @param byte_width + * The width of an object to operate on. + * + * @param order + * The minimum memory order to perform the operation with. + * + * @param opts + * Value is currently unused. + * + * @return + * Implementation where operations are as C11 atomic operations would be. + */ +patomic_t +patomic_impl_create_std( + size_t byte_width, + patomic_memory_order_t order, + unsigned int opts +); + + +/** + * @addtogroup impl.std + * + * @brief + * Support for operations depends on the availability of C11 atomics. If one + * operation is supported for a given width, all operations are supported for + * that width. + * + * @note + * Bitwise operations are implemented as a cmpxchg loop. + * + * @param byte_width + * The width of an object to operate on. + * + * @param opts + * Value is currently unused. + * + * @return + * Implementation where operations are as C11 atomic operations would be. + */ +patomic_explicit_t +patomic_impl_create_explicit_std( + size_t byte_width, + unsigned int opts +); + + +/** + * @addtogroup impl.std + * + * @brief + * No operations are supported here, since C11 does not provide transactional + * operations. + * + * @param opts + * Value is ignored. + * + * @return + * Implementation where no operations are supported and alignment requirements + * are the minimum possible. + */ +patomic_transaction_t +patomic_impl_create_transaction_std( + unsigned int opts +); + + +#endif /* PATOMIC_IMPL_STD_H */ From 7c9ec6b856dc1bec4193c1f31e5179d8b6422f78 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 05:29:04 +0000 Subject: [PATCH 12/54] GHI #35 Rename opts to options --- include/patomic/patomic.h | 12 ++++++------ src/impl/null/null.c | 12 ++++++------ src/impl/null/null.h | 12 ++++++------ src/impl/std/std.h | 12 ++++++------ src/patomic.c | 18 +++++++++--------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/patomic/patomic.h b/include/patomic/patomic.h index 12f442efb..97d20b856 100644 --- a/include/patomic/patomic.h +++ b/include/patomic/patomic.h @@ -35,7 +35,7 @@ extern "C" { * @param order * Memory order to implicitly use for all atomic operations. * - * @param opts + * @param options * One or more patomic_option_t flags combined. Passed on to each internal * implementation to be used in an unspecified manner. * @@ -57,7 +57,7 @@ PATOMIC_EXPORT patomic_t patomic_create( size_t byte_width, patomic_memory_order_t order, - unsigned int opts, + unsigned int options, unsigned int kinds, unsigned long ids ); @@ -74,7 +74,7 @@ patomic_create( * @param byte_width * Width in bytes of type to support. * - * @param opts + * @param options * One or more patomic_option_t flags combined. Passed on to each internal * implementation to be used in an unspecified manner. * @@ -95,7 +95,7 @@ patomic_create( PATOMIC_EXPORT patomic_explicit_t patomic_create_explicit( size_t byte_width, - unsigned int opts, + unsigned int options, unsigned int kinds, unsigned long ids ); @@ -116,7 +116,7 @@ patomic_create_explicit( * than one set of APIs using hardware support for performing lock-free * transactional operations. * - * @param opts + * @param options * One or more patomic_option_t flags combined. Passed on to each internal * implementation to be used in an unspecified manner. * @@ -137,7 +137,7 @@ patomic_create_explicit( */ PATOMIC_EXPORT patomic_transaction_t patomic_create_transaction( - unsigned int opts, + unsigned int options, unsigned int kinds, unsigned long ids ); diff --git a/src/impl/null/null.c b/src/impl/null/null.c index 1d4f682c7..7f553a8e2 100644 --- a/src/impl/null/null.c +++ b/src/impl/null/null.c @@ -7,7 +7,7 @@ patomic_t patomic_impl_create_null( const size_t byte_width, const patomic_memory_order_t order, - const unsigned int opts + const unsigned int options ) { /* zero all fields */ @@ -16,7 +16,7 @@ patomic_impl_create_null( /* ignore parameters */ PATOMIC_IGNORE_UNUSED(byte_width); PATOMIC_IGNORE_UNUSED(order); - PATOMIC_IGNORE_UNUSED(opts); + PATOMIC_IGNORE_UNUSED(options); /* set a valid minimal alignment */ impl.align.recommended = 1; @@ -30,7 +30,7 @@ patomic_impl_create_null( patomic_explicit_t patomic_impl_create_explicit_null( const size_t byte_width, - const unsigned int opts + const unsigned int options ) { /* zero all fields */ @@ -38,7 +38,7 @@ patomic_impl_create_explicit_null( /* ignore parameters */ PATOMIC_IGNORE_UNUSED(byte_width); - PATOMIC_IGNORE_UNUSED(opts); + PATOMIC_IGNORE_UNUSED(options); /* set a valid minimal alignment */ impl.align.recommended = 1; @@ -51,14 +51,14 @@ patomic_impl_create_explicit_null( patomic_transaction_t patomic_impl_create_transaction_null( - const unsigned int opts + const unsigned int options ) { /* zero all fields */ patomic_transaction_t impl = {0}; /* ignore parameters */ - PATOMIC_IGNORE_UNUSED(opts); + PATOMIC_IGNORE_UNUSED(options); /* set a valid minimal alignment */ impl.align.recommended = 1; diff --git a/src/impl/null/null.h b/src/impl/null/null.h index b3742ec51..538ca44e1 100644 --- a/src/impl/null/null.h +++ b/src/impl/null/null.h @@ -16,7 +16,7 @@ * @param order * Value is ignored. * - * @param opts + * @param options * Value is ignored. * * @return @@ -27,7 +27,7 @@ patomic_t patomic_impl_create_null( size_t byte_width, patomic_memory_order_t order, - unsigned int opts + unsigned int options ); @@ -40,7 +40,7 @@ patomic_impl_create_null( * @param byte_width * Value is ignored. * - * @param opts + * @param options * Value is ignored. * * @return @@ -50,7 +50,7 @@ patomic_impl_create_null( patomic_explicit_t patomic_impl_create_explicit_null( size_t byte_width, - unsigned int opts + unsigned int options ); @@ -60,7 +60,7 @@ patomic_impl_create_explicit_null( * @brief * No operations are supported. * - * @param opts + * @param options * Value is ignored. * * @return @@ -69,7 +69,7 @@ patomic_impl_create_explicit_null( */ patomic_transaction_t patomic_impl_create_transaction_null( - unsigned int opts + unsigned int options ); diff --git a/src/impl/std/std.h b/src/impl/std/std.h index 1d77970ea..c2951ac71 100644 --- a/src/impl/std/std.h +++ b/src/impl/std/std.h @@ -21,7 +21,7 @@ * @param order * The minimum memory order to perform the operation with. * - * @param opts + * @param options * Value is currently unused. * * @return @@ -31,7 +31,7 @@ patomic_t patomic_impl_create_std( size_t byte_width, patomic_memory_order_t order, - unsigned int opts + unsigned int options ); @@ -49,7 +49,7 @@ patomic_impl_create_std( * @param byte_width * The width of an object to operate on. * - * @param opts + * @param options * Value is currently unused. * * @return @@ -58,7 +58,7 @@ patomic_impl_create_std( patomic_explicit_t patomic_impl_create_explicit_std( size_t byte_width, - unsigned int opts + unsigned int options ); @@ -69,7 +69,7 @@ patomic_impl_create_explicit_std( * No operations are supported here, since C11 does not provide transactional * operations. * - * @param opts + * @param options * Value is ignored. * * @return @@ -78,7 +78,7 @@ patomic_impl_create_explicit_std( */ patomic_transaction_t patomic_impl_create_transaction_std( - unsigned int opts + unsigned int options ); diff --git a/src/patomic.c b/src/patomic.c index dd6c71c90..7ef47b1aa 100644 --- a/src/patomic.c +++ b/src/patomic.c @@ -43,7 +43,7 @@ patomic_t patomic_create( const size_t byte_width, const patomic_memory_order_t order, - const unsigned int opts, + const unsigned int options, const unsigned int kinds, const unsigned long ids ) @@ -63,7 +63,7 @@ patomic_create( ((unsigned int) patomic_impl_register[i].kind & kinds)) { /* only add to array if some operation is supported */ - *end = patomic_impl_register[i].fp_create(byte_width, order, opts); + *end = patomic_impl_register[i].fp_create(byte_width, order, options); if (opcats != patomic_internal_feature_check_any(&end->ops, opcats)) { ++end; @@ -80,7 +80,7 @@ patomic_create( ); /* combine implementations */ - ret = patomic_impl_create_null(byte_width, order, opts); + ret = patomic_impl_create_null(byte_width, order, options); for (; begin != end; ++begin) { patomic_internal_combine(&ret, begin); @@ -93,7 +93,7 @@ patomic_create( patomic_explicit_t patomic_create_explicit( const size_t byte_width, - const unsigned int opts, + const unsigned int options, const unsigned int kinds, const unsigned long ids ) @@ -113,7 +113,7 @@ patomic_create_explicit( ((unsigned int) patomic_impl_register[i].kind & kinds)) { /* only add to array if some operation is supported */ - *end = patomic_impl_register[i].fp_create_explicit(byte_width, opts); + *end = patomic_impl_register[i].fp_create_explicit(byte_width, options); if (opcats != patomic_internal_feature_check_any_explicit(&end->ops, opcats)) { ++end; @@ -130,7 +130,7 @@ patomic_create_explicit( ); /* combine implementations */ - ret = patomic_impl_create_explicit_null(byte_width, opts); + ret = patomic_impl_create_explicit_null(byte_width, options); for (; begin != end; ++begin) { patomic_internal_combine_explicit(&ret, begin); @@ -142,7 +142,7 @@ patomic_create_explicit( patomic_transaction_t patomic_create_transaction( - const unsigned int opts, + const unsigned int options, const unsigned int kinds, const unsigned long ids ) @@ -163,7 +163,7 @@ patomic_create_transaction( ((unsigned int) patomic_impl_register[i].kind & kinds)) { /* only add to array if some operation is supported */ - ret = patomic_impl_register[i].fp_create_transaction(opts); + ret = patomic_impl_register[i].fp_create_transaction(options); if(opcats != patomic_internal_feature_check_any_transaction(&ret.ops, opcats)) { /* ignore previous implementations if current one has a better kind */ @@ -184,6 +184,6 @@ patomic_create_transaction( } else { - return patomic_impl_create_transaction_null(opts); + return patomic_impl_create_transaction_null(options); } } From d8d85ae02c5e90aaab90b8df418501a87018dfca Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 05:33:06 +0000 Subject: [PATCH 13/54] GHI #35 Implement fallback for std --- src/impl/std/std.c | 81 +++++++++++++++++++++++++++++++++++++++++++ src/stdlib/stdalign.c | 2 +- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index e69de29bb..02bd05fea 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -0,0 +1,81 @@ +#include "std.h" + +#include + +#include + + +#if 0 /* PATOMIC_HAS_STD_ATOMIC */ + + + +#else /* PATOMIC_HAS_STD_ATOMIC */ + + +patomic_t +patomic_impl_create_std( + const size_t byte_width, + const patomic_memory_order_t order, + const unsigned int options +) +{ + /* zero all fields */ + patomic_t impl = {0}; + + /* ignore parameters */ + PATOMIC_IGNORE_UNUSED(byte_width); + PATOMIC_IGNORE_UNUSED(order); + PATOMIC_IGNORE_UNUSED(options); + + /* set a valid minimal alignment */ + impl.align.recommended = 1; + impl.align.minimum = 1; + + /* return */ + return impl; +} + + +patomic_explicit_t +patomic_impl_create_explicit_std( + const size_t byte_width, + const unsigned int options +) +{ + /* zero all fields */ + patomic_explicit_t impl = {0}; + + /* ignore all parameters */ + PATOMIC_IGNORE_UNUSED(byte_width); + PATOMIC_IGNORE_UNUSED(options); + + /* set a valid minimal alignment */ + impl.align.recommended = 1; + impl.align.minimum = 1; + + /* return */ + return impl; +} + + +#endif /* PATOMIC_HAS_STD_ATOMIC */ + + +patomic_transaction_t +patomic_impl_create_transaction_std( + const unsigned int options +) +{ + /* zero all fields */ + patomic_transaction_t impl = {0}; + + /* ignore parameters */ + PATOMIC_IGNORE_UNUSED(options); + + /* set a valid minimal alignment */ + impl.align.recommended = 1; + impl.align.minimum = 1; + + /* return */ + return impl; +} diff --git a/src/stdlib/stdalign.c b/src/stdlib/stdalign.c index 3813f070a..df0dae7f4 100644 --- a/src/stdlib/stdalign.c +++ b/src/stdlib/stdalign.c @@ -24,7 +24,7 @@ patomic_is_aligned( const size_t alignment ) { - /* check that our address is exactly divisible by the alignment */ + /* check that our address is a multiple of the alignment */ patomic_intptr_unsigned_t address = (patomic_intptr_unsigned_t) ptr; address &= (alignment - 1u); return address == 0; From 3d6970b7140ffa261d5d6ee257d364573bfe01c9 Mon Sep 17 00:00:00 2001 From: doodspav Date: Tue, 29 Oct 2024 23:33:54 +0000 Subject: [PATCH 14/54] GHI #35 Add static_assert --- src/include/patomic/macros/CMakeLists.txt | 1 + src/include/patomic/macros/static_assert.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/include/patomic/macros/static_assert.h diff --git a/src/include/patomic/macros/CMakeLists.txt b/src/include/patomic/macros/CMakeLists.txt index bc631f179..4fa104221 100644 --- a/src/include/patomic/macros/CMakeLists.txt +++ b/src/include/patomic/macros/CMakeLists.txt @@ -4,5 +4,6 @@ target_sources(${target_name} PRIVATE ignore_unused.h noreturn.h restrict.h + static_assert.h unreachable.h ) diff --git a/src/include/patomic/macros/static_assert.h b/src/include/patomic/macros/static_assert.h new file mode 100644 index 000000000..07bd11933 --- /dev/null +++ b/src/include/patomic/macros/static_assert.h @@ -0,0 +1,16 @@ +#ifndef PATOMIC_STATIC_ASSERT + +/** + * @addtogroup macros + * + * @brief + * Asserts that an expression evaluates to a non-zero value at compile time. + * + * @pre + * The message must be able to be part of a valid C identifier (but will + * never be at the start). + */ +#define PATOMIC_STATIC_ASSERT(msg, expr) \ + typedef char patomic_static_assert##msg[(expr) ? 1 : -1] + +#endif /* PATOMIC_STATIC_ASSERT */ From ab7035fabf8c716072a32e7efd19ba2fc1f7e5a1 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 00:18:09 +0000 Subject: [PATCH 15/54] GHI #35 Add wrapped macros for direct load and store --- src/include/patomic/wrapped/CMakeLists.txt | 1 + src/include/patomic/wrapped/base.h | 26 +-- src/include/patomic/wrapped/direct.h | 195 +++++++++++++++++++++ 3 files changed, 209 insertions(+), 13 deletions(-) create mode 100644 src/include/patomic/wrapped/direct.h diff --git a/src/include/patomic/wrapped/CMakeLists.txt b/src/include/patomic/wrapped/CMakeLists.txt index 9ff839eea..2b99227f9 100644 --- a/src/include/patomic/wrapped/CMakeLists.txt +++ b/src/include/patomic/wrapped/CMakeLists.txt @@ -1,4 +1,5 @@ # add directory files to target target_sources(${target_name} PRIVATE base.h + direct.h ) diff --git a/src/include/patomic/wrapped/base.h b/src/include/patomic/wrapped/base.h index 8824ce2f6..cbdea2836 100644 --- a/src/include/patomic/wrapped/base.h +++ b/src/include/patomic/wrapped/base.h @@ -19,7 +19,7 @@ /** - * @addtogroup wrapped + * @addtogroup wrapped.base * * @brief * Hides a token from the compiler. @@ -28,7 +28,7 @@ /** - * @addtogroup wrapped + * @addtogroup wrapped.base * * @brief * Hides two comma-separated tokens from the compiler. @@ -36,11 +36,11 @@ * @note * Can be used for conditionally hiding a function parameter. */ -#define HIDE_P(tokenA, tokenB) +#define HIDE_P(token_a, token_b) /** - * @addtogroup wrapped + * @addtogroup wrapped.base * * @brief * Makes a token visible to the compiler. @@ -49,7 +49,7 @@ /** - * @addtogroup wrapped + * @addtogroup wrapped.base * * @brief * Makes the second of two comma-separated tokens visible to the compiler, @@ -58,11 +58,11 @@ * @note * Can be used for conditionally making a function parameter visible. */ -#define SHOW_P(tokenA, tokenB) ,tokenB +#define SHOW_P(token_a, token_b) ,token_b /** - * @addtogroup wrapped + * @addtogroup wrapped.base * * @brief * Asserts that an expression evaluates to a non-zero value. @@ -72,19 +72,19 @@ /** - * @addtogroup wrapped + * @addtogroup wrapped.base * * @brief - * Asserts that an object meets a types alignment requirements. + * Asserts that a pointed-to object meets a type's alignment requirements. */ -#define PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, type) \ - patomic_assert_unreachable( \ - patomic_is_aligned(obj, patomic_alignof_type(type)) \ +#define PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj_ptr, type) \ + patomic_assert_unreachable( \ + patomic_is_aligned(obj_ptr, patomic_alignof_type(type)) \ ) /** - * @addtogroup wrapped + * @addtogroup wrapped.base * * @brief * Acts as a transparent wrapper around memcpy where the return value is diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h new file mode 100644 index 000000000..7397f9a14 --- /dev/null +++ b/src/include/patomic/wrapped/direct.h @@ -0,0 +1,195 @@ +#ifndef PATOMIC_WRAPPED_DIRECT_H +#define PATOMIC_WRAPPED_DIRECT_H + +#include "base.h" + +#include +#include + +#include + +#include + + +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic store operation using + * store as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_store_t + * or patomic_opsig_explicit_store_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_store_explicit + * A macro, M, callable as 'M(obj, des, order)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'des' will be the name of a local identifier, with the type 'type' + * - 'order' will be an expression of type 'int' whose value is a valid + * store memory order + * + * The expected behaviour of calling the macro M as above is: + * - 'des' is atomically stored into the object pointed to by 'obj' with a + * store memory ordering at least as strong as 'order' + * + * The following local variables will also be available to be used by + * the macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_STORE( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_store_explicit \ +) \ + static void \ + fn_name( \ + volatile void *obj \ + ,const void *desired \ + vis_p(_,int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type des; \ + type scratch \ + int temp; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(desired != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_STORE_ORDER((int) order)); \ + \ + /* setup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ + \ + /* operation */ \ + do_atomic_store_explicit( \ + (volatile atomic_type *) obj, \ + des, \ + (int) order \ + ); \ + \ + /* cleanup */ \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + } + + +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic load operation using + * load as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_load_t + * or patomic_opsig_explicit_load_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_load_explicit + * A macro, M, callable as 'M(obj, order, res)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of the type 'const volatile atomic_type *' + * - 'order' will be an expression of type 'int' whose value is a valid + * load memory order + * - 'res' will be the name of a local identifier, with the type 'type' + * + * The expected behaviour of calling the macro M as above is: + * - the value of the object pointed to by 'obj' is atomically read with a + * load memory ordering at least as strong as 'order' + * - 'res' is set to the value which was read + * + * The following local variables will also be available to be used by + * the macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_LOAD( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_load_explicit \ +) \ + static void \ + fn_name( \ + volatile void *obj \ + vis_p(_,int order) \ + ,void *ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type res; \ + type scratch; \ + int temp; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_LOAD_ORDER((int) order)); \ + \ + /* operation */ \ + do_atomic_load_explicit( \ + (const volatile atype *) obj, \ + (int) order, \ + res \ + ); \ + \ + /* cleanup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + } + + +#endif /* PATOMIC_WRAPPED_DIRECT_H */ From 485ead46eb497d7440a51f2fa92c20fc5c72c4c5 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 00:50:56 +0000 Subject: [PATCH 16/54] GHI #35 Add wrapped macro for direct explicit --- src/include/patomic/wrapped/direct.h | 112 +++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 5 deletions(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 7397f9a14..dfe46c87b 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -51,8 +51,10 @@ * store memory order * * The expected behaviour of calling the macro M as above is: - * - 'des' is atomically stored into the object pointed to by 'obj' with a - * store memory ordering at least as strong as 'order' + * - the value of 'des' is read and atomically stored into the object pointed + * to by 'obj' + * - the atomic operation uses a store memory ordering at least as strong as + * 'order' * * The following local variables will also be available to be used by * the macro M: @@ -142,9 +144,10 @@ * - 'res' will be the name of a local identifier, with the type 'type' * * The expected behaviour of calling the macro M as above is: - * - the value of the object pointed to by 'obj' is atomically read with a - * load memory ordering at least as strong as 'order' + * - the value of the object pointed to by 'obj' is atomically read * - 'res' is set to the value which was read + * - the atomic operation uses a load memory ordering at least as strong as + * 'order' * * The following local variables will also be available to be used by * the macro M: @@ -180,7 +183,7 @@ \ /* operation */ \ do_atomic_load_explicit( \ - (const volatile atype *) obj, \ + (const volatile atomic_type *) obj, \ (int) order, \ res \ ); \ @@ -192,4 +195,103 @@ } +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic exchange operation using + * exchange as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_exchange_t + * or patomic_opsig_explicit_exchange_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_exchange_explicit + * A macro, M, callable as 'M(obj, des, order, res)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'des' will be the name of a local identifier, with the type 'type' + * - 'order' will be an expression of type 'int' whose value is a valid + * memory order + * - 'res' will be the name of a local identifier, with the type 'type' + * + * The expected behaviour of calling the macro M as above is: + * - the value of 'des' is read and, in a single atomic operation is stored + * into the object pointed to by 'obj' while the value of 'obj' is read + * - the value read from 'obj' is stored into 'res' + * - the atomic operation uses a memory ordering at least as strong as + * 'order' + * + * The following local variables will also be available to be used by + * the macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DEFINE_OP_EXCHANGE( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_exchange_explicit \ +) \ + static void \ + fn_name( \ + volatile void *obj \ + ,const void *desired \ + vis_p(_,int order) \ + ,void *ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type des; \ + type res; \ + type scratch; \ + int temp; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(desired != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* setup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ + \ + /* operation */ \ + do_atomic_exchange_explicit( \ + (volatile atomic_type *) obj, \ + des, \ + (int) order, \ + res \ + ); \ + \ + /* cleanup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + } + + #endif /* PATOMIC_WRAPPED_DIRECT_H */ From a9ffbfc5913c2ddac91b5a01b848aa7d58e1a0c9 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 01:23:48 +0000 Subject: [PATCH 17/54] GHI #35 Add wrapped macro for direct cmpxchg --- src/include/patomic/wrapped/direct.h | 124 ++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index dfe46c87b..38a4be612 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -237,7 +237,8 @@ * * The expected behaviour of calling the macro M as above is: * - the value of 'des' is read and, in a single atomic operation is stored - * into the object pointed to by 'obj' while the value of 'obj' is read + * into the object pointed to by 'obj' while the value of the object + * pointed to by 'obj' is read * - the value read from 'obj' is stored into 'res' * - the atomic operation uses a memory ordering at least as strong as * 'order' @@ -273,6 +274,7 @@ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ PATOMIC_WRAPPED_DO_ASSERT(desired != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ \ @@ -294,4 +296,124 @@ } +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic cmpxchg operation using + * cmpxchg as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_cmpxchg_t + * or patomic_opsig_explicit_cmpxchg_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param inv + * Either the macro 'HIDE' if 'vis_p' is 'SHOW_P', or the macro 'SHOW' if + * 'vis_p' is 'HIDE_P'. + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_explicit + * A macro, M, callable as 'M(obj, exp, des, succ, fail, ok)' where + * - the result of the expression is unused + * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'exp' will be the name of a local identifier, with the type 'type' + * - 'des' will be the name of a local identifier, with the type 'type' + * - 'succ' will be an expression of type 'int' whose value is a valid + * memory order + * - 'fail' will be an expression of type 'int' whose value is a valid + * load memory order not stronger than 'succ' + * - 'ok' will be the name of a local identifier, with the type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + * + * The following local variables will also be available to be used by + * the macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DEFINE_OP_CMPXCHG( \ + atomic_type, type, fn_name, vis_p, inv, order, \ + do_atomic_cmpxchg_explicit \ +) \ + static int \ + fn_name( \ + volatile void *obj \ + ,void *expected \ + ,const void *desired \ + vis_p(_,int succ) \ + vis_p(_,int fail) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp; \ + type des; \ + type scratch; \ + int ok = 0; \ + int temp; \ + inv(int succ = (int) order;) \ + inv(int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ);) \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(expected != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(desired != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER(succ)); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_FAIL_ORDER(succ, fail)); \ + \ + \ + /* setup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ + PATOMIC_WRAPPED_DO_MEMCPY(&exp, expected, sizeof(type)); \ + \ + /* operation */ \ + do_atomic_cmpxchg_explicit( \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + \ + /* cleanup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(expected, &exp, sizeof(type)); \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + return ok != 0; \ + } + + #endif /* PATOMIC_WRAPPED_DIRECT_H */ From 8246dce33612f046fd3aba82fd15b2dcbeee07b4 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 03:35:22 +0000 Subject: [PATCH 18/54] GHI #35 Add wrapped macro for direct bit test/modify --- src/include/patomic/wrapped/direct.h | 239 ++++++++++++++++++++++++--- 1 file changed, 216 insertions(+), 23 deletions(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 38a4be612..ccc0cfe6b 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -8,6 +8,7 @@ #include +#include #include @@ -56,8 +57,8 @@ * - the atomic operation uses a store memory ordering at least as strong as * 'order' * - * The following local variables will also be available to be used by - * the macro M: + * The following local variables will also be available to be used by the + * macro M: * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized @@ -68,9 +69,9 @@ ) \ static void \ fn_name( \ - volatile void *obj \ - ,const void *desired \ - vis_p(_,int order) \ + volatile void *const obj \ + ,const void *const desired \ + vis_p(_,const int order) \ ) \ { \ /* static assertions */ \ @@ -149,8 +150,8 @@ * - the atomic operation uses a load memory ordering at least as strong as * 'order' * - * The following local variables will also be available to be used by - * the macro M: + * The following local variables will also be available to be used by the + * macro M: * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized @@ -161,9 +162,9 @@ ) \ static void \ fn_name( \ - volatile void *obj \ - vis_p(_,int order) \ - ,void *ret \ + volatile void *const obj \ + vis_p(_,const int order) \ + ,void *const ret \ ) \ { \ /* static assertions */ \ @@ -243,8 +244,8 @@ * - the atomic operation uses a memory ordering at least as strong as * 'order' * - * The following local variables will also be available to be used by - * the macro M: + * The following local variables will also be available to be used by the + * macro M: * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized @@ -255,10 +256,10 @@ ) \ static void \ fn_name( \ - volatile void *obj \ - ,const void *desired \ - vis_p(_,int order) \ - ,void *ret \ + volatile void *const obj \ + ,const void *const desired \ + vis_p(_,const int order) \ + ,void *const ret \ ) \ { \ /* static assertions */ \ @@ -355,8 +356,8 @@ * for a successful exchange, and a load memory ordering at least as strong * as 'fail' for a failed exchange * - * The following local variables will also be available to be used by - * the macro M: + * The following local variables will also be available to be used by the + * macro M: * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized @@ -367,11 +368,11 @@ ) \ static int \ fn_name( \ - volatile void *obj \ - ,void *expected \ - ,const void *desired \ - vis_p(_,int succ) \ - vis_p(_,int fail) \ + volatile void *const obj \ + ,void *const expected \ + ,const void *const desired \ + vis_p(_,const int succ) \ + vis_p(_,const int fail) \ ) \ { \ /* static assertions */ \ @@ -416,4 +417,196 @@ } +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic bit test operation using + * bit test as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_test_t + * or patomic_opsig_explicit_test_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_bit_test_explicit + * A macro, M, callable as 'M(obj, offset, order, res)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of the type 'const volatile atomic_type *' + * - 'offset' will be an expression of type 'int' whose value is non-negative + * and less than 'sizeof(type) * CHAR_BIT' + * - 'order' will be an expression of type 'int' whose value is a valid + * load memory order + * - 'res' will be the name of a local identifier, with the type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the value of the object pointed to by 'obj' is atomically read + * - 'res' is set to the bit at offset 'offset' of the value which was read + * - the atomic operation uses a load memory ordering at least as strong as + * 'order' + * + * The following local variables will also be available to be used by the + * macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_bit_test_explicit \ +) \ + static int \ + fn_name( \ + const volatile void *const obj \ + ,const int offset \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type scratch; \ + int temp; \ + int res; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(offset >= 0); \ + PATOMIC_WRAPPED_DO_ASSERT((size_t) offset < (sizeof(type) * CHAR_BIT)); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_LOAD_ORDER((int) order)); \ + \ + /* operation */ \ + do_atomic_bit_test_explicit( \ + (const volatile atomic_type *) obj, \ + offset, \ + (int) order, \ + res \ + ); \ + \ + /* cleanup */ \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + return res != 0; \ + } + + +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic bit test-modify operation + * using bit test-modify as the underlying atomic operation. + * + * @details + * The defined function's signature will match either + * patomic_opsig_test_modify_t or patomic_opsig_explicit_test_modify_t + * (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_bit_test_modify_explicit + * A macro, M, callable as 'M(obj, offset, order, res)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'offset' will be an expression of type 'int' whose value is non-negative + * and less than 'sizeof(type) * CHAR_BIT' + * - 'order' will be an expression of type 'int' whose value is a valid + * memory order + * - 'res' will be the name of a local identifier, with the type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the bit at offset 'offset' in the object pointed to by 'obj' is modified + * in a single atomic operation + * - the atomic operation uses a store memory ordering at least as strong as + * 'order' if the operation does not require reading the old value, + * otherwise it uses a memory ordering at least as strong as 'order' + * + * The following local variables will also be available to be used by the + * macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST_MODIFY( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_bit_test_modify_explicit \ +) \ + static int \ + fn_name( \ + volatile void *const obj \ + ,const int offset \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type scratch; \ + int temp; \ + int res; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(offset >= 0); \ + PATOMIC_WRAPPED_DO_ASSERT((size_t) offset < (sizeof(type) * CHAR_BIT)); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* operation */ \ + do_atomic_bit_test_modify_explicit( \ + (volatile atomic_type *) obj, \ + offset, \ + (int) order, \ + res \ + ); \ + \ + /* cleanup */ \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + return res != 0; \ + } + + #endif /* PATOMIC_WRAPPED_DIRECT_H */ From 9d7e4472e59d3b6b87c6c473b4c3fe143c5c245d Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 04:24:53 +0000 Subject: [PATCH 19/54] GHI #35 Add wrapped macro for direct fetch --- src/include/patomic/wrapped/direct.h | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index ccc0cfe6b..0626e684a 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -609,4 +609,108 @@ } +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an unary atomic fetch operation using + * unary fetch as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_fetch_t + * or patomic_opsig_explicit_fetch_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_fetch_explicit + * A macro, M, callable as 'M(obj, arg, order, res) where: + * - the result of the expression is unused + * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'arg' will be the name of a local identifier, with the type 'type' + * - 'order' will be an expression of type 'int' whose value is a valid + * memory order + * - 'res' will be the name of a local identifier, with the type 'type' + * + * The expected behaviour of calling the macro M as above is: + * - the value of the object pointed to by 'obj' is read and modified in + * a single atomic operation + * - 'res' is set to the original value read from the object pointed to by + * 'obj' + * - the atomic operation uses a memory ordering at least as strong as + * 'order' + * + * The following local variables will also be available to be used by the + * macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_fetch_explicit \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + ,const void *const argument \ + vis_p(_,int order) \ + ,void *const ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type arg; \ + type res; \ + type scratch; \ + int temp; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(argument != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* setup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&arg, argument, sizeof(type)); \ + \ + /* operation */ \ + do_atomic_fetch_explicit( \ + (volatile atomic_type *) obj, \ + arg, \ + (int) order, \ + res \ + ); \ + \ + /* cleanup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + } + + + + + #endif /* PATOMIC_WRAPPED_DIRECT_H */ From 206386a2e593c69181cebfe2a02a864e77669cdf Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 04:36:24 +0000 Subject: [PATCH 20/54] GHI #35 Add wrapped macro for direct fetch noarg --- src/include/patomic/wrapped/direct.h | 115 ++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 12 deletions(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 0626e684a..36c93a24a 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -46,7 +46,7 @@ * @param do_atomic_store_explicit * A macro, M, callable as 'M(obj, des, order)' where: * - the result of the expression is unused - * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'des' will be the name of a local identifier, with the type 'type' * - 'order' will be an expression of type 'int' whose value is a valid * store memory order @@ -139,7 +139,7 @@ * @param do_atomic_load_explicit * A macro, M, callable as 'M(obj, order, res)' where: * - the result of the expression is unused - * - 'obj' will be an expression of the type 'const volatile atomic_type *' + * - 'obj' will be an expression of type 'const volatile atomic_type *' * - 'order' will be an expression of type 'int' whose value is a valid * load memory order * - 'res' will be the name of a local identifier, with the type 'type' @@ -230,7 +230,7 @@ * @param do_atomic_exchange_explicit * A macro, M, callable as 'M(obj, des, order, res)' where: * - the result of the expression is unused - * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'des' will be the name of a local identifier, with the type 'type' * - 'order' will be an expression of type 'int' whose value is a valid * memory order @@ -335,7 +335,7 @@ * @param do_atomic_cmpxchg_explicit * A macro, M, callable as 'M(obj, exp, des, succ, fail, ok)' where * - the result of the expression is unused - * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'exp' will be the name of a local identifier, with the type 'type' * - 'des' will be the name of a local identifier, with the type 'type' * - 'succ' will be an expression of type 'int' whose value is a valid @@ -451,7 +451,7 @@ * @param do_atomic_bit_test_explicit * A macro, M, callable as 'M(obj, offset, order, res)' where: * - the result of the expression is unused - * - 'obj' will be an expression of the type 'const volatile atomic_type *' + * - 'obj' will be an expression of type 'const volatile atomic_type *' * - 'offset' will be an expression of type 'int' whose value is non-negative * and less than 'sizeof(type) * CHAR_BIT' * - 'order' will be an expression of type 'int' whose value is a valid @@ -547,7 +547,7 @@ * @param do_atomic_bit_test_modify_explicit * A macro, M, callable as 'M(obj, offset, order, res)' where: * - the result of the expression is unused - * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'offset' will be an expression of type 'int' whose value is non-negative * and less than 'sizeof(type) * CHAR_BIT' * - 'order' will be an expression of type 'int' whose value is a valid @@ -641,17 +641,17 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_fetch_explicit - * A macro, M, callable as 'M(obj, arg, order, res) where: + * A macro, M, callable as 'M(obj, arg, order, res)' where: * - the result of the expression is unused - * - 'obj' will be an expression of the type 'volatile atomic_type *' + * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'arg' will be the name of a local identifier, with the type 'type' * - 'order' will be an expression of type 'int' whose value is a valid * memory order * - 'res' will be the name of a local identifier, with the type 'type' * * The expected behaviour of calling the macro M as above is: - * - the value of the object pointed to by 'obj' is read and modified in - * a single atomic operation + * - the value of the object pointed to by 'obj' is read and modified in a + * single atomic operation * - 'res' is set to the original value read from the object pointed to by * 'obj' * - the atomic operation uses a memory ordering at least as strong as @@ -671,7 +671,7 @@ fn_name( \ volatile void *const obj \ ,const void *const argument \ - vis_p(_,int order) \ + vis_p(_,const int order) \ ,void *const ret \ ) \ { \ @@ -710,7 +710,98 @@ } - +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements a noarg atomic fetch operation using + * noarg fetch as the underlying atomic operation. + * + * @details + * The defined function's signature will match either + * patomic_opsig_fetch_noarg_t or patomic_opsig_explicit_fetch_noarg_t + * (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_fetch_noarg_explicit + * A macro, M, callable as 'M(obj, order, res)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of type 'volatile atomic_type *' + * - 'order' will be an expression of type 'int' whose value is a valid + * memory order + * - 'res' will be the name of a local identifier, with the type 'type' + * + * The expected behaviour of calling the macro M as above is: + * - the value of the object pointed to by 'obj' is read and modified in a + * single atomic operation + * - 'res' is set to the original value read from the object pointed to by + * 'obj' + * - the atomic operation uses a memory ordering at least as strong as + * 'order' + * + * The following local variables will also be available to be used by the + * macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH_NOARG( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_fetch_noarg_explicit \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + vis_p(_,const int order) \ + ,void *const ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type res; \ + type scratch; \ + int temp; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DOO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* operation */ \ + do_atomic_fetch_noarg_explicit( \ + (volatile atomic_type *) obj, \ + (int) order, \ + res \ + ); \ + \ + /* cleanup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + } #endif /* PATOMIC_WRAPPED_DIRECT_H */ From 6adbcb052d67f24a2d7c65a27145a2d33a434cec Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 04:51:32 +0000 Subject: [PATCH 21/54] GHI #35 Add wrapped macro for direct void --- src/include/patomic/wrapped/direct.h | 173 ++++++++++++++++++++------- 1 file changed, 133 insertions(+), 40 deletions(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 36c93a24a..67fddbb7b 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -613,8 +613,8 @@ * @addtogroup wrapped.direct * * @brief - * Defines a function which implements an unary atomic fetch operation using - * unary fetch as the underlying atomic operation. + * Defines a function which implements an atomic fetch operation using fetch + * as the underlying atomic operation. * * @details * The defined function's signature will match either patomic_opsig_fetch_t @@ -714,7 +714,7 @@ * @addtogroup wrapped.direct * * @brief - * Defines a function which implements a noarg atomic fetch operation using + * Defines a function which implements a atomic noarg fetch operation using * noarg fetch as the underlying atomic operation. * * @details @@ -764,43 +764,136 @@ * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized */ -#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH_NOARG( \ - atomic_type, type, fn_name, vis_p, order, \ - do_atomic_fetch_noarg_explicit \ -) \ - static void \ - fn_name( \ - volatile void *const obj \ - vis_p(_,const int order) \ - ,void *const ret \ - ) \ - { \ - /* static assertions */ \ - PATOMIC_STATIC_ASSERT( \ - sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ - \ - /* declarations */ \ - type res; \ - type scratch; \ - int temp; \ - \ - /* assertions */ \ - PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ - PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ - PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ - PATOMIC_WRAPPED_DOO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ - \ - /* operation */ \ - do_atomic_fetch_noarg_explicit( \ - (volatile atomic_type *) obj, \ - (int) order, \ - res \ - ); \ - \ - /* cleanup */ \ - PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH_NOARG( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_fetch_noarg_explicit \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + vis_p(_,const int order) \ + ,void *const ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type res; \ + type scratch; \ + int temp; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* operation */ \ + do_atomic_fetch_noarg_explicit( \ + (volatile atomic_type *) obj, \ + (int) order, \ + res \ + ); \ + \ + /* cleanup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + } + + +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic void operation using void + * as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_void_t or + * patomic_opsig_explicit_void_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_void_explicit + * A macro, M, callable as 'M(obj, arg, order)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of type 'volatile atomic_type *' + * - 'arg' will be the name of a local identifier, with the type 'type' + * - 'order' will be an expression of type 'int' whose value is a valid + * memory order + * + * The expected behaviour of calling the macro M as above is: + * - the value of the object pointed to by 'obj' is read and modified in a + * single atomic operation + * - the atomic operation uses a memory ordering at least as strong as + * 'order' + * + * The following local variables will also be available to be used by the + * macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_void_explicit \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + ,const void *const argument \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type arg; \ + type scratch; \ + int temp \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(argument != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* setup */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&arg, argument, sizeof(type)); \ + \ + /* operation */ \ + do_atomic_void_explicit( \ + (volatile atomic_type *) obj, \ + arg, \ + (int) order \ + ); \ + \ + /* cleanup */ \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ } From 7dbc9393da3ef58af12b28c8a0cb0001f19afea5 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 04:59:48 +0000 Subject: [PATCH 22/54] GHI #35 Add wrapped macro for direct void noarg --- src/include/patomic/wrapped/direct.h | 88 +++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 67fddbb7b..ad7730c97 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -714,7 +714,7 @@ * @addtogroup wrapped.direct * * @brief - * Defines a function which implements a atomic noarg fetch operation using + * Defines a function which implements an atomic noarg fetch operation using * noarg fetch as the underlying atomic operation. * * @details @@ -897,4 +897,90 @@ } +/** + * @addtogroup wrapped.direct + * + * @brief + * Defines a function which implements an atomic void noarg operation using + * void noarg as the underlying atomic operation. + * + * @details + * The defined function's signature will match either + * patomic_opsig_void_noarg_t or patomic_opsig_explicit_void_noarg_t + * (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_void_noarg_explicit + * A macro, M, callable as 'M(obj, order)' where: + * - the result of the expression is unused + * - 'obj' will be an expression of type 'volatile atomic_type *' + * - 'order' will be an expression of type 'int' whose value is a valid + * memory order + * + * The expected behaviour of calling the macro M as above is: + * - the value of the object pointed to by 'obj' is read and modified in a + * single atomic operation + * - the atomic operation uses a memory ordering at least as strong as + * 'order' + * + * The following local variables will also be available to be used by the + * macro M: + * - 'temp' has type 'int' + * - 'scratch' has type 'type' + * - their value is unspecified and they may be uninitialized + */ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID_NOARG( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_void_noarg_explicit \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type scratch; \ + int temp; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* operation */ \ + do_atomic_void_noarg_explicit( \ + (volatile atomic_type *) obj, \ + (int) order \ + ); \ + \ + /* cleanup */ \ + PATOMIC_IGNORE_UNUSED(scratch); \ + PATOMIC_IGNORE_UNUSED(temp); \ + } + + #endif /* PATOMIC_WRAPPED_DIRECT_H */ From 7190620a304a82a757b53dfa28db9512aec0f12e Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 05:07:04 +0000 Subject: [PATCH 23/54] GHI #35 Add config check for --- cmake/check/HasHeader.cmake | 22 ++++++++++++++++------ cmake/in/_config.h.in | 13 +++++++++++++ src/include/patomic/config.h | 14 ++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/cmake/check/HasHeader.cmake b/cmake/check/HasHeader.cmake index a98aa9d32..c0bf40f1e 100644 --- a/cmake/check/HasHeader.cmake +++ b/cmake/check/HasHeader.cmake @@ -1,13 +1,23 @@ # ---- Has Header ---- -# ---------------------------------------------------------- -# | Variable | Check | -# |=======================|================================| -# | COMPILER_HAS_STDINT_H | header is available | -# | COMPILER_HAS_WCHAR_H | header is available | -# ---------------------------------------------------------- +# ---------------------------------------------------------------- +# | Variable | Check | +# |==========================|===================================| +# | COMPILER_HAS_STDATOMIC_H | header is available | +# | COMPILER_HAS_STDINT_H | header is available | +# | COMPILER_HAS_WCHAR_H | header is available | +# ---------------------------------------------------------------- +# header is available +check_c_source_compiles_or_zero( + SOURCE + "#include \n\ + int main(void) {}" + OUTPUT_VARIABLE + COMPILER_HAS_STDATOMIC_H +) + # header is available check_c_source_compiles_or_zero( SOURCE diff --git a/cmake/in/_config.h.in b/cmake/in/_config.h.in index 58be7a7dd..4d90874ae 100644 --- a/cmake/in/_config.h.in +++ b/cmake/in/_config.h.in @@ -58,6 +58,19 @@ #endif +#ifndef PATOMIC_HAS_STDATOMIC_H + /** + * @addtogroup config.safe + * + * @brief + * header is available. + * + * @note + * Usually required: C11. + */ + #define PATOMIC_HAS_STDATOMIC_H @COMPILER_HAS_STDATOMIC_H@ +#endif + #ifndef PATOMIC_HAS_STDINT_H /** diff --git a/src/include/patomic/config.h b/src/include/patomic/config.h index 1cfcdec23..3af9fa706 100644 --- a/src/include/patomic/config.h +++ b/src/include/patomic/config.h @@ -85,6 +85,20 @@ #endif +#ifndef PATOMIC_HAS_STDATOMIC_H + /** + * @addtogroup config.safe + * + * @brief + * header is available. + * + * @note + * Usually required: C11. + */ + #define PATOMIC_HAS_STDATOMIC_H 0 +#endif + + #ifndef PATOMIC_HAS_STDINT_H /** * @addtogroup config.safe From feffb5ec1474d7a1b42da03f670eb61f7eb13ee1 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 05:28:43 +0000 Subject: [PATCH 24/54] GHI #35 Add config check for _Atomic --- cmake/check/HasKeyword.cmake | 9 +++++++++ cmake/in/_config.h.in | 14 ++++++++++++++ src/include/patomic/config.h | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/cmake/check/HasKeyword.cmake b/cmake/check/HasKeyword.cmake index 46e312585..153ba9631 100644 --- a/cmake/check/HasKeyword.cmake +++ b/cmake/check/HasKeyword.cmake @@ -7,6 +7,7 @@ # | COMPILER_HAS_RESTRICT | 'restrict' is available as a keyword | # | COMPILER_HAS_MS_RESTRICT | '__restrict' is available as a keyword | # | COMPILER_HAS_GNU_RESTRICT | '__restrict__' is available as a keyword | +# | COMPILER_HAS_ATOMIC | '_Atomic' is available as a keyword | # ------------------------------------------------------------------------- @@ -44,3 +45,11 @@ check_c_source_compiles_or_zero( OUTPUT_VARIABLE COMPILER_HAS_GNU_RESTRICT ) + +# '_Atomic' is available as a keyword +check_c_source_compiles_or_zero( + SOURCE + "int main(void) { _Atomic(int) x = 0; return x; }" + OUTPUT_VARIABLE + COMPILER_HAS_ATOMIC +) diff --git a/cmake/in/_config.h.in b/cmake/in/_config.h.in index 4d90874ae..f3accf598 100644 --- a/cmake/in/_config.h.in +++ b/cmake/in/_config.h.in @@ -58,6 +58,20 @@ #endif +#ifndef PATOMIC_HAS_ATOMIC + /** + * @addtogroup config.safe + * + * @brief + * '_Atomic' is available as a keyword. + * + * @note + * Usually required: C11. + */ + #define PATOMIC_HAS_ATOMIC @COMPILER_HAS_ATOMIC@ +#endif + + #ifndef PATOMIC_HAS_STDATOMIC_H /** * @addtogroup config.safe diff --git a/src/include/patomic/config.h b/src/include/patomic/config.h index 3af9fa706..3d2f50117 100644 --- a/src/include/patomic/config.h +++ b/src/include/patomic/config.h @@ -85,6 +85,20 @@ #endif +#ifndef PATOMIC_HAS_ATOMIC + /** + * @addtogroup config.safe + * + * @brief + * '_Atomic' is available as a keyword. + * + * @note + * Usually required: C11. + */ + #define PATOMIC_HAS_ATOMIC 0 +#endif + + #ifndef PATOMIC_HAS_STDATOMIC_H /** * @addtogroup config.safe From d1276bb97be5d0b94617983a010ce1b1315a8838 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 06:17:47 +0000 Subject: [PATCH 25/54] GHI #35 Fix direct macro names --- src/include/patomic/wrapped/direct.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index ad7730c97..1cf6e5f99 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -250,7 +250,7 @@ * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized */ -#define PATOMIC_WRAPPED_DEFINE_OP_EXCHANGE( \ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_EXCHANGE( \ atomic_type, type, fn_name, vis_p, order, \ do_atomic_exchange_explicit \ ) \ @@ -362,7 +362,7 @@ * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized */ -#define PATOMIC_WRAPPED_DEFINE_OP_CMPXCHG( \ +#define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_CMPXCHG( \ atomic_type, type, fn_name, vis_p, inv, order, \ do_atomic_cmpxchg_explicit \ ) \ From 766aeab73d254bf754b234adc54dd0611336fe6d Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 06:22:21 +0000 Subject: [PATCH 26/54] GHI #35 Add comment --- src/include/patomic/wrapped/direct.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 1cf6e5f99..a6d09fb52 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -62,6 +62,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_STORE( \ atomic_type, type, fn_name, vis_p, order, \ @@ -155,6 +156,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_LOAD( \ atomic_type, type, fn_name, vis_p, order, \ @@ -249,6 +251,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_EXCHANGE( \ atomic_type, type, fn_name, vis_p, order, \ @@ -361,6 +364,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_CMPXCHG( \ atomic_type, type, fn_name, vis_p, inv, order, \ @@ -469,6 +473,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST( \ atomic_type, type, fn_name, vis_p, order, \ @@ -566,6 +571,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST_MODIFY( \ atomic_type, type, fn_name, vis_p, order, \ @@ -662,6 +668,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ atomic_type, type, fn_name, vis_p, order, \ @@ -763,6 +770,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH_NOARG( \ atomic_type, type, fn_name, vis_p, order, \ @@ -854,6 +862,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ atomic_type, type, fn_name, vis_p, order, \ @@ -947,6 +956,7 @@ * - 'temp' has type 'int' * - 'scratch' has type 'type' * - their value is unspecified and they may be uninitialized + * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID_NOARG( \ atomic_type, type, fn_name, vis_p, order, \ From 243ff729aca7209e264c752d784773c60d4b248a Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 06:29:25 +0000 Subject: [PATCH 27/54] GHI #35 Add type param to all do_ macros in direct --- src/include/patomic/wrapped/direct.h | 40 +++++++++++++++++++++------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index a6d09fb52..708cba0bd 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -44,8 +44,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_store_explicit - * A macro, M, callable as 'M(obj, des, order)' where: + * A macro, M, callable as 'M(type, obj, des, order)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'des' will be the name of a local identifier, with the type 'type' * - 'order' will be an expression of type 'int' whose value is a valid @@ -95,6 +96,7 @@ \ /* operation */ \ do_atomic_store_explicit( \ + type, \ (volatile atomic_type *) obj, \ des, \ (int) order \ @@ -138,8 +140,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_load_explicit - * A macro, M, callable as 'M(obj, order, res)' where: + * A macro, M, callable as 'M(type, obj, order, res)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'const volatile atomic_type *' * - 'order' will be an expression of type 'int' whose value is a valid * load memory order @@ -186,6 +189,7 @@ \ /* operation */ \ do_atomic_load_explicit( \ + type, \ (const volatile atomic_type *) obj, \ (int) order, \ res \ @@ -230,8 +234,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_exchange_explicit - * A macro, M, callable as 'M(obj, des, order, res)' where: + * A macro, M, callable as 'M(type, obj, des, order, res)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'des' will be the name of a local identifier, with the type 'type' * - 'order' will be an expression of type 'int' whose value is a valid @@ -287,6 +292,7 @@ \ /* operation */ \ do_atomic_exchange_explicit( \ + type, \ (volatile atomic_type *) obj, \ des, \ (int) order, \ @@ -336,8 +342,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_cmpxchg_explicit - * A macro, M, callable as 'M(obj, exp, des, succ, fail, ok)' where + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok)' where * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'exp' will be the name of a local identifier, with the type 'type' * - 'des' will be the name of a local identifier, with the type 'type' @@ -407,6 +414,7 @@ \ /* operation */ \ do_atomic_cmpxchg_explicit( \ + type, \ (volatile atomic_type *) obj, \ exp, des, \ succ, fail, \ @@ -453,8 +461,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_bit_test_explicit - * A macro, M, callable as 'M(obj, offset, order, res)' where: + * A macro, M, callable as 'M(type, obj, offset, order, res)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'const volatile atomic_type *' * - 'offset' will be an expression of type 'int' whose value is non-negative * and less than 'sizeof(type) * CHAR_BIT' @@ -504,6 +513,7 @@ \ /* operation */ \ do_atomic_bit_test_explicit( \ + type, \ (const volatile atomic_type *) obj, \ offset, \ (int) order, \ @@ -550,8 +560,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_bit_test_modify_explicit - * A macro, M, callable as 'M(obj, offset, order, res)' where: + * A macro, M, callable as 'M(type, obj, offset, order, res)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'offset' will be an expression of type 'int' whose value is non-negative * and less than 'sizeof(type) * CHAR_BIT' @@ -602,6 +613,7 @@ \ /* operation */ \ do_atomic_bit_test_modify_explicit( \ + type, \ (volatile atomic_type *) obj, \ offset, \ (int) order, \ @@ -647,8 +659,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_fetch_explicit - * A macro, M, callable as 'M(obj, arg, order, res)' where: + * A macro, M, callable as 'M(type, obj, arg, order, res)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'arg' will be the name of a local identifier, with the type 'type' * - 'order' will be an expression of type 'int' whose value is a valid @@ -704,6 +717,7 @@ \ /* operation */ \ do_atomic_fetch_explicit( \ + type, \ (volatile atomic_type *) obj, \ arg, \ (int) order, \ @@ -750,8 +764,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_fetch_noarg_explicit - * A macro, M, callable as 'M(obj, order, res)' where: + * A macro, M, callable as 'M(type, obj, order, res)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'order' will be an expression of type 'int' whose value is a valid * memory order @@ -800,6 +815,7 @@ \ /* operation */ \ do_atomic_fetch_noarg_explicit( \ + type, \ (volatile atomic_type *) obj, \ (int) order, \ res \ @@ -844,8 +860,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_void_explicit - * A macro, M, callable as 'M(obj, arg, order)' where: + * A macro, M, callable as 'M(type, obj, arg, order)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'arg' will be the name of a local identifier, with the type 'type' * - 'order' will be an expression of type 'int' whose value is a valid @@ -895,6 +912,7 @@ \ /* operation */ \ do_atomic_void_explicit( \ + type, \ (volatile atomic_type *) obj, \ arg, \ (int) order \ @@ -939,8 +957,9 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_void_noarg_explicit - * A macro, M, callable as 'M(obj, order)' where: + * A macro, M, callable as 'M(type, obj, order)' where: * - the result of the expression is unused + * - 'type' is forwarded directly * - 'obj' will be an expression of type 'volatile atomic_type *' * - 'order' will be an expression of type 'int' whose value is a valid * memory order @@ -983,6 +1002,7 @@ \ /* operation */ \ do_atomic_void_noarg_explicit( \ + type, \ (volatile atomic_type *) obj, \ (int) order \ ); \ From d8fccc895b7417554478772ac3aa02b8ea00acb0 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 07:19:12 +0000 Subject: [PATCH 28/54] GHI #35 Define all direct ops in std impl --- src/impl/std/std.c | 303 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 300 insertions(+), 3 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 02bd05fea..2047ace64 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -5,11 +5,308 @@ #include -#if 0 /* PATOMIC_HAS_STD_ATOMIC */ +#if PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H +#include -#else /* PATOMIC_HAS_STD_ATOMIC */ +#include +#include + + +/* + * BASE: + * - store (direct) + * - load (direct) + */ +#define do_store_explicit(type, obj, des, order) \ + atomic_store_explicit(obj, des order) +#define do_load_explicit(type, obj, order, res) \ + res = atomic_load_explicit(obj, order) + +#define PATOMIC_DEFINE_STORE_OP(type, name, vis_p, order) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_STORE( \ + _Atomic(type), type, \ + patomic_opimpl_store_##name, \ + vis_p, order, \ + do_store_explicit \ + ) + +#define PATOMIC_DEFINE_LOAD_OP(type, name, vis_p, order) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_LOAD( \ + _Atomic(type), type, \ + patomic_opimpl_load_##name, \ + vis_p, order, \ + do_load_explicit \ + ) + + +/* + * XCHG: + * - exchange (direct) + * - cmpxchg_weak (direct) + * - cmpxchg_strong (direct) + */ +#define do_exchange_explicit(type, obj, des, order, res) \ + res = atomic_exchange_explicit(obj, des, order) +#define do_cmpxchg_weak(type, obj, exp, des, succ, fail, ok) \ + ok = atomic_compare_exchange_weak_explicit(obj, &exp, des, succ, fail) +#define do_cmpxchg_strong(type, obj, exp, des, succ, fail, ok) \ + ok = atomic_compare_exchange_strong_explicit(obj, &exp, des, succ, fail) + +#define PATOMIC_DEFINE_XCHG_OPS_CREATE(type, name, order, vis_p, inv, ops) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_EXCHANGE( \ + _Atomic(type), type, \ + patomic_opimpl_exchange_##name, \ + vis_p, order, \ + do_exchange_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_CMPXCHG( \ + _Atomic(type), type, \ + patomic_opimpl_cmpxchg_weak_##name, \ + vis_p, inv, order, \ + do_cmpxchg_weak \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_CMPXCHG( \ + _Atomic(type), type, \ + patomic_opimpl_cmpxchg_strong_##name, \ + vis_p, inv, order, \ + do_cmpxchg_strong \ + ) \ + static patomic_##ops##_xchg_t \ + patomic_ops_xchg_create_##name(void) \ + { \ + patomic_##ops##_xchg_t pao; \ + pao.fp_exchange = patomic_opimpl_exchange_##name; \ + pao.fp_cmpxchg_weak = patomic_opimpl_cmpxchg_weak_##name; \ + pao.fp_cmpxchg_strong = patomic_opimpl_cmpxchg_strong_##name; \ + return pao; \ + } + + +/* + * BITWISE: + * - bit_test (direct) + * - bit_test_compl (no) + * - bit_test_set (no) + * - bit_test_reset (no) + */ +#define do_bit_test_explicit(type, obj, offset, order, res) \ + scratch = (type) ((type) 1 << (type) offset); \ + scratch &= atomic_load_explicit(obj, order); \ + res = (scratch != (type) 0) + +#define PATOMIC_DEFINE_BIT_TEST_OP(type, name, vis_p, order) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST( \ + _Atomic(type), type, \ + patomic_opimpl_bit_test_##name, \ + vis_p, order, \ + do_bit_test_explicit \ + ) + +#define PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ + static const patomic_opsig_test_modify_t patomic_opimpl_bit_test_compl_##name = NULL; \ + static const patomic_opsig_test_modify_t patomic_opimpl_bit_test_set_##name = NULL; \ + static const patomic_opsig_test_modify_t patomic_opimpl_bit_test_reset_##name = NULL; + +/* create ops which support all memory orders */ +#define PATOMIC_DEFINE_BITWISE_OPS_CREATE_ALL(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ + static patomic_##ops##_bitwise_t \ + patomic_ops_bitwise_createe_##name(void) \ + { \ + patomic_##ops##_bitwise_t pao; \ + pao.fp_test = NULL; /* does not support release/acq_rel */ \ + pao.fp_test_compl = patomic_opimpl_bit_test_compl_##name; \ + pao.fp_test_set = patomic_opimpl_bit_test_set_##name; \ + pao.fp_test_reset = patomic_opimpl_bit_test_reset_##name; \ + return pao; \ + } + +/* order cannot be release or acq_rel */ +#define PATOMIC_DEFINE_BITWISE_OPS_CREATE_LOAD(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_BIT_TEST_OP(type, name, vis_p, order) \ + PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ + static patomic_##ops##_bitwise_t \ + patomic_ops_bitwise_createe_##name(void) \ + { \ + patomic_##ops##_bitwise_t pao; \ + pao.fp_test = patomic_opimpl_bit_test_##name; \ + pao.fp_test_compl = patomic_opimpl_bit_test_compl_##name; \ + pao.fp_test_set = patomic_opimpl_bit_test_set_##name; \ + pao.fp_test_reset = patomic_opimpl_bit_test_reset_##name; \ + return pao; \ + } + + +/* + * BINARY: + * - (fetch_)or (direct) + * - (fetch_)xor (direct) + * - (fetch_)and (direct) + * - (fetch_)not (no) + */ +#define do_void_or_explicit(type, obj, arg, order) \ + PATOMIC_IGNORE_UNUSED(atomic_fetch_or_explicit(obj, arg, order) +#define do_void_xor_explicit(type, obj, arg, order) \ + PATOMIC_IGNORE_UNUSED(atomic_fetch_xor_explicit(obj, arg, order) +#define do_void_and_explicit(type, obj, arg, order) \ + PATOMIC_IGNORE_UNUSED(atomic_fetch_and_explicit(obj, arg, order) + +#define do_fetch_or_explicit(type, obj, arg, order, res) \ + res = atomic_fetch_or_explicit(obj, arg, order) +#define do_fetch_xor_explicit(type, obj, arg, order, res) \ + res = atomic_fetch_xor_explicit(obj, arg, order) +#define do_fetch_and_explicit(type, obj, arg, order, res) \ + res = atomic_fetch_and_explicit(obj, arg, order) + +#define PATOMIC_DEFINE_BINARY_OPS_CREATE(type, name, vis_p, order, ops) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + _Atomic(type), type, \ + patomic_opimpl_void_or_##name, \ + vis_p, order, \ + do_void_or_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + _Atomic(type), type, \ + patomic_opimpl_void_xor_##name, \ + vis_p, order, \ + do_void_xor_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + _Atomic(type), type, \ + patomic_opimpl_void_and_##name, \ + vis_p, order, \ + do_void_and_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_or_##name, \ + vis_p, order, \ + do_fetch_or_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_xor_##name, \ + vis_p, order, \ + do_fetch_xor_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_and_##name, \ + vis_p, order, \ + do_fetch_and_explicit \ + ) \ + static patomic_##ops##_binary_t \ + patomic_ops_binary_create_##name(void) \ + { \ + patomic_##ops##_binary_t pao; \ + pao.fp_or = patomic_opimpl_void_or_##name; \ + pao.fp_xor = patomic_opimpl_void_xor_##name; \ + pao.fp_and = patomic_opimpl_void_and_##name; \ + pao.fp_not = NULL; \ + pao.fp_fetch_or = patomic_opimpl_fetch_or_##name; \ + pao.fp_fetch_xor = patomic_opimpl_fetch_xor_##name; \ + pao.fp_fetch_and = patomic_opimpl_fetch_and_##name; \ + pao.fp_fetch_not = NULL; \ + return pao; \ + } + + +/* + * ARITHMETIC: + * - (fetch_)add (direct) + * - (fetch_)sub (direct) + * - (fetch_)inc (direct) + * - (fetch_)dec (direct) + * - (fetch_)neg (no) + */ +#define do_void_add_explicit(type, obj, arg, order) \ + PATOMIC_IGNORE_UNUSED(atomic_fetch_add_explicit(obj, arg, order)) +#define do_void_sub_explicit(type, obj, arg, order) \ + PATOMIC_IGNORE_UNUSED(atomic_fetch_sub_explicit(obj, arg, order)) +#define do_void_inc_explicit(type, obj, arg, order) \ + PATOMIC_IGNORE_UNUSED(atomic_fetch_add_explicit(obj, (type) 1, order)) +#define do_void_dec_explicit(type, obj, arg, order) \ + PATOMIC_IGNORE_UNUSED(atomic_fetch_sub_explicit(obj, (type) 1, order)) + +#define do_fetch_add_explicit(type, obj, arg, order, res) \ + res = atomic_fetch_add_explicit(obj, arg, order) +#define do_fetch_sub_explicit(type, obj, arg, order, res) \ + res = atomic_fetch_sub_explicit(obj, arg, order) +#define do_fetch_inc_explicit(type, obj, arg, order, res) \ + res = atomic_fetch_add_explicit(obj, (type) 1, order) +#define do_fetch_dec_explicit(type, obj, arg, order, res) \ + res = atomic_fetch_sub_explicit(obj, (type) 1, order) + +#define PATOMIC_DEFINE_ARITHMETIC_OPS_CREATE(type, name, vis_p, order, ops) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + _Atomic(type), type, \ + patomic_opimpl_void_add_##name, \ + vis_p, order, \ + do_void_add_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + _Atomic(type), type, \ + patomic_opimpl_void_sub_##name, \ + vis_p, order, \ + do_void_sub_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + _Atomic(type), type, \ + patomic_opimpl_void_inc_##name, \ + vis_p, order, \ + do_void_inc_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + _Atomic(type), type, \ + patomic_opimpl_void_dec_##name, \ + vis_p, order, \ + do_void_dec_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_add_##name, \ + vis_p, order, \ + do_fetch_add_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_sub_##name, \ + vis_p, order, \ + do_fetch_sub_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_inc_##name, \ + vis_p, order, \ + do_fetch_inc_explicit \ + ) \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_dec_##name, \ + vis_p, order, \ + do_fetch_dec_explicit \ + ) \ + static patomic_##ops##_arithmetic_t \ + patomic_ops_arithmetic_create_##name(void) \ + { \ + patomic_##ops##_arithmetic_t pao; \ + pao.fp_add = patomic_opimpl_void_add_##name; \ + pao.fp_sub = patomic_opimpl_void_sub_##name; \ + pao.fp_inc = patomic_opimpl_void_inc_##name; \ + pao.fp_dec = patomic_opimpl_void_dec_##name; \ + pao.fp_neg = NULL; \ + pao.fp_fetch_add = patomic_opimpl_fetch_add_##name; \ + pao.fp_fetch_sub = patomic_opimpl_fetch_sub_##name; \ + pao.fp_fetch_inc = patomic_opimpl_fetch_inc_##name; \ + pao.fp_fetch_dec = patomic_opimpl_fetch_dec_##name; \ + pao.fp_fetch_neg = NULL; \ + return pao; \ + } + + +#else /* PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H */ patomic_t @@ -58,7 +355,7 @@ patomic_impl_create_explicit_std( } -#endif /* PATOMIC_HAS_STD_ATOMIC */ +#endif /* PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H */ patomic_transaction_t From a8f032ee5cefec3873a652eb30a04b3e7b8b61f3 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 08:45:53 +0000 Subject: [PATCH 29/54] GHI #35 Define create functions for std impl and fix some mistakes --- src/impl/std/std.c | 174 +++++++++++++++++---- src/include/patomic/macros/static_assert.h | 2 +- src/include/patomic/wrapped/direct.h | 6 +- 3 files changed, 146 insertions(+), 36 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 2047ace64..0cad3d890 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -5,7 +5,7 @@ #include -#if PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H +#if PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H && PATOMIC_HAS_IR_TWOS_COMPL #include @@ -20,7 +20,7 @@ * - load (direct) */ #define do_store_explicit(type, obj, des, order) \ - atomic_store_explicit(obj, des order) + atomic_store_explicit(obj, des, order) #define do_load_explicit(type, obj, order, res) \ res = atomic_load_explicit(obj, order) @@ -54,7 +54,7 @@ #define do_cmpxchg_strong(type, obj, exp, des, succ, fail, ok) \ ok = atomic_compare_exchange_strong_explicit(obj, &exp, des, succ, fail) -#define PATOMIC_DEFINE_XCHG_OPS_CREATE(type, name, order, vis_p, inv, ops) \ +#define PATOMIC_DEFINE_XCHG_OPS_CREATE(type, name, vis_p, inv, order, ops) \ PATOMIC_WRAPPED_DIRECT_DEFINE_OP_EXCHANGE( \ _Atomic(type), type, \ patomic_opimpl_exchange_##name, \ @@ -104,23 +104,23 @@ do_bit_test_explicit \ ) -#define PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ - static const patomic_opsig_test_modify_t patomic_opimpl_bit_test_compl_##name = NULL; \ - static const patomic_opsig_test_modify_t patomic_opimpl_bit_test_set_##name = NULL; \ - static const patomic_opsig_test_modify_t patomic_opimpl_bit_test_reset_##name = NULL; +#define PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ + static const void * patomic_opimpl_bit_test_compl_##name = NULL; \ + static const void * patomic_opimpl_bit_test_set_##name = NULL; \ + static const void * patomic_opimpl_bit_test_reset_##name = NULL; /* create ops which support all memory orders */ -#define PATOMIC_DEFINE_BITWISE_OPS_CREATE_ALL(type, name, vis_p, order, ops) \ - PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ - static patomic_##ops##_bitwise_t \ - patomic_ops_bitwise_createe_##name(void) \ - { \ - patomic_##ops##_bitwise_t pao; \ - pao.fp_test = NULL; /* does not support release/acq_rel */ \ - pao.fp_test_compl = patomic_opimpl_bit_test_compl_##name; \ - pao.fp_test_set = patomic_opimpl_bit_test_set_##name; \ - pao.fp_test_reset = patomic_opimpl_bit_test_reset_##name; \ - return pao; \ +#define PATOMIC_DEFINE_BITWISE_OPS_CREATE_NO_LOAD(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ + static patomic_##ops##_bitwise_t \ + patomic_ops_bitwise_create_##name(void) \ + { \ + patomic_##ops##_bitwise_t pao; \ + pao.fp_test = NULL; /* does not support release or acq_rel */ \ + pao.fp_test_compl = patomic_opimpl_bit_test_compl_##name; \ + pao.fp_test_set = patomic_opimpl_bit_test_set_##name; \ + pao.fp_test_reset = patomic_opimpl_bit_test_reset_##name; \ + return pao; \ } /* order cannot be release or acq_rel */ @@ -128,7 +128,7 @@ PATOMIC_DEFINE_BIT_TEST_OP(type, name, vis_p, order) \ PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ static patomic_##ops##_bitwise_t \ - patomic_ops_bitwise_createe_##name(void) \ + patomic_ops_bitwise_create_##name(void) \ { \ patomic_##ops##_bitwise_t pao; \ pao.fp_test = patomic_opimpl_bit_test_##name; \ @@ -147,11 +147,11 @@ * - (fetch_)not (no) */ #define do_void_or_explicit(type, obj, arg, order) \ - PATOMIC_IGNORE_UNUSED(atomic_fetch_or_explicit(obj, arg, order) + PATOMIC_IGNORE_UNUSED(atomic_fetch_or_explicit(obj, arg, order)) #define do_void_xor_explicit(type, obj, arg, order) \ - PATOMIC_IGNORE_UNUSED(atomic_fetch_xor_explicit(obj, arg, order) + PATOMIC_IGNORE_UNUSED(atomic_fetch_xor_explicit(obj, arg, order)) #define do_void_and_explicit(type, obj, arg, order) \ - PATOMIC_IGNORE_UNUSED(atomic_fetch_and_explicit(obj, arg, order) + PATOMIC_IGNORE_UNUSED(atomic_fetch_and_explicit(obj, arg, order)) #define do_fetch_or_explicit(type, obj, arg, order, res) \ res = atomic_fetch_or_explicit(obj, arg, order) @@ -225,18 +225,18 @@ PATOMIC_IGNORE_UNUSED(atomic_fetch_add_explicit(obj, arg, order)) #define do_void_sub_explicit(type, obj, arg, order) \ PATOMIC_IGNORE_UNUSED(atomic_fetch_sub_explicit(obj, arg, order)) -#define do_void_inc_explicit(type, obj, arg, order) \ +#define do_void_inc_explicit(type, obj, order) \ PATOMIC_IGNORE_UNUSED(atomic_fetch_add_explicit(obj, (type) 1, order)) -#define do_void_dec_explicit(type, obj, arg, order) \ +#define do_void_dec_explicit(type, obj, order) \ PATOMIC_IGNORE_UNUSED(atomic_fetch_sub_explicit(obj, (type) 1, order)) #define do_fetch_add_explicit(type, obj, arg, order, res) \ res = atomic_fetch_add_explicit(obj, arg, order) #define do_fetch_sub_explicit(type, obj, arg, order, res) \ res = atomic_fetch_sub_explicit(obj, arg, order) -#define do_fetch_inc_explicit(type, obj, arg, order, res) \ +#define do_fetch_inc_explicit(type, obj, order, res) \ res = atomic_fetch_add_explicit(obj, (type) 1, order) -#define do_fetch_dec_explicit(type, obj, arg, order, res) \ +#define do_fetch_dec_explicit(type, obj, order, res) \ res = atomic_fetch_sub_explicit(obj, (type) 1, order) #define PATOMIC_DEFINE_ARITHMETIC_OPS_CREATE(type, name, vis_p, order, ops) \ @@ -252,13 +252,13 @@ vis_p, order, \ do_void_sub_explicit \ ) \ - PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID_NOARG( \ _Atomic(type), type, \ patomic_opimpl_void_inc_##name, \ vis_p, order, \ do_void_inc_explicit \ ) \ - PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID_NOARG( \ _Atomic(type), type, \ patomic_opimpl_void_dec_##name, \ vis_p, order, \ @@ -276,13 +276,13 @@ vis_p, order, \ do_fetch_sub_explicit \ ) \ - PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH_NOARG( \ _Atomic(type), type, \ patomic_opimpl_fetch_inc_##name, \ vis_p, order, \ do_fetch_inc_explicit \ ) \ - PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ + PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH_NOARG( \ _Atomic(type), type, \ patomic_opimpl_fetch_dec_##name, \ vis_p, order, \ @@ -306,7 +306,117 @@ } -#else /* PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H */ +/* + * CREATE STRUCTS + * + * Implicit: + * - ca: { consume, acquire } (not supported by store) + * - r: { release } (not supported by load) + * - ar: { acq_rel } (not supported by store or load) + * - rsc:{ relaxed, seq_cst } + */ +#define PATOMIC_DEFINE_OPS_CREATE_CA(type, name, vis_p, inv, order, ops) \ + /* no store in consume or acquire */ \ + PATOMIC_DEFINE_LOAD_OP(type, name, vis_p, order) \ + PATOMIC_DEFINE_XCHG_OPS_CREATE(type, name, vis_p, inv, order, ops) \ + PATOMIC_DEFINE_BITWISE_OPS_CREATE_LOAD(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_BINARY_OPS_CREATE(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_ARITHMETIC_OPS_CREATE(type, name, vis_p, order, ops) \ + static patomic_##ops##_t \ + patomic_ops_create_##name(void) \ + { \ + patomic_##ops##_t pao; \ + pao.fp_store = NULL; \ + pao.fp_load = patomic_opimpl_load_##name; \ + pao.xchg_ops = patomic_ops_xchg_create_##name(); \ + pao.bitwise_ops = patomic_ops_bitwise_create_##name(); \ + pao.binary_ops = patomic_ops_binary_create_##name(); \ + pao.arithmetic_ops = patomic_ops_arithmetic_create_##name(); \ + return pao; \ + } + +#define PATOMIC_DEFINE_OPS_CREATE_R(type, name, vis_p, inv, order, ops) \ + PATOMIC_DEFINE_STORE_OP(type, name, vis_p, order) \ + /* no load in release */ \ + PATOMIC_DEFINE_XCHG_OPS_CREATE(type, name, vis_p, inv, order, ops) \ + PATOMIC_DEFINE_BITWISE_OPS_CREATE_NO_LOAD(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_BINARY_OPS_CREATE(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_ARITHMETIC_OPS_CREATE(type, name, vis_p, order, ops) \ + static patomic_##ops##_t \ + patomic_ops_create_##name(void) \ + { \ + patomic_##ops##_t pao; \ + pao.fp_store = patomic_opimpl_store_##name; \ + pao.fp_load = NULL; \ + pao.xchg_ops = patomic_ops_xchg_create_##name(); \ + pao.bitwise_ops = patomic_ops_bitwise_create_##name(); \ + pao.binary_ops = patomic_ops_binary_create_##name(); \ + pao.arithmetic_ops = patomic_ops_arithmetic_create_##name(); \ + return pao; \ + } + +#define PATOMIC_DEFINE_OPS_CREATE_AR(type, name, vis_p, inv, order, ops) \ + /* no store or load in acq_rel */ \ + PATOMIC_DEFINE_XCHG_OPS_CREATE(type, name, vis_p, inv, order, ops) \ + PATOMIC_DEFINE_BITWISE_OPS_CREATE_NO_LOAD(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_BINARY_OPS_CREATE(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_ARITHMETIC_OPS_CREATE(type, name, vis_p, order, ops) \ + static patomic_##ops##_t \ + patomic_ops_create_##name(void) \ + { \ + patomic_##ops##_t pao; \ + pao.fp_store = NULL; \ + pao.fp_load = NULL; \ + pao.xchg_ops = patomic_ops_xchg_create_##name(); \ + pao.bitwise_ops = patomic_ops_bitwise_create_##name(); \ + pao.binary_ops = patomic_ops_binary_create_##name(); \ + pao.arithmetic_ops = patomic_ops_arithmetic_create_##name(); \ + return pao; \ + } + +#define PATOMIC_DEFINE_OPS_CREATE_RSC(type, name, vis_p, inv, order, ops) \ + PATOMIC_DEFINE_STORE_OP(type, name, vis_p, order) \ + PATOMIC_DEFINE_LOAD_OP(type, name, vis_p, order) \ + PATOMIC_DEFINE_XCHG_OPS_CREATE(type, name, vis_p, inv, order, ops) \ + PATOMIC_DEFINE_BITWISE_OPS_CREATE_LOAD(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_BINARY_OPS_CREATE(type, name, vis_p, order, ops) \ + PATOMIC_DEFINE_ARITHMETIC_OPS_CREATE(type, name, vis_p, order, ops) \ + static patomic_##ops##_t \ + patomic_ops_create_##name(void) \ + { \ + patomic_##ops##_t pao; \ + pao.fp_store = patomic_opimpl_store_##name; \ + pao.fp_load = patomic_opimpl_load_##name; \ + pao.xchg_ops = patomic_ops_xchg_create_##name(); \ + pao.bitwise_ops = patomic_ops_bitwise_create_##name(); \ + pao.binary_ops = patomic_ops_binary_create_##name(); \ + pao.arithmetic_ops = patomic_ops_arithmetic_create_##name(); \ + return pao; \ + } + +#define PATOMIC_DEFINE_OPS_CREATE_ALL(type, name) \ + PATOMIC_DEFINE_OPS_CREATE_RSC( \ + type, name##_relaxed, HIDE_P, SHOW, memory_order_relaxed, ops \ + ) \ + /* consume is not supported, we just use acquire */ \ + PATOMIC_DEFINE_OPS_CREATE_CA( \ + type, name##_acquire, HIDE_P, SHOW, memory_order_acquire, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_R( \ + type, name##_release, HIDE_P, SHOW, memory_order_release, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_AR( \ + type, name##_acq_rel, HIDE_P, SHOW, memory_order_acq_rel, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_RSC( \ + type, name##_seq_cst, HIDE_P, SHOW, memory_order_seq_cst, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_RSC( \ + type, name##_explicit, SHOW_P, HIDE, order, ops_explicit \ + ) + + +#else /* PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H && PATOMIC_HAS_IR_TWOS_COMPL */ patomic_t @@ -355,7 +465,7 @@ patomic_impl_create_explicit_std( } -#endif /* PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H */ +#endif /* PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H && PATOMIC_HAS_IR_TWOS_COMPL */ patomic_transaction_t diff --git a/src/include/patomic/macros/static_assert.h b/src/include/patomic/macros/static_assert.h index 07bd11933..af1285042 100644 --- a/src/include/patomic/macros/static_assert.h +++ b/src/include/patomic/macros/static_assert.h @@ -11,6 +11,6 @@ * never be at the start). */ #define PATOMIC_STATIC_ASSERT(msg, expr) \ - typedef char patomic_static_assert##msg[(expr) ? 1 : -1] + typedef char patomic_static_assert_##msg[(expr) ? 1 : -1] #endif /* PATOMIC_STATIC_ASSERT */ diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 708cba0bd..6d98aa853 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -82,7 +82,7 @@ \ /* declarations */ \ type des; \ - type scratch \ + type scratch; \ int temp; \ \ /* assertions */ \ @@ -167,7 +167,7 @@ ) \ static void \ fn_name( \ - volatile void *const obj \ + const volatile void *const obj \ vis_p(_,const int order) \ ,void *const ret \ ) \ @@ -899,7 +899,7 @@ /* declarations */ \ type arg; \ type scratch; \ - int temp \ + int temp; \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ From 4e7e9cf54b7bfef399f425ebdfd4300db261ab8a Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 10:38:37 +0000 Subject: [PATCH 30/54] GHI #35 Implement all direct functionality for std impl --- src/impl/std/std.c | 231 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 212 insertions(+), 19 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 0cad3d890..72b61e132 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -8,6 +8,9 @@ #if PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H && PATOMIC_HAS_IR_TWOS_COMPL +#include +#include + #include #include @@ -394,28 +397,218 @@ return pao; \ } -#define PATOMIC_DEFINE_OPS_CREATE_ALL(type, name) \ - PATOMIC_DEFINE_OPS_CREATE_RSC( \ - type, name##_relaxed, HIDE_P, SHOW, memory_order_relaxed, ops \ - ) \ - /* consume is not supported, we just use acquire */ \ - PATOMIC_DEFINE_OPS_CREATE_CA( \ - type, name##_acquire, HIDE_P, SHOW, memory_order_acquire, ops \ - ) \ - PATOMIC_DEFINE_OPS_CREATE_R( \ - type, name##_release, HIDE_P, SHOW, memory_order_release, ops \ - ) \ - PATOMIC_DEFINE_OPS_CREATE_AR( \ - type, name##_acq_rel, HIDE_P, SHOW, memory_order_acq_rel, ops \ - ) \ - PATOMIC_DEFINE_OPS_CREATE_RSC( \ - type, name##_seq_cst, HIDE_P, SHOW, memory_order_seq_cst, ops \ - ) \ - PATOMIC_DEFINE_OPS_CREATE_RSC( \ - type, name##_explicit, SHOW_P, HIDE, order, ops_explicit \ +#define PATOMIC_DEFINE_OPS_CREATE_ALL(type, name) \ + PATOMIC_DEFINE_OPS_CREATE_RSC( \ + type, name##_relaxed, HIDE_P, SHOW, patomic_RELAXED, ops \ + ) \ + /* consume is not supported, we just use acquire */ \ + PATOMIC_DEFINE_OPS_CREATE_CA( \ + type, name##_acquire, HIDE_P, SHOW, patomic_ACQUIRE, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_R( \ + type, name##_release, HIDE_P, SHOW, patomic_RELEASE, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_AR( \ + type, name##_acq_rel, HIDE_P, SHOW, patomic_ACQ_REL, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_RSC( \ + type, name##_seq_cst, HIDE_P, SHOW, patomic_SEQ_CST, ops \ + ) \ + PATOMIC_DEFINE_OPS_CREATE_RSC( \ + type, name##_explicit, SHOW_P, HIDE, order, ops_explicit \ ) +#if ATOMIC_CHAR_LOCK_FREE + PATOMIC_DEFINE_OPS_CREATE_ALL(unsigned char, char) +#endif + +#if ATOMIC_SHORT_LOCK_FREE + PATOMIC_DEFINE_OPS_CREATE_ALL(unsigned short, short) +#endif + +#if ATOMIC_INT_LOCK_FREE + PATOMIC_DEFINE_OPS_CREATE_ALL(unsigned int, int) +#endif + +#if ATOMIC_LONG_LOCK_FREE + PATOMIC_DEFINE_OPS_CREATE_ALL(unsigned long, long) +#endif + +#undef HAS_LLONG_IMPL +#if ATOMIC_LLONG_LOCK_FREE && PATOMIC_STDINT_HAS_LLONG + #define HAS_LLONG_IMPL 1 + PATOMIC_DEFINE_OPS_CREATE_ALL(patomic_llong_unsigned_t, llong) +#else + #define HAS_LLONG_IMPL 0 +#endif + + +#define PATOMIC_SET_RET(type, name, byte_width, order, ops) \ + ((byte_width == sizeof(type)) && \ + (byte_width == sizeof(_Atomic(type)))) \ + { \ + _Atomic(type) obj; \ + if (atomic_is_lock_free(&obj)) \ + { \ + switch (order) \ + { \ + case patomic_RELAXED: \ + ops = patomic_ops_create_##name##_relaxed(); \ + break; \ + case patomic_CONSUME: \ + case patomic_ACQUIRE: \ + ops = patomic_ops_create_##name##_acquire(); \ + break; \ + case patomic_RELEASE: \ + ops = patomic_ops_create_##name##_release(); \ + break; \ + case patomic_ACQ_REL: \ + ops = patomic_ops_create_##name##_acq_rel(); \ + break; \ + case patomic_SEQ_CST: \ + ops = patomic_ops_create_##name##_seq_cst(); \ + break; \ + default: \ + patomic_assert_always("invalid memory order" && 0); \ + } \ + } \ + PATOMIC_IGNORE_UNUSED(obj); \ + } + +#define PATOMIC_SET_RET_EXPLICIT(type, name, byte_width, ops) \ + ((byte_width == sizeof(type)) && \ + (byte_width == sizeof(_Atomic(type)))) \ + { \ + _Atomic(type) obj; \ + if (atomic_is_lock_free(&obj)) \ + { \ + ops = patomic_ops_create_##name##_explicit(); \ + } \ + PATOMIC_IGNORE_UNUSED(obj); \ + } + +#define PATOMIC_SET_ALIGN(type, byte_width, member) \ + ((byte_width == sizeof(type)) && \ + (byte_width == sizeof(_Atomic(type)))) \ + { \ + member = patomic_alignof_type(_Atomic(type)); \ + } + + +static patomic_ops_t +patomic_create_ops( + const size_t byte_width, + const patomic_memory_order_t order +) +{ + /* setup */ + patomic_ops_t ops = {0}; + patomic_assert_always(patomic_is_valid_order((int) order)); + + /* set members */ + if PATOMIC_SET_RET(unsigned char, char, byte_width, order, ops) + else if PATOMIC_SET_RET(unsigned short, short, byte_width, order, ops) + else if PATOMIC_SET_RET(unsigned int, int, byte_width, order, ops) + else if PATOMIC_SET_RET(unsigned long, long, byte_width, order, ops) +#if HAS_LLONG_IMPL + else if PATOMIC_SET_RET(patomic_llong_unsigned_t, llong, byte_width, order, ops) +#endif + + /* return */ + return ops; +} + +static patomic_ops_explicit_t +patomic_create_ops_explicit( + const size_t byte_width +) +{ + /* setup */ + patomic_ops_explicit_t ops = {0}; + + /* set members */ + if PATOMIC_SET_RET_EXPLICIT(unsigned char, char, byte_width, ops) + else if PATOMIC_SET_RET_EXPLICIT(unsigned short, short, byte_width, ops) + else if PATOMIC_SET_RET_EXPLICIT(unsigned int, int, byte_width, ops) + else if PATOMIC_SET_RET_EXPLICIT(unsigned long, long, byte_width, ops) +#if HAS_LLONG_IMPL + else if PATOMIC_SET_RET_EXPLICIT(patomic_llong_unsigned_t, llong, byte_width, ops) +#endif + + /* return */ + return ops; +} + +static patomic_align_t +patomic_create_align( + const size_t byte_width +) +{ + /* setup */ + patomic_align_t align = {0}; + + /* set recommended */ + if PATOMIC_SET_ALIGN(unsigned char, byte_width, align.recommended) + else if PATOMIC_SET_ALIGN(unsigned short, byte_width, align.recommended) + else if PATOMIC_SET_ALIGN(unsigned int, byte_width, align.recommended) + else if PATOMIC_SET_ALIGN(unsigned long, byte_width, align.recommended) +#if HAS_LLONG_IMPL + else if PATOMIC_SET_ALIGN(patomic_llong_unsigned_t, byte_width, align.recommended) +#endif + else + { + /* minimum valid alignment */ + align.recommended = 1; + } + + /* set remaining members */ + align.minimum = align.recommended; + align.size_within = 0; + + /* return */ + return align; +} + + +patomic_t +patomic_impl_create_std( + const size_t byte_width, + const patomic_memory_order_t order, + const unsigned int options +) +{ + /* setup */ + patomic_t impl; + PATOMIC_IGNORE_UNUSED(options); + + /* set members */ + impl.ops = patomic_create_ops(byte_width, order); + impl.align = patomic_create_align(byte_width); + + /* return */ + return impl; +} + +patomic_explicit_t +patomic_impl_create_explicit_std( + const size_t byte_width, + const unsigned int options +) +{ + /* setup */ + patomic_explicit_t impl; + PATOMIC_IGNORE_UNUSED(options); + + /* set members */ + impl.ops = patomic_create_ops_explicit(byte_width); + impl.align = patomic_create_align(byte_width); + + /* return */ + return impl; +} + + #else /* PATOMIC_HAS_ATOMIC && PATOMIC_HAS_STDATOMIC_H && PATOMIC_HAS_IR_TWOS_COMPL */ From 3694227099081ea2905d286092acb5175aa2cde7 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 21:55:07 +0000 Subject: [PATCH 31/54] GHI #35 Flip rank order in std impl --- src/impl/std/std.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 72b61e132..2975502e0 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -507,13 +507,16 @@ patomic_create_ops( patomic_assert_always(patomic_is_valid_order((int) order)); /* set members */ - if PATOMIC_SET_RET(unsigned char, char, byte_width, order, ops) - else if PATOMIC_SET_RET(unsigned short, short, byte_width, order, ops) - else if PATOMIC_SET_RET(unsigned int, int, byte_width, order, ops) - else if PATOMIC_SET_RET(unsigned long, long, byte_width, order, ops) + /* go from largest to smallest in case some platform has two types with the + * same width but one has a larger range */ #if HAS_LLONG_IMPL - else if PATOMIC_SET_RET(patomic_llong_unsigned_t, llong, byte_width, order, ops) + if PATOMIC_SET_RET(patomic_llong_unsigned_t, llong, byte_width, order, ops) + else #endif + if PATOMIC_SET_RET(unsigned long, long, byte_width, order, ops) + else if PATOMIC_SET_RET(unsigned int, int, byte_width, order, ops) + else if PATOMIC_SET_RET(unsigned short, short, byte_width, order, ops) + else if PATOMIC_SET_RET(unsigned char, char, byte_width, order, ops) /* return */ return ops; @@ -528,13 +531,16 @@ patomic_create_ops_explicit( patomic_ops_explicit_t ops = {0}; /* set members */ - if PATOMIC_SET_RET_EXPLICIT(unsigned char, char, byte_width, ops) - else if PATOMIC_SET_RET_EXPLICIT(unsigned short, short, byte_width, ops) - else if PATOMIC_SET_RET_EXPLICIT(unsigned int, int, byte_width, ops) - else if PATOMIC_SET_RET_EXPLICIT(unsigned long, long, byte_width, ops) + /* go from largest to smallest in case some platform has two types with the + * same width but one has a larger range */ #if HAS_LLONG_IMPL - else if PATOMIC_SET_RET_EXPLICIT(patomic_llong_unsigned_t, llong, byte_width, ops) + if PATOMIC_SET_RET_EXPLICIT(patomic_llong_unsigned_t, llong, byte_width, ops) + else #endif + if PATOMIC_SET_RET_EXPLICIT(unsigned long, long, byte_width, ops) + else if PATOMIC_SET_RET_EXPLICIT(unsigned int, int, byte_width, ops) + else if PATOMIC_SET_RET_EXPLICIT(unsigned short, short, byte_width, ops) + else if PATOMIC_SET_RET_EXPLICIT(unsigned char, char, byte_width, ops) /* return */ return ops; @@ -549,13 +555,16 @@ patomic_create_align( patomic_align_t align = {0}; /* set recommended */ - if PATOMIC_SET_ALIGN(unsigned char, byte_width, align.recommended) - else if PATOMIC_SET_ALIGN(unsigned short, byte_width, align.recommended) - else if PATOMIC_SET_ALIGN(unsigned int, byte_width, align.recommended) - else if PATOMIC_SET_ALIGN(unsigned long, byte_width, align.recommended) + /* go from largest to smallest in case some platform has two types with the + * same width but one has a larger range */ #if HAS_LLONG_IMPL - else if PATOMIC_SET_ALIGN(patomic_llong_unsigned_t, byte_width, align.recommended) + if PATOMIC_SET_ALIGN(patomic_llong_unsigned_t, byte_width, align.recommended) + else #endif + if PATOMIC_SET_ALIGN(unsigned long, byte_width, align.recommended) + else if PATOMIC_SET_ALIGN(unsigned int, byte_width, align.recommended) + else if PATOMIC_SET_ALIGN(unsigned short, byte_width, align.recommended) + else if PATOMIC_SET_ALIGN(unsigned char, byte_width, align.recommended) else { /* minimum valid alignment */ From b060e85ac7c00fb970bb915f96aeac7ed58beef1 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 22:54:53 +0000 Subject: [PATCH 32/54] GHI #35 Remove scratch and temp --- src/impl/std/std.c | 9 +- src/include/patomic/wrapped/direct.h | 143 +++------------------------ 2 files changed, 18 insertions(+), 134 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 2975502e0..560386aeb 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -95,9 +95,12 @@ * - bit_test_reset (no) */ #define do_bit_test_explicit(type, obj, offset, order, res) \ - scratch = (type) ((type) 1 << (type) offset); \ - scratch &= atomic_load_explicit(obj, order); \ - res = (scratch != (type) 0) + do { \ + type scratch = (type) ((type) 1 << (type) offset); \ + scratch &= atomic_load_explicit(obj, order); \ + res = (scratch != (type) 0); \ + } \ + while (0) #define PATOMIC_DEFINE_BIT_TEST_OP(type, name, vis_p, order) \ PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST( \ diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 6d98aa853..d1b828f02 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -57,13 +57,6 @@ * to by 'obj' * - the atomic operation uses a store memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_STORE( \ atomic_type, type, fn_name, vis_p, order, \ @@ -82,8 +75,6 @@ \ /* declarations */ \ type des; \ - type scratch; \ - int temp; \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -91,7 +82,7 @@ PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_STORE_ORDER((int) order)); \ \ - /* setup */ \ + /* inputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ \ /* operation */ \ @@ -101,10 +92,6 @@ des, \ (int) order \ ); \ - \ - /* cleanup */ \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ } @@ -153,13 +140,6 @@ * - 'res' is set to the value which was read * - the atomic operation uses a load memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_LOAD( \ atomic_type, type, fn_name, vis_p, order, \ @@ -178,8 +158,6 @@ \ /* declarations */ \ type res; \ - type scratch; \ - int temp; \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -195,10 +173,8 @@ res \ ); \ \ - /* cleanup */ \ + /* outputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ } @@ -250,13 +226,6 @@ * - the value read from 'obj' is stored into 'res' * - the atomic operation uses a memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_EXCHANGE( \ atomic_type, type, fn_name, vis_p, order, \ @@ -277,8 +246,6 @@ /* declarations */ \ type des; \ type res; \ - type scratch; \ - int temp; \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -287,7 +254,7 @@ PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ \ - /* setup */ \ + /* inputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ \ /* operation */ \ @@ -299,10 +266,8 @@ res \ ); \ \ - /* cleanup */ \ + /* outputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ } @@ -365,13 +330,6 @@ * - the atomic operation uses a memory ordering at least as strong as 'succ' * for a successful exchange, and a load memory ordering at least as strong * as 'fail' for a failed exchange - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_CMPXCHG( \ atomic_type, type, fn_name, vis_p, inv, order, \ @@ -393,9 +351,7 @@ /* declarations */ \ type exp; \ type des; \ - type scratch; \ int ok = 0; \ - int temp; \ inv(int succ = (int) order;) \ inv(int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ);) \ \ @@ -407,8 +363,7 @@ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER(succ)); \ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_FAIL_ORDER(succ, fail)); \ \ - \ - /* setup */ \ + /* inputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ PATOMIC_WRAPPED_DO_MEMCPY(&exp, expected, sizeof(type)); \ \ @@ -421,10 +376,8 @@ ok \ ); \ \ - /* cleanup */ \ + /* outputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(expected, &exp, sizeof(type)); \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ return ok != 0; \ } @@ -476,13 +429,6 @@ * - 'res' is set to the bit at offset 'offset' of the value which was read * - the atomic operation uses a load memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST( \ atomic_type, type, fn_name, vis_p, order, \ @@ -500,8 +446,6 @@ sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ \ /* declarations */ \ - type scratch; \ - int temp; \ int res; \ \ /* assertions */ \ @@ -520,9 +464,7 @@ res \ ); \ \ - /* cleanup */ \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ + /* outputs */ \ return res != 0; \ } @@ -576,13 +518,6 @@ * - the atomic operation uses a store memory ordering at least as strong as * 'order' if the operation does not require reading the old value, * otherwise it uses a memory ordering at least as strong as 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST_MODIFY( \ atomic_type, type, fn_name, vis_p, order, \ @@ -600,8 +535,6 @@ sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ \ /* declarations */ \ - type scratch; \ - int temp; \ int res; \ \ /* assertions */ \ @@ -620,9 +553,7 @@ res \ ); \ \ - /* cleanup */ \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ + /* outputs */ \ return res != 0; \ } @@ -675,13 +606,6 @@ * 'obj' * - the atomic operation uses a memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ atomic_type, type, fn_name, vis_p, order, \ @@ -702,8 +626,6 @@ /* declarations */ \ type arg; \ type res; \ - type scratch; \ - int temp; \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -712,7 +634,7 @@ PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ \ - /* setup */ \ + /* inputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(&arg, argument, sizeof(type)); \ \ /* operation */ \ @@ -724,10 +646,8 @@ res \ ); \ \ - /* cleanup */ \ + /* outputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ } @@ -779,13 +699,6 @@ * 'obj' * - the atomic operation uses a memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH_NOARG( \ atomic_type, type, fn_name, vis_p, order, \ @@ -804,8 +717,6 @@ \ /* declarations */ \ type res; \ - type scratch; \ - int temp; \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -821,10 +732,8 @@ res \ ); \ \ - /* cleanup */ \ + /* outputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(ret, &res, sizeof(type)); \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ } @@ -873,13 +782,6 @@ * single atomic operation * - the atomic operation uses a memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ atomic_type, type, fn_name, vis_p, order, \ @@ -898,8 +800,6 @@ \ /* declarations */ \ type arg; \ - type scratch; \ - int temp; \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -907,7 +807,7 @@ PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ \ - /* setup */ \ + /* inputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(&arg, argument, sizeof(type)); \ \ /* operation */ \ @@ -917,10 +817,6 @@ arg, \ (int) order \ ); \ - \ - /* cleanup */ \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ } @@ -969,13 +865,6 @@ * single atomic operation * - the atomic operation uses a memory ordering at least as strong as * 'order' - * - * The following local variables will also be available to be used by the - * macro M: - * - 'temp' has type 'int' - * - 'scratch' has type 'type' - * - their value is unspecified and they may be uninitialized - * - these are provided to support C90's lack of declarations after code */ #define PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID_NOARG( \ atomic_type, type, fn_name, vis_p, order, \ @@ -991,10 +880,6 @@ PATOMIC_STATIC_ASSERT( \ sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ \ - /* declarations */ \ - type scratch; \ - int temp; \ - \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ @@ -1006,10 +891,6 @@ (volatile atomic_type *) obj, \ (int) order \ ); \ - \ - /* cleanup */ \ - PATOMIC_IGNORE_UNUSED(scratch); \ - PATOMIC_IGNORE_UNUSED(temp); \ } From 598a6bda023b93615ef0a6096d06c35442c35acf Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 23:23:13 +0000 Subject: [PATCH 33/54] GHI #35 Improve direct docs --- src/include/patomic/wrapped/direct.h | 163 ++++++++++++++------------- 1 file changed, 84 insertions(+), 79 deletions(-) diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index d1b828f02..13a975d79 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -44,13 +44,14 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_store_explicit - * A macro, M, callable as 'M(type, obj, des, order)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'des' will be the name of a local identifier, with the type 'type' - * - 'order' will be an expression of type 'int' whose value is a valid - * store memory order + * A macro, M, callable as 'M(type, obj, des, order);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'order' : an expression of type 'int' whose value is a valid store + * memory order * * The expected behaviour of calling the macro M as above is: * - the value of 'des' is read and atomically stored into the object pointed @@ -127,13 +128,14 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_load_explicit - * A macro, M, callable as 'M(type, obj, order, res)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'const volatile atomic_type *' - * - 'order' will be an expression of type 'int' whose value is a valid - * load memory order - * - 'res' will be the name of a local identifier, with the type 'type' + * A macro, M, callable as 'M(type, obj, order, res);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'const volatile atomic_type *' + * - 'order' : an expression of type 'int' whose value is a valid load memory + * order + * - 'res' : the name of an identifier designating an object of type 'type' * * The expected behaviour of calling the macro M as above is: * - the value of the object pointed to by 'obj' is atomically read @@ -210,14 +212,14 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_exchange_explicit - * A macro, M, callable as 'M(type, obj, des, order, res)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'des' will be the name of a local identifier, with the type 'type' - * - 'order' will be an expression of type 'int' whose value is a valid - * memory order - * - 'res' will be the name of a local identifier, with the type 'type' + * A macro, M, callable as 'M(type, obj, des, order, res);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'order' : an expression of type 'int' whose value is a valid memory order + * - 'res' : the name of an identifier designating an object of type 'type' * * The expected behaviour of calling the macro M as above is: * - the value of 'des' is read and, in a single atomic operation is stored @@ -307,17 +309,18 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_cmpxchg_explicit - * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok)' where - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'exp' will be the name of a local identifier, with the type 'type' - * - 'des' will be the name of a local identifier, with the type 'type' - * - 'succ' will be an expression of type 'int' whose value is a valid - * memory order - * - 'fail' will be an expression of type 'int' whose value is a valid - * load memory order not stronger than 'succ' - * - 'ok' will be the name of a local identifier, with the type 'int' + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' * * The expected behaviour of calling the macro M as above is: * - the values of 'exp' and 'des' are read @@ -414,15 +417,16 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_bit_test_explicit - * A macro, M, callable as 'M(type, obj, offset, order, res)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'const volatile atomic_type *' - * - 'offset' will be an expression of type 'int' whose value is non-negative - * and less than 'sizeof(type) * CHAR_BIT' - * - 'order' will be an expression of type 'int' whose value is a valid - * load memory order - * - 'res' will be the name of a local identifier, with the type 'int' + * A macro, M, callable as 'M(type, obj, offset, order, res);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'const volatile atomic_type *' + * - 'offset' : an expression of type 'int' whose value is non-negative and + * less than 'sizeof(type) * CHAR_BIT' + * - 'order' : an expression of type 'int' whose value is a valid load + * memory order + * - 'res' : the name of an identifier designating an object of type 'int' * * The expected behaviour of calling the macro M as above is: * - the value of the object pointed to by 'obj' is atomically read @@ -502,15 +506,16 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_bit_test_modify_explicit - * A macro, M, callable as 'M(type, obj, offset, order, res)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'offset' will be an expression of type 'int' whose value is non-negative - * and less than 'sizeof(type) * CHAR_BIT' - * - 'order' will be an expression of type 'int' whose value is a valid - * memory order - * - 'res' will be the name of a local identifier, with the type 'int' + * A macro, M, callable as 'M(type, obj, offset, order, res);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'offset' : an expression of type 'int' whose value is non-negative and + * less than 'sizeof(type) * CHAR_BIT' + * - 'order' : an expression of type 'int' whose value is a valid memory + * order + * - 'res' : the name of an identifier designating an object of type 'int' * * The expected behaviour of calling the macro M as above is: * - the bit at offset 'offset' in the object pointed to by 'obj' is modified @@ -590,14 +595,14 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_fetch_explicit - * A macro, M, callable as 'M(type, obj, arg, order, res)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'arg' will be the name of a local identifier, with the type 'type' - * - 'order' will be an expression of type 'int' whose value is a valid - * memory order - * - 'res' will be the name of a local identifier, with the type 'type' + * A macro, M, callable as 'M(type, obj, arg, order, res);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'arg' : the name of an identifier designating an object of type 'type' + * - 'order' : an expression of type 'int' whose value is a valid memory order + * - 'res' : the name of an identifier designating an object of type 'type' * * The expected behaviour of calling the macro M as above is: * - the value of the object pointed to by 'obj' is read and modified in a @@ -684,13 +689,13 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_fetch_noarg_explicit - * A macro, M, callable as 'M(type, obj, order, res)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'order' will be an expression of type 'int' whose value is a valid - * memory order - * - 'res' will be the name of a local identifier, with the type 'type' + * A macro, M, callable as 'M(type, obj, order, res);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'order' : an expression of type 'int' whose value is a valid memory order + * - 'res' : the name of an identifier designating an object of type 'type' * * The expected behaviour of calling the macro M as above is: * - the value of the object pointed to by 'obj' is read and modified in a @@ -769,13 +774,13 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_void_explicit - * A macro, M, callable as 'M(type, obj, arg, order)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'arg' will be the name of a local identifier, with the type 'type' - * - 'order' will be an expression of type 'int' whose value is a valid - * memory order + * A macro, M, callable as 'M(type, obj, arg, order);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'arg' : the name of an identifier designating an object of type 'type' + * - 'order' : an expression of type 'int' whose value is a valid memory order * * The expected behaviour of calling the macro M as above is: * - the value of the object pointed to by 'obj' is read and modified in a @@ -853,12 +858,12 @@ * memory order to be used implicitly by the atomic operation. * * @param do_atomic_void_noarg_explicit - * A macro, M, callable as 'M(type, obj, order)' where: - * - the result of the expression is unused - * - 'type' is forwarded directly - * - 'obj' will be an expression of type 'volatile atomic_type *' - * - 'order' will be an expression of type 'int' whose value is a valid - * memory order + * A macro, M, callable as 'M(type, obj, order);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'order' : an expression of type 'int' whose value is a valid memory order * * The expected behaviour of calling the macro M as above is: * - the value of the object pointed to by 'obj' is read and modified in a From 65f9452708e27f1c10d53125d0f7a278504f5093 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 23:40:21 +0000 Subject: [PATCH 34/54] GHI #35 Add cmpxchg wrapped with store --- src/include/patomic/wrapped/CMakeLists.txt | 1 + src/include/patomic/wrapped/cmpxchg.h | 117 +++++++++++++++++++++ src/include/patomic/wrapped/direct.h | 1 - 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/include/patomic/wrapped/cmpxchg.h diff --git a/src/include/patomic/wrapped/CMakeLists.txt b/src/include/patomic/wrapped/CMakeLists.txt index 2b99227f9..e5cc08343 100644 --- a/src/include/patomic/wrapped/CMakeLists.txt +++ b/src/include/patomic/wrapped/CMakeLists.txt @@ -1,5 +1,6 @@ # add directory files to target target_sources(${target_name} PRIVATE base.h + cmpxchg.h direct.h ) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h new file mode 100644 index 000000000..035593c49 --- /dev/null +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -0,0 +1,117 @@ +#ifndef PATOMIC_WRAPPED_CMPXCHG_H +#define PATOMIC_WRAPPED_CMPXCHG_H + +#include "base.h" + +#include + +#include + +#include +#include + + +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic store operation using + * cmpxchg_weak as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_store_t + * or patomic_opsig_explicit_store_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_STORE( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_cmpxchg_weak_explicit \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + ,const void *const desired \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp = {0}; \ + type des; \ + int succ; \ + int fail; \ + int ok = 0; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(desired != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_STORE_ORDER((int) order)); \ + \ + /* inputs */ \ + succ = (int) order; \ + fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ + PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ + \ + /* operation */ \ + do { \ + do_atomic_cmpxchg_weak_explicit( \ + type, \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + while (!ok); \ + } + + +#endif /* PATOMIC_WRAPPED_CMPXCHG_H */ diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 13a975d79..3ef12dffe 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -3,7 +3,6 @@ #include "base.h" -#include #include #include From a70391f9f5d83a4bcaebcf1aae3ff37691ec59eb Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 30 Oct 2024 23:48:03 +0000 Subject: [PATCH 35/54] GHI #35 Add exchange to cmpxchg wrapped --- src/include/patomic/wrapped/cmpxchg.h | 109 ++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index 035593c49..2378e7457 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -114,4 +114,113 @@ } +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic exchange operation using + * cmpxchg_weak as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_exchange_t + * or patomic_opsig_explicit_exchange_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_EXCHANGE( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_cmpxchg_weak_explicit \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + ,const void *const desired \ + vis_p(_,const int order) \ + ,void *const ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp = {0}; \ + type des; \ + int succ; \ + int fail; \ + int ok = 0; \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(desired != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* inputs */ \ + succ = (int) order; \ + fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ + PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ + \ + /* operation */ \ + do { \ + do_atomic_cmpxchg_weak_explicit( \ + type, \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + } \ + while (!ok); \ + \ + /* outputs */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &exp, sizeof(type)); \ + } + + #endif /* PATOMIC_WRAPPED_CMPXCHG_H */ From 80a7eb6646f9dce06ea79f51c13f594e995b40c2 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 00:52:30 +0000 Subject: [PATCH 36/54] GHI #35 Add cmpxchg_strong to cmpxchg wrapped --- src/include/patomic/wrapped/cmpxchg.h | 153 ++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index 2378e7457..b465883f8 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -223,4 +223,157 @@ } +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic cmpxchg operation which + * cannot spuriously fail using cmpxchg_weak as the underlying atomic + * operation. + * + * @details + * The defined function's signature will match either patomic_opsig_cmpxchg_t + * or patomic_opsig_explicit_cmpxchg_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param inv + * Either the macro 'HIDE' if 'vis_p' is 'SHOW_P', or the macro 'SHOW' if + * 'vis_p' is 'HIDE_P'. + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + * + * @param do_cmp_eq + * A macro, C, callable as 'C(type, a, b, cmp);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'a' : the name of an identifier designating an object of type 'type' + * - 'b' : the name of an identifier designating an object of type 'type' + * - 'cmp' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro C as above is: + * - 'cmp' is set to a non-zero value if 'a' and 'b' compare equal, otherwise + * it is set to zero + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_CMPXCHG_STRONG( \ + atomic_type, type, fn_name, vis_p, inv, order, \ + do_atomic_cmpxchg_weak_explicit, do_cmp_eq \ +) \ + static int \ + fn_name( \ + volatile void *const obj \ + ,void *const expected \ + ,const void *const desired \ + vis_p(_,const int succ) \ + vis_p(_,const int fail) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp; \ + type des; \ + type old; \ + int cmp = 0; \ + int ok = 0; \ + inv(int succ = (int) order;) \ + inv(int fail = PATOMIC_CMPXCHG_FAIL_ORDER((int) order);) \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(expected != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(desired != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER(succ)); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_FAIL_ORDER(succ, fail)); \ + \ + /* inputs */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&exp, expected, sizeof(type)); \ + PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ + PATOMIC_WRAPPED_DO_MEMCPY(&old, &exp, sizeof(type)); \ + \ + /* operation */ \ + do { \ + /* cmpxchg_weak */ \ + do_atomic_cmpxchg_weak_explicit( \ + type \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + \ + /* check for modification */ \ + do_cmp_eq( \ + type, \ + exp, old, \ + cmp \ + ); \ + \ + /* was modified */ \ + if (!cmp) \ + { \ + break; \ + } \ + \ + /* spurious failure */ \ + /* save loaded value for future comparison */ \ + else \ + { \ + PATOMIC_WRAPPED_DO_MEMCPY(&old, &exp, sizeof(type)); \ + } \ + } \ + while (!ok); \ + \ + /* outputs */ \ + PATOMIC_WRAPPED_DO_MEMCPY(expected, &exp, sizeof(type)); \ + return ok != 0; \ + } + + #endif /* PATOMIC_WRAPPED_CMPXCHG_H */ From c5cf0ebcefe290162365e7782a8ee003e9d94376 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 01:47:37 +0000 Subject: [PATCH 37/54] GHI #35 Minor tidying up --- src/include/patomic/wrapped/cmpxchg.h | 41 +++++++++++---------------- src/include/patomic/wrapped/direct.h | 6 ++-- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index b465883f8..13725f68a 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -86,9 +86,9 @@ /* declarations */ \ type exp = {0}; \ type des; \ - int succ; \ - int fail; \ - int ok = 0; \ + int ok; \ + const int succ = (int) order; \ + const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -97,8 +97,6 @@ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_STORE_ORDER((int) order)); \ \ /* inputs */ \ - succ = (int) order; \ - fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ \ /* operation */ \ @@ -190,9 +188,9 @@ /* declarations */ \ type exp = {0}; \ type des; \ - int succ; \ - int fail; \ - int ok = 0; \ + int ok; \ + const int succ = (int) order; \ + const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -202,8 +200,6 @@ PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ \ /* inputs */ \ - succ = (int) order; \ - fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ \ /* operation */ \ @@ -319,10 +315,10 @@ type exp; \ type des; \ type old; \ - int cmp = 0; \ - int ok = 0; \ - inv(int succ = (int) order;) \ - inv(int fail = PATOMIC_CMPXCHG_FAIL_ORDER((int) order);) \ + int eq; \ + int ok; \ + inv(const int succ = (int) order;) \ + inv(const int fail = PATOMIC_CMPXCHG_FAIL_ORDER((int) order);) \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ @@ -335,10 +331,12 @@ /* inputs */ \ PATOMIC_WRAPPED_DO_MEMCPY(&exp, expected, sizeof(type)); \ PATOMIC_WRAPPED_DO_MEMCPY(&des, desired, sizeof(type)); \ - PATOMIC_WRAPPED_DO_MEMCPY(&old, &exp, sizeof(type)); \ \ /* operation */ \ do { \ + /* save expected value for comparison */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&old, &exp, sizeof(type)); \ + \ /* cmpxchg_weak */ \ do_atomic_cmpxchg_weak_explicit( \ type \ @@ -352,20 +350,13 @@ do_cmp_eq( \ type, \ exp, old, \ - cmp \ + eq \ ); \ \ - /* was modified */ \ - if (!cmp) \ + /* was modified: non-spurious failure */ \ + if (!eq) \ { \ break; \ - } \ - \ - /* spurious failure */ \ - /* save loaded value for future comparison */ \ - else \ - { \ - PATOMIC_WRAPPED_DO_MEMCPY(&old, &exp, sizeof(type)); \ } \ } \ while (!ok); \ diff --git a/src/include/patomic/wrapped/direct.h b/src/include/patomic/wrapped/direct.h index 3ef12dffe..7ece5c431 100644 --- a/src/include/patomic/wrapped/direct.h +++ b/src/include/patomic/wrapped/direct.h @@ -353,9 +353,9 @@ /* declarations */ \ type exp; \ type des; \ - int ok = 0; \ - inv(int succ = (int) order;) \ - inv(int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ);) \ + int ok; \ + inv(const int succ = (int) order;) \ + inv(const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ);) \ \ /* assertions */ \ PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ From 5cc96d475a34f12c4e7c26cf7ffec0cdffb3b0e6 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 02:15:45 +0000 Subject: [PATCH 38/54] GHI #35 Add bit-test-modify to wrapped cmpxchg --- src/include/patomic/wrapped/cmpxchg.h | 152 +++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 1 deletion(-) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index 13725f68a..f9716f0d9 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -339,7 +339,7 @@ \ /* cmpxchg_weak */ \ do_atomic_cmpxchg_weak_explicit( \ - type \ + type, \ (volatile atomic_type *) obj, \ exp, des, \ succ, fail, \ @@ -367,4 +367,154 @@ } +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic bit test-modify operation + * using cmpxchg_weak as the underlying atomic operation. + * + * @details + * The defined function's signature will match either + * patomic_opsig_test_modify_t or patomic_opsig_explicit_test_modify_t + * (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + * + * @param do_get_bit + * A macro, B, callable as 'B(type, exp, offset, bit);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'offset' : an expression of type 'int' whose value is non-negative and + * less than 'sizeof(type) * CHAR_BIT' + * - 'bit' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro B as above is: + * - 'bit' is set to the value of the bit at offset 'offset' of 'exp' + * - 'exp' should not be modified + * + * @param do_make_desired + * A macro, D, callable as 'D(type, exp, offset, des);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'offset' : an expression of type 'int' whose value is non-negative and + * less than 'sizeof(type) * CHAR_BIT' + * - 'des' : the name of an identifier designating an object of type 'type' + * + * The expected behaviour of calling the macro D as above is: + * - 'des' should be set to the value of 'exp' after the desired modify + * operation is applied + * - 'exp' should not be modified + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_BIT_TEST_MODIFY( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_cmpxchg_weak_explicit, \ + do_get_bit, do_make_desired \ +) \ + static int \ + fn_name( \ + volatil void *const obj, \ + ,const int offset \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp = {0}; \ + type des; \ + int exp_bit; \ + int ok; \ + const int succ = (int) order; \ + const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(offset >= 0); \ + PATOMIC_WRAPPED_DO_ASSERT((size_t) offset < (sizeof(type) * CHAR_BIT)); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* operation */ \ + do { \ + /* get the expected bit */ \ + do_get_bit( \ + type, \ + exp, offset \ + old_bit \ + ); \ + \ + /* make the desired value from the expected value */ \ + do_make_desired( \ + type, \ + exp, offset, \ + des \ + ); \ + \ + /* cmpxchg_weak */ \ + do_atomic_cmpxchg_weak_explicit( \ + type, \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + } \ + while (!ok); \ + \ + /* outputs */ \ + return ok != 0; \ + } + + #endif /* PATOMIC_WRAPPED_CMPXCHG_H */ From 2d416d49c6952f091793bee4cf325b713fb65696 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 02:33:14 +0000 Subject: [PATCH 39/54] GHI #35 Add bit-test-modify ops to std impl (using cmpxchg) --- src/impl/std/std.c | 59 ++++++++++++++++++++++++--- src/include/patomic/wrapped/cmpxchg.h | 8 ++-- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 560386aeb..303dfb89b 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -96,12 +97,40 @@ */ #define do_bit_test_explicit(type, obj, offset, order, res) \ do { \ - type scratch = (type) ((type) 1 << (type) offset); \ - scratch &= atomic_load_explicit(obj, order); \ - res = (scratch != (type) 0); \ + type mask = (type) ((type) 1 << offset); \ + mask &= atomic_load_explicit(obj, order); \ + res = (mask != (type) 0); \ } \ while (0) +#define do_get_bit(type, exp, offset, bit) \ + do { \ + const type mask = (type) ((type) 1 << offset); \ + bit = (exp & mask) != 0; \ + } \ + while (0) + +#define do_make_desired_compl(type, exp, offset, des) \ + do { \ + const type mask = (type) ((type) 1 << offset); \ + des = (type) (exp ^ mask); \ + } \ + while (0) + +#define do_make_desired_set(type, exp, offset, des) \ + do { \ + const type mask = (type) ((type) 1 << offset); \ + des = (type) (exp | mask); \ + } \ + while (0) + +#define do_make_desired_reset(type, exp, offset, des) \ + do { \ + const type mask = (type) ((type) 1 << offset); \ + des = (type) (exp & (type) ~mask); \ + } \ + while (0) + #define PATOMIC_DEFINE_BIT_TEST_OP(type, name, vis_p, order) \ PATOMIC_WRAPPED_DIRECT_DEFINE_OP_BIT_TEST( \ _Atomic(type), type, \ @@ -111,9 +140,27 @@ ) #define PATOMIC_DEFINE_BIT_TEST_MODIFY_OPS(type, name, vis_p, order) \ - static const void * patomic_opimpl_bit_test_compl_##name = NULL; \ - static const void * patomic_opimpl_bit_test_set_##name = NULL; \ - static const void * patomic_opimpl_bit_test_reset_##name = NULL; + PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_BIT_TEST_MODIFY( \ + _Atomic(type), type, \ + patomic_opimpl_bit_test_compl_##name, \ + vis_p, order, \ + do_cmpxchg_weak, \ + do_get_bit, do_make_desired_compl \ + ) \ + PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_BIT_TEST_MODIFY( \ + _Atomic(type), type, \ + patomic_opimpl_bit_test_set_##name, \ + vis_p, order, \ + do_cmpxchg_weak, \ + do_get_bit, do_make_desired_set \ + ) \ + PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_BIT_TEST_MODIFY( \ + _Atomic(type), type, \ + patomic_opimpl_bit_test_reset_##name, \ + vis_p, order, \ + do_cmpxchg_weak, \ + do_get_bit, do_make_desired_reset \ + ) /* create ops which support all memory orders */ #define PATOMIC_DEFINE_BITWISE_OPS_CREATE_NO_LOAD(type, name, vis_p, order, ops) \ diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index f9716f0d9..f71b26db3 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -461,7 +461,7 @@ ) \ static int \ fn_name( \ - volatil void *const obj, \ + volatile void *const obj \ ,const int offset \ vis_p(_,const int order) \ ) \ @@ -490,8 +490,8 @@ /* get the expected bit */ \ do_get_bit( \ type, \ - exp, offset \ - old_bit \ + exp, offset, \ + exp_bit \ ); \ \ /* make the desired value from the expected value */ \ @@ -513,7 +513,7 @@ while (!ok); \ \ /* outputs */ \ - return ok != 0; \ + return exp_bit; \ } From 047a5ba668df931b9a90ca5c3ccb740ab4fdc504 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 02:54:34 +0000 Subject: [PATCH 40/54] GHI #35 Add define fetch ops to wrapped cmpxchg --- src/include/patomic/wrapped/cmpxchg.h | 131 ++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index f71b26db3..860d1e5ad 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -517,4 +517,135 @@ } +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic fetch operation using + * cmpxchg_weak as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_fetch_t + * or patomic_opsig_explicit_fetch_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + * + * @param do_make_desired + * A macro, D, callable as 'D(type, exp, arg, des);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'arg' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * + * The expected behaviour of calling the macro D as above is: + * - 'des' should be set to the value of 'exp' after the desired modify + * operation is applied + * - 'exp' and 'arg' should not be modified + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_FETCH( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_cmpxchg_weak_explicit, \ + do_make_desired \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + ,const void *const argument \ + vis_p(_,const int order) \ + ,void *const ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp = {0}; \ + type des; \ + type arg; \ + int ok; \ + const int succ = (int) order; \ + const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(argument != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* inputs */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&arg, argument, sizeof(type)); \ + \ + /* operation */ \ + do { \ + /* make the desired value from the expected value */ \ + do_make_desired( \ + type, \ + exp, arg, \ + des \ + ); \ + \ + /* cmpxchg_weak */ \ + do_atomic_cmpxchg_weak_explicit( \ + type, \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + } \ + while (!ok); \ + \ + /* outputs */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &exp, sizeof(type)); \ + } + + #endif /* PATOMIC_WRAPPED_CMPXCHG_H */ From 2383b51d28de8f7ce41e75975c5cede406f76278 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 03:03:10 +0000 Subject: [PATCH 41/54] GHI #35 Add define fetch noarg ops to wrapped cmpxchg --- src/include/patomic/wrapped/cmpxchg.h | 125 ++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index 860d1e5ad..10cfcc623 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -648,4 +648,129 @@ } +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic noarg fetch operation using + * cmpxchg_weak as the underlying atomic operation. + * + * @details + * The defined function's signature will match either + * patomic_opsig_fetch_noarg_t or patomic_opsig_explicit_fetch_noarg_t + * (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + * + * @param do_make_desired + * A macro, D, callable as 'D(type, exp, des);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * + * The expected behaviour of calling the macro D as above is: + * - 'des' should be set to the value of 'exp' after the desired modify + * operation is applied + * - 'exp' and should not be modified + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_FETCH_NOARG( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_cmpxchg_weak_explicit, \ + do_make_desired \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + vis_p(_,const int order) \ + ,void *const ret \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp = {0}; \ + type des; \ + int ok; \ + const int succ = (int) order; \ + const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(ret != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* operation */ \ + do { \ + /* make the desired value from the expected value */ \ + do_make_desired( \ + type, \ + exp, \ + des \ + ); \ + \ + /* cmpxchg_weak */ \ + do_atomic_cmpxchg_weak_explicit( \ + type, \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + } \ + while (!ok); \ + \ + /* outputs */ \ + PATOMIC_WRAPPED_DO_MEMCPY(ret, &exp, sizeof(type)); \ + } + + #endif /* PATOMIC_WRAPPED_CMPXCHG_H */ From c6ee31a1852dc4b8d4e5b860ebcfed5c21924fd5 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 03:07:48 +0000 Subject: [PATCH 42/54] GHI #35 Add define void ops to wrapped cmpxchg --- src/include/patomic/wrapped/cmpxchg.h | 126 ++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index 10cfcc623..1b642ace7 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -773,4 +773,130 @@ } +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic void operation using + * cmpxchg_weak as the underlying atomic operation. + * + * @details + * The defined function's signature will match either patomic_opsig_void_t or + * patomic_opsig_explicit_void_t (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + * + * @param do_make_desired + * A macro, D, callable as 'D(type, exp, arg, des);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'arg' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * + * The expected behaviour of calling the macro D as above is: + * - 'des' should be set to the value of 'exp' after the desired modify + * operation is applied + * - 'exp' and 'arg' should not be modified + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_VOID( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_cmpxchg_weak_explicit, \ + do_make_desired \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + ,const void *const argument \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp = {0}; \ + type des; \ + type arg; \ + int ok; \ + const int succ = (int) order; \ + const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT(argument != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* inputs */ \ + PATOMIC_WRAPPED_DO_MEMCPY(&arg, argument, sizeof(type)); \ + \ + /* operation */ \ + do { \ + /* make the desired value from the expected value */ \ + do_make_desired( \ + type, \ + exp, arg, \ + des \ + ); \ + \ + /* cmpxchg_weak */ \ + do_atomic_cmpxchg_weak_explicit( \ + type, \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + } \ + while (!ok); \ + } + + #endif /* PATOMIC_WRAPPED_CMPXCHG_H */ From 890090ff3903d7093d385bf65326845d7c8c62ee Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 03:10:12 +0000 Subject: [PATCH 43/54] GHI #35 Add define void noarg ops to wrapped cmpxchg --- src/include/patomic/wrapped/cmpxchg.h | 122 +++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/src/include/patomic/wrapped/cmpxchg.h b/src/include/patomic/wrapped/cmpxchg.h index 1b642ace7..4c5be5320 100644 --- a/src/include/patomic/wrapped/cmpxchg.h +++ b/src/include/patomic/wrapped/cmpxchg.h @@ -717,7 +717,7 @@ * The expected behaviour of calling the macro D as above is: * - 'des' should be set to the value of 'exp' after the desired modify * operation is applied - * - 'exp' and should not be modified + * - 'exp' should not be modified */ #define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_FETCH_NOARG( \ atomic_type, type, fn_name, vis_p, order, \ @@ -899,4 +899,124 @@ } +/** + * @addtogroup wrapped.cmpxchg + * + * @brief + * Defines a function which implements an atomic void noarg operation using + * cmpxchg_weak as the underlying atomic operation. + * + * @details + * The defined function's signature will match either + * patomic_opsig_void_noarg_t or patomic_opsig_explicit_void_noarg_t + * (depending on the value of 'vis_p'). + * + * @param atomic_type + * The type of the object on which the atomic operation is to be performed. + * Must not be a VLA or an array of unknown size. + * + * @param type + * The non-atomic counterpart of 'atomic_type'. This must have the same size + * as 'atomic_type' and must not have a stricter alignment. + * + * @param fn_name + * The name of the function to be defined. + * + * @param vis_p + * Either the macro 'SHOW_P' if the function should be defined as taking a + * memory order parameter (a.k.a. explicit), or the macro 'HIDE_P' if it + * should not (a.k.a. implicit). + * + * @param order + * The literal token 'order' if 'vis_p' is 'SHOW_P', otherwise the desired + * memory order to be used implicitly by the atomic operation. + * + * @param do_atomic_cmpxchg_weak_explicit + * A macro, M, callable as 'M(type, obj, exp, des, succ, fail, ok);' in block + * scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'obj' : an expression of type 'volatile atomic_type *' + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * - 'succ' : an expression of type 'int' whose value is a valid memory order + * - 'fail' : an expression of type 'int' whose value is a valid load memory + * order not stronger than 'succ' + * - 'ok' : the name of an identifier designating an object of type 'int' + * + * The expected behaviour of calling the macro M as above is: + * - the values of 'exp' and 'des' are read + * - in a single atomic operation, the value of the object pointed to by + * 'obj' is read and, if it compares equal to the value of 'exp', the + * value of 'des' is written to the object pointed to by 'obj' + * - the value read from 'obj' is stored in 'exp' + * - 'ok' is set to non-zero if the value of 'des' was written to the object + * pointed to by 'obj' (success), otherwise it is set to zero (failure) + * - the atomic operation uses a memory ordering at least as strong as 'succ' + * for a successful exchange, and a load memory ordering at least as strong + * as 'fail' for a failed exchange + * + * @param do_make_desired + * A macro, D, callable as 'D(type, exp, des);' in block scope. + * + * The arguments provided are: + * - 'type' : forwarded directly from the 'type' argument in this macro + * - 'exp' : the name of an identifier designating an object of type 'type' + * - 'des' : the name of an identifier designating an object of type 'type' + * + * The expected behaviour of calling the macro D as above is: + * - 'des' should be set to the value of 'exp' after the desired modify + * operation is applied + * - 'exp' should not be modified + */ +#define PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_VOID_NOARG( \ + atomic_type, type, fn_name, vis_p, order, \ + do_atomic_cmpxchg_weak_explicit, \ + do_make_desired \ +) \ + static void \ + fn_name( \ + volatile void *const obj \ + vis_p(_,const int order) \ + ) \ + { \ + /* static assertions */ \ + PATOMIC_STATIC_ASSERT( \ + sizeof_type_eq_atype, sizeof(type) == sizeof(atomic_type)); \ + \ + /* declarations */ \ + type exp = {0}; \ + type des; \ + int ok; \ + const int succ = (int) order; \ + const int fail = PATOMIC_CMPXCHG_FAIL_ORDER(succ); \ + \ + /* assertions */ \ + PATOMIC_WRAPPED_DO_ASSERT(obj != NULL); \ + PATOMIC_WRAPPED_DO_ASSERT_ALIGNED(obj, atomic_type); \ + PATOMIC_WRAPPED_DO_ASSERT(PATOMIC_IS_VALID_ORDER((int) order)); \ + \ + /* operation */ \ + do { \ + /* make the desired value from the expected value */ \ + do_make_desired( \ + type, \ + exp, \ + des \ + ); \ + \ + /* cmpxchg_weak */ \ + do_atomic_cmpxchg_weak_explicit( \ + type, \ + (volatile atomic_type *) obj, \ + exp, des, \ + succ, fail, \ + ok \ + ); \ + } \ + while (!ok); \ + } + + #endif /* PATOMIC_WRAPPED_CMPXCHG_H */ From 674e6a9bcdd14aeb4906b602896b7750027c0b0c Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 03:20:07 +0000 Subject: [PATCH 44/54] GHI #35 Add binary not to std impl --- src/impl/std/std.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 303dfb89b..c33332bfb 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -91,9 +91,9 @@ /* * BITWISE: * - bit_test (direct) - * - bit_test_compl (no) - * - bit_test_set (no) - * - bit_test_reset (no) + * - bit_test_compl (cmpxchg) + * - bit_test_set (cmpxchg) + * - bit_test_reset (cmpxchg) */ #define do_bit_test_explicit(type, obj, offset, order, res) \ do { \ @@ -197,7 +197,7 @@ * - (fetch_)or (direct) * - (fetch_)xor (direct) * - (fetch_)and (direct) - * - (fetch_)not (no) + * - (fetch_)not (cmpxchg) */ #define do_void_or_explicit(type, obj, arg, order) \ PATOMIC_IGNORE_UNUSED(atomic_fetch_or_explicit(obj, arg, order)) @@ -213,6 +213,9 @@ #define do_fetch_and_explicit(type, obj, arg, order, res) \ res = atomic_fetch_and_explicit(obj, arg, order) +#define do_make_desired_not(type, exp, des) \ + des = (type) ~exp + #define PATOMIC_DEFINE_BINARY_OPS_CREATE(type, name, vis_p, order, ops) \ PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ _Atomic(type), type, \ @@ -232,6 +235,12 @@ vis_p, order, \ do_void_and_explicit \ ) \ + PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_VOID_NOARG( \ + _Atomic(type), type, \ + patomic_opimpl_void_not_##name, \ + vis_p, order, \ + do_cmpxchg_weak, do_make_desired_not \ + ) \ PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ _Atomic(type), type, \ patomic_opimpl_fetch_or_##name, \ @@ -250,6 +259,12 @@ vis_p, order, \ do_fetch_and_explicit \ ) \ + PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_FETCH_NOARG( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_not_##name, \ + vis_p, order, \ + do_cmpxchg_weak, do_make_desired_not \ + ) \ static patomic_##ops##_binary_t \ patomic_ops_binary_create_##name(void) \ { \ @@ -257,11 +272,11 @@ pao.fp_or = patomic_opimpl_void_or_##name; \ pao.fp_xor = patomic_opimpl_void_xor_##name; \ pao.fp_and = patomic_opimpl_void_and_##name; \ - pao.fp_not = NULL; \ + pao.fp_not = patomic_opimpl_void_not_##name; \ pao.fp_fetch_or = patomic_opimpl_fetch_or_##name; \ pao.fp_fetch_xor = patomic_opimpl_fetch_xor_##name; \ pao.fp_fetch_and = patomic_opimpl_fetch_and_##name; \ - pao.fp_fetch_not = NULL; \ + pao.fp_fetch_not = patomic_opimpl_fetch_not_##name; \ return pao; \ } From 9f2856d22860220fd55c795efd281d87ec08eeb7 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 03:25:59 +0000 Subject: [PATCH 45/54] GHI #35 Add missing paren to assert --- src/include/patomic/stdlib/assert.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/patomic/stdlib/assert.h b/src/include/patomic/stdlib/assert.h index aeb1f8c26..929032894 100644 --- a/src/include/patomic/stdlib/assert.h +++ b/src/include/patomic/stdlib/assert.h @@ -57,7 +57,7 @@ __patomic_assert_fail( #if defined(NDEBUG) && !defined(NNDEBUG) #define patomic_assert_unreachable_(expr) (PATOMIC_IGNORE_UNUSED((expr || \ - (PATOMIC_UNREACHABLE(), 0))) + (PATOMIC_UNREACHABLE(), 0)))) #else #define patomic_assert_unreachable_(expr) patomic_assert_always(expr) #endif From 9d377e2f4c7d0c24383cac76d2c0be4294d73110 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 03:38:53 +0000 Subject: [PATCH 46/54] GHI #35 Add arithmetic neg to std impl --- src/impl/std/std.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index c33332bfb..69a67bcf9 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -287,7 +287,7 @@ * - (fetch_)sub (direct) * - (fetch_)inc (direct) * - (fetch_)dec (direct) - * - (fetch_)neg (no) + * - (fetch_)neg (cmpxchg) */ #define do_void_add_explicit(type, obj, arg, order) \ PATOMIC_IGNORE_UNUSED(atomic_fetch_add_explicit(obj, arg, order)) @@ -307,6 +307,9 @@ #define do_fetch_dec_explicit(type, obj, order, res) \ res = atomic_fetch_sub_explicit(obj, (type) 1, order) +#define do_make_desired_neg(type, exp, des) \ + des = (type) -exp + #define PATOMIC_DEFINE_ARITHMETIC_OPS_CREATE(type, name, vis_p, order, ops) \ PATOMIC_WRAPPED_DIRECT_DEFINE_OP_VOID( \ _Atomic(type), type, \ @@ -332,6 +335,12 @@ vis_p, order, \ do_void_dec_explicit \ ) \ + PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_VOID_NOARG( \ + _Atomic(type), type, \ + patomic_opimpl_void_neg_##name, \ + vis_p, order, \ + do_cmpxchg_weak, do_make_desired_neg \ + ) \ PATOMIC_WRAPPED_DIRECT_DEFINE_OP_FETCH( \ _Atomic(type), type, \ patomic_opimpl_fetch_add_##name, \ @@ -356,6 +365,12 @@ vis_p, order, \ do_fetch_dec_explicit \ ) \ + PATOMIC_WRAPPED_CMPXCHG_DEFINE_OP_FETCH_NOARG( \ + _Atomic(type), type, \ + patomic_opimpl_fetch_neg_##name, \ + vis_p, order, \ + do_cmpxchg_weak, do_make_desired_neg \ + ) \ static patomic_##ops##_arithmetic_t \ patomic_ops_arithmetic_create_##name(void) \ { \ @@ -364,12 +379,12 @@ pao.fp_sub = patomic_opimpl_void_sub_##name; \ pao.fp_inc = patomic_opimpl_void_inc_##name; \ pao.fp_dec = patomic_opimpl_void_dec_##name; \ - pao.fp_neg = NULL; \ + pao.fp_neg = patomic_opimpl_void_neg_##name; \ pao.fp_fetch_add = patomic_opimpl_fetch_add_##name; \ pao.fp_fetch_sub = patomic_opimpl_fetch_sub_##name; \ pao.fp_fetch_inc = patomic_opimpl_fetch_inc_##name; \ pao.fp_fetch_dec = patomic_opimpl_fetch_dec_##name; \ - pao.fp_fetch_neg = NULL; \ + pao.fp_fetch_neg = patomic_opimpl_fetch_neg_##name; \ return pao; \ } From 7374624c760fd8d8c9fdae839d464e547c84a32b Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 04:04:13 +0000 Subject: [PATCH 47/54] GHI #35 Add -Wno-unused-local-typedef and /wd4668 --- CMakePresets.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index e43a605f2..70b720666 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -94,7 +94,7 @@ "name": "_patomic-ci-flags-warning-clang", "hidden": true, "cacheVariables": { - "CMAKE_C_FLAGS_INIT": "-Weverything -Werror -Wpedantic -Wno-c++98-compat -Wno-covered-switch-default -Wno-padded -Wno-unused-function -Wno-atomic-alignment -Wno-poison-system-directories -Wno-reserved-identifier -Wno-documentation-unknown-command", + "CMAKE_C_FLAGS_INIT": "-Weverything -Werror -Wpedantic -Wno-c++98-compat -Wno-covered-switch-default -Wno-padded -Wno-unused-function -Wno-atomic-alignment -Wno-poison-system-directories -Wno-reserved-identifier -Wno-documentation-unknown-command -Wno-unused-local-typedef", "CMAKE_CXX_FLAGS_INIT": "-Wall -Wextra -Werror -Wpedantic -Wno-c++17-attribute-extensions" } }, @@ -102,7 +102,7 @@ "name": "_patomic-ci-flags-warning-gcc", "hidden": true, "cacheVariables": { - "CMAKE_C_FLAGS_INIT": "-Wall -Wextra -Werror -Wpedantic -Wshadow -Wcast-align -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wstrict-prototypes -Wmisleading-indentation -Wduplicated-branches -Wlogical-op -Wdeclaration-after-statement -Wno-unused-function", + "CMAKE_C_FLAGS_INIT": "-Wall -Wextra -Werror -Wpedantic -Wshadow -Wcast-align -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wstrict-prototypes -Wmisleading-indentation -Wduplicated-branches -Wlogical-op -Wdeclaration-after-statement -Wno-unused-function -Wno-unused-local-typedef", "CMAKE_CXX_FLAGS_INIT": "-Wall -Wextra -Werror -Wpedantic" } }, @@ -110,7 +110,7 @@ "name": "_patomic-ci-flags-warning-msvc", "hidden": true, "cacheVariables": { - "CMAKE_C_FLAGS_INIT": "/permissive- /volatile:iso /Wall /WX /wd4464 /wd4132 /wd4820 /wd4127 /wd5045 /wd4710 /wd4711 /wd4668", + "CMAKE_C_FLAGS_INIT": "/permissive- /volatile:iso /Wall /WX /wd4464 /wd4132 /wd4820 /wd4127 /wd5045 /wd4710 /wd4711 /wd4668 /wd4146", "CMAKE_CXX_FLAGS_INIT": "/permissive- /volatile:iso /W4 /WX" } }, From d562c574c5e2a0d8e3d9438d64f4057b2eac8eca Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 04:12:11 +0000 Subject: [PATCH 48/54] GHI #35 Add -Wno-unused-local-typedef to ansi flags --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 70b720666..394919fff 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -56,7 +56,7 @@ "name": "_patomic-ci-flags-ansi-gnu", "hidden": true, "cacheVariables": { - "CMAKE_C_FLAGS": "-Wall -Wextra -Werror -Wpedantic -Wno-unused-function -Wno-atomic-alignment", + "CMAKE_C_FLAGS": "-Wall -Wextra -Werror -Wpedantic -Wno-unused-function -Wno-atomic-alignment -Wno-unused-local-typedef", "CMAKE_C_STANDARD": "90" } }, From f4352bfb97fa4fdc3222bed06a5eb1cd1b1525c8 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 04:38:13 +0000 Subject: [PATCH 49/54] GHI #35 Improve COMPILER_HAS_ATOMIC check --- cmake/check/HasKeyword.cmake | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cmake/check/HasKeyword.cmake b/cmake/check/HasKeyword.cmake index 153ba9631..b03773d08 100644 --- a/cmake/check/HasKeyword.cmake +++ b/cmake/check/HasKeyword.cmake @@ -49,7 +49,25 @@ check_c_source_compiles_or_zero( # '_Atomic' is available as a keyword check_c_source_compiles_or_zero( SOURCE - "int main(void) { _Atomic(int) x = 0; return x; }" + "#include \n\ + int main(void) { \n\ + const _Atomic(unsigned char) a1 = {0}; \n\ + const _Atomic(unsigned short) a2 = {0}; \n\ + const _Atomic(unsigned int) a3 = {0}; \n\ + const _Atomic(unsigned long) a4 = {0}; \n\ + const volatile *const _Atomic(unsigned char) p1 = &a1; \n\ + const volatile *const _Atomic(unsigned short) p1 = &a1; \n\ + const volatile *const _Atomic(unsigned int) p1 = &a1; \n\ + const volatile *const _Atomic(unsigned long) p1 = &a1; \n\ + unsigned long sum = 0; \n\ + sum += (unsigned long) atomic_load(p1); \n\ + sum += (unsigned long) atomic_load(p2); \n\ + sum += (unsigned long) atomic_load(p3); \n\ + sum += (unsigned long) atomic_load(p4); \n\ + return (int) sum; \n\ + }" OUTPUT_VARIABLE COMPILER_HAS_ATOMIC + WILL_FAIL_IF_ANY_NOT + ${COMPILER_HAS_STDATOMIC_H} ) From 2a5301a1ef89cdeaed58c4dfac503e10b8f40b09 Mon Sep 17 00:00:00 2001 From: doodspav Date: Thu, 31 Oct 2024 05:22:43 +0000 Subject: [PATCH 50/54] GHI #35 Improve COMPILER_HAS_ATOMIC check further --- cmake/check/HasKeyword.cmake | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/check/HasKeyword.cmake b/cmake/check/HasKeyword.cmake index b03773d08..9c9621cee 100644 --- a/cmake/check/HasKeyword.cmake +++ b/cmake/check/HasKeyword.cmake @@ -51,14 +51,14 @@ check_c_source_compiles_or_zero( SOURCE "#include \n\ int main(void) { \n\ - const _Atomic(unsigned char) a1 = {0}; \n\ - const _Atomic(unsigned short) a2 = {0}; \n\ - const _Atomic(unsigned int) a3 = {0}; \n\ - const _Atomic(unsigned long) a4 = {0}; \n\ - const volatile *const _Atomic(unsigned char) p1 = &a1; \n\ - const volatile *const _Atomic(unsigned short) p1 = &a1; \n\ - const volatile *const _Atomic(unsigned int) p1 = &a1; \n\ - const volatile *const _Atomic(unsigned long) p1 = &a1; \n\ + static const _Atomic(unsigned char) a1; \n\ + static const _Atomic(unsigned short) a2; \n\ + static const _Atomic(unsigned int) a3; \n\ + static const _Atomic(unsigned long) a4; \n\ + const volatile _Atomic(unsigned char) *const p1 = &a1; \n\ + const volatile _Atomic(unsigned short) *const p2 = &a2; \n\ + const volatile _Atomic(unsigned int) *const p3 = &a3; \n\ + const volatile _Atomic(unsigned long) *const p4 = &a4; \n\ unsigned long sum = 0; \n\ sum += (unsigned long) atomic_load(p1); \n\ sum += (unsigned long) atomic_load(p2); \n\ From d317f8fa9daac785394ba7ea586ab4545913a6ff Mon Sep 17 00:00:00 2001 From: doodspav Date: Fri, 1 Nov 2024 03:27:03 +0000 Subject: [PATCH 51/54] GHI #35 Remove align from transaction (unnecessary) --- include/patomic/api/core.h | 3 --- include/patomic/patomic.h | 4 ---- src/impl/null/null.c | 4 ---- src/impl/std/std.c | 4 ---- 4 files changed, 15 deletions(-) diff --git a/include/patomic/api/core.h b/include/patomic/api/core.h index be282f199..9b79c3237 100644 --- a/include/patomic/api/core.h +++ b/include/patomic/api/core.h @@ -59,9 +59,6 @@ typedef struct { * transaction, and non-atomic transaction specific operations. */ patomic_ops_transaction_t ops; - /** @brief Alignment requirements for atomic operations. */ - patomic_align_t align; - /** @brief Recommended time and space bounds for atomic operations. */ patomic_transaction_recommended_t recommended; diff --git a/include/patomic/patomic.h b/include/patomic/patomic.h index 97d20b856..6111d6aae 100644 --- a/include/patomic/patomic.h +++ b/include/patomic/patomic.h @@ -130,10 +130,6 @@ patomic_create_explicit( * The implementation with the most efficient kind that supports at least a * single operation. If no such implementations exist, the NULL implementation * is returned. - * - * @note - * The alignment requirements returned by this function will always be valid - * even if no operations are supported. */ PATOMIC_EXPORT patomic_transaction_t patomic_create_transaction( diff --git a/src/impl/null/null.c b/src/impl/null/null.c index 7f553a8e2..3cdf3a022 100644 --- a/src/impl/null/null.c +++ b/src/impl/null/null.c @@ -60,10 +60,6 @@ patomic_impl_create_transaction_null( /* ignore parameters */ PATOMIC_IGNORE_UNUSED(options); - /* set a valid minimal alignment */ - impl.align.recommended = 1; - impl.align.minimum = 1; - /* return */ return impl; } diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 69a67bcf9..a80cbd82b 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -761,10 +761,6 @@ patomic_impl_create_transaction_std( /* ignore parameters */ PATOMIC_IGNORE_UNUSED(options); - /* set a valid minimal alignment */ - impl.align.recommended = 1; - impl.align.minimum = 1; - /* return */ return impl; } From 03bc69fa66907f60517c8eacab33ee6c47d3ea1c Mon Sep 17 00:00:00 2001 From: doodspav Date: Mon, 11 Nov 2024 20:19:38 +0000 Subject: [PATCH 52/54] GHI #35 Fix defines if stdatomic is supported but nothing is lock free --- src/impl/std/std.c | 103 ++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 39 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index a80cbd82b..418dd9406 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -524,9 +524,9 @@ #endif -#define PATOMIC_SET_RET(type, name, byte_width, order, ops) \ - ((byte_width == sizeof(type)) && \ - (byte_width == sizeof(_Atomic(type)))) \ +#define PATOMIC_RET_OPS(type, name, byte_width, order, ops) \ + if ((byte_width == sizeof(type)) && \ + (byte_width == sizeof(_Atomic(type)))) \ { \ _Atomic(type) obj; \ if (atomic_is_lock_free(&obj)) \ @@ -552,27 +552,37 @@ default: \ patomic_assert_always("invalid memory order" && 0); \ } \ + return ops; \ } \ PATOMIC_IGNORE_UNUSED(obj); \ } -#define PATOMIC_SET_RET_EXPLICIT(type, name, byte_width, ops) \ - ((byte_width == sizeof(type)) && \ - (byte_width == sizeof(_Atomic(type)))) \ +#define PATOMIC_RET_OPS_EXPLICIT(type, name, byte_width, ops) \ + if ((byte_width == sizeof(type)) && \ + (byte_width == sizeof(_Atomic(type)))) \ { \ _Atomic(type) obj; \ if (atomic_is_lock_free(&obj)) \ { \ ops = patomic_ops_create_##name##_explicit(); \ + return ops; \ } \ PATOMIC_IGNORE_UNUSED(obj); \ } -#define PATOMIC_SET_ALIGN(type, byte_width, member) \ - ((byte_width == sizeof(type)) && \ - (byte_width == sizeof(_Atomic(type)))) \ - { \ - member = patomic_alignof_type(_Atomic(type)); \ +#define PATOMIC_RET_ALIGN(type, byte_width) \ + if ((byte_width == sizeof(type)) && \ + (byte_width == sizeof(_Atomic(type)))) \ + { \ + _Atomic(type) obj; \ + if (atomic_is_lock_free(&obj)) \ + { \ + align.recommended = patomic_alignof_type(_Atomic(type)); \ + align.minimum = align.recommended; \ + align.size_within = 0; \ + return align; \ + } \ + PATOMIC_IGNORE_UNUSED(obj); \ } @@ -590,15 +600,22 @@ patomic_create_ops( /* go from largest to smallest in case some platform has two types with the * same width but one has a larger range */ #if HAS_LLONG_IMPL - if PATOMIC_SET_RET(patomic_llong_unsigned_t, llong, byte_width, order, ops) - else + PATOMIC_RET_OPS(patomic_llong_unsigned_t, llong, byte_width, order, ops) +#endif +#if ATOMIC_LONG_LOCK_FREE + PATOMIC_RET_OPS(unsigned long, long, byte_width, order, ops) +#endif +#if ATOMIC_INT_LOCK_FREE + PATOMIC_RET_OPS(unsigned int, int, byte_width, order, ops) +#endif +#if ATOMIC_SHORT_LOCK_FREE + PATOMIC_RET_OPS(unsigned short, short, byte_width, order, ops) +#endif +#if ATOMIC_CHAR_LOCK_FREE + PATOMIC_RET_OPS(unsigned char, char, byte_width, order, ops) #endif - if PATOMIC_SET_RET(unsigned long, long, byte_width, order, ops) - else if PATOMIC_SET_RET(unsigned int, int, byte_width, order, ops) - else if PATOMIC_SET_RET(unsigned short, short, byte_width, order, ops) - else if PATOMIC_SET_RET(unsigned char, char, byte_width, order, ops) - /* return */ + /* fallback, width not supported */ return ops; } @@ -614,15 +631,22 @@ patomic_create_ops_explicit( /* go from largest to smallest in case some platform has two types with the * same width but one has a larger range */ #if HAS_LLONG_IMPL - if PATOMIC_SET_RET_EXPLICIT(patomic_llong_unsigned_t, llong, byte_width, ops) - else + PATOMIC_RET_OPS_EXPLICIT(patomic_llong_unsigned_t, llong, byte_width, ops) +#endif +#if ATOMIC_LONG_LOCK_FREE + PATOMIC_RET_OPS_EXPLICIT(unsigned long, long, byte_width, ops) +#endif +#if ATOMIC_INT_LOCK_FREE + PATOMIC_RET_OPS_EXPLICIT(unsigned int, int, byte_width, ops) +#endif +#if ATOMIC_SHORT_LOCK_FREE + PATOMIC_RET_OPS_EXPLICIT(unsigned short, short, byte_width, ops) +#endif +#if ATOMIC_CHAR_LOCK_FREE + PATOMIC_RET_OPS_EXPLICIT(unsigned char, char, byte_width, ops) #endif - if PATOMIC_SET_RET_EXPLICIT(unsigned long, long, byte_width, ops) - else if PATOMIC_SET_RET_EXPLICIT(unsigned int, int, byte_width, ops) - else if PATOMIC_SET_RET_EXPLICIT(unsigned short, short, byte_width, ops) - else if PATOMIC_SET_RET_EXPLICIT(unsigned char, char, byte_width, ops) - /* return */ + /* fallback, width not supported */ return ops; } @@ -638,24 +662,25 @@ patomic_create_align( /* go from largest to smallest in case some platform has two types with the * same width but one has a larger range */ #if HAS_LLONG_IMPL - if PATOMIC_SET_ALIGN(patomic_llong_unsigned_t, byte_width, align.recommended) - else + PATOMIC_RET_ALIGN(patomic_llong_unsigned_t, byte_width) +#endif +#if ATOMIC_LONG_LOCK_FREE + PATOMIC_RET_ALIGN(unsigned long, byte_width) +#endif +#if ATOMIC_INT_LOCK_FREE + PATOMIC_RET_ALIGN(unsigned int, byte_width) +#endif +#if ATOMIC_SHORT_LOCK_FREE + PATOMIC_RET_ALIGN(unsigned short, byte_width) +#endif +#if ATOMIC_CHAR_LOCK_FREE + PATOMIC_RET_ALIGN(unsigned char, byte_width) #endif - if PATOMIC_SET_ALIGN(unsigned long, byte_width, align.recommended) - else if PATOMIC_SET_ALIGN(unsigned int, byte_width, align.recommended) - else if PATOMIC_SET_ALIGN(unsigned short, byte_width, align.recommended) - else if PATOMIC_SET_ALIGN(unsigned char, byte_width, align.recommended) - else - { - /* minimum valid alignment */ - align.recommended = 1; - } - /* set remaining members */ + /* fallback, width not supported */ + align.recommended = 1; align.minimum = align.recommended; align.size_within = 0; - - /* return */ return align; } From f84fa77305f7486790a8113dc91a267a03b78cef Mon Sep 17 00:00:00 2001 From: doodspav Date: Mon, 11 Nov 2024 20:59:42 +0000 Subject: [PATCH 53/54] GHI #35 Update comment [[skip ci]] --- src/impl/std/std.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/impl/std/std.c b/src/impl/std/std.c index 418dd9406..6478a6c8e 100644 --- a/src/impl/std/std.c +++ b/src/impl/std/std.c @@ -596,7 +596,7 @@ patomic_create_ops( patomic_ops_t ops = {0}; patomic_assert_always(patomic_is_valid_order((int) order)); - /* set members */ + /* set and return implicit atomic ops */ /* go from largest to smallest in case some platform has two types with the * same width but one has a larger range */ #if HAS_LLONG_IMPL @@ -627,7 +627,7 @@ patomic_create_ops_explicit( /* setup */ patomic_ops_explicit_t ops = {0}; - /* set members */ + /* set and return explicit atomic ops */ /* go from largest to smallest in case some platform has two types with the * same width but one has a larger range */ #if HAS_LLONG_IMPL @@ -658,7 +658,7 @@ patomic_create_align( /* setup */ patomic_align_t align = {0}; - /* set recommended */ + /* set and return atomic alignments */ /* go from largest to smallest in case some platform has two types with the * same width but one has a larger range */ #if HAS_LLONG_IMPL From bc399865dc3579f0758667134e8b470642489827 Mon Sep 17 00:00:00 2001 From: doodspav Date: Wed, 13 Nov 2024 21:22:28 +0000 Subject: [PATCH 54/54] GHI #35 Disable CI jobs to build, test, and cover code --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c71b95461..57c077994 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,6 +9,7 @@ on: jobs: test-native: + if: false strategy: matrix: # verbose labels make things easier to read in GitHub Actions @@ -55,6 +56,7 @@ jobs: architecture: ${{ matrix.architecture }} test-qemu: + if: false strategy: matrix: # architecture gets converted to triple @@ -133,6 +135,7 @@ jobs: skip_llvm: ${{ matrix.skip_llvm == true }} publish-results: + if: false runs-on: ubuntu-latest needs: - test-native