/** * A D implementation of the C stdatomic.h header. * * $(NOTE If it compiles it should produce similar assembly to the system C toolchain * and should not introduce when optimizing unnecessary behaviors, * if you do not care about this guarantee use the _impl suffix.) * * $(NOTE The D shared type qualifier is the closest to the _Atomic type qualifier from C. It may be changed from shared in the future.) * * $(NOTE Fail memory order is currently ignored due to limitations with internal implementation of atomics.) * * Copyright: Copyright Richard (Rikki) Andrew Cattermole 2023. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Richard (Rikki) Andrew cattermole * Source: $(DRUNTIMESRC core/stdc/stdatomic.d) */module core.stdc.stdatomic;import core.atomic : MemoryOrder;import core.internal.atomic;import core.stdc.config;import core.stdc.stddef;import core.stdc.stdint; @safe nothrow @nogc: ///enum memory_order{ /// No ordering provided memory_order_relaxed = MemoryOrder.raw, /// As per cppreference.com circa 2015 no compiler supports consume memory order and in practice it devolves to acquire. memory_order_consume = MemoryOrder.acq, /// Prevent reordering before operation memory_order_acquire = MemoryOrder.acq, /// Prevent reordering after operation memory_order_release = MemoryOrder.rel, /// Prevent reordering before and after operation memory_order_acq_rel = MemoryOrder.acq_rel, /// Prevent reordering before for read operations and after for writes. memory_order_seq_cst = MemoryOrder.seq} ///enum{ /// __STDC_VERSION_STDATOMIC_H__ = 202311, /// ATOMIC_BOOL_LOCK_FREE = IsAtomicLockFree!bool ? 2 : 0, /// ATOMIC_CHAR_LOCK_FREE = IsAtomicLockFree!char ? 2 : 0, /// ATOMIC_CHAR16_T_LOCK_FREE = IsAtomicLockFree!wchar ? 2 : 0, /// ATOMIC_CHAR32_T_LOCK_FREE = IsAtomicLockFree!dchar ? 2 : 0, /// ATOMIC_WCHAR_T_LOCK_FREE = IsAtomicLockFree!wchar_t ? 2 : 0, /// ATOMIC_SHORT_LOCK_FREE = IsAtomicLockFree!short ? 2 : 0, /// ATOMIC_INT_LOCK_FREE = IsAtomicLockFree!int ? 2 : 0, /// ATOMIC_LONG_LOCK_FREE = IsAtomicLockFree!c_long ? 2 : 0, /// ATOMIC_LLONG_LOCK_FREE = IsAtomicLockFree!ulong ? 2 : 0, /// ATOMIC_POINTER_LOCK_FREE = IsAtomicLockFree!(void*) ? 2 : 0, /// ATOMIC_CHAR8_T_LOCK_FREE = ATOMIC_CHAR_LOCK_FREE,} version (DigitalMars){ alias atomic_signal_fence = atomic_signal_fence_impl; /// // these all use inline assembly, so will unlikely produce the codegen a user will expect version(none) { alias atomic_flag_clear = atomic_flag_clear_impl; /// alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; /// alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; /// alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; /// alias atomic_thread_fence = atomic_thread_fence_impl; /// alias atomic_store = atomic_store_impl; /// alias atomic_store_explicit = atomic_store_explicit_impl; /// alias atomic_load = atomic_load_impl; /// alias atomic_load_explicit = atomic_load_explicit_impl; /// alias atomic_exchange = atomic_exchange_impl; /// alias atomic_exchange_explicit = atomic_exchange_explicit_impl; /// alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; /// alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; /// alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; /// alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; /// alias atomic_fetch_add = atomic_fetch_add_impl; /// alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; /// alias atomic_fetch_sub = atomic_fetch_sub_impl; /// alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; /// alias atomic_fetch_or = atomic_fetch_or_impl; /// alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; /// alias atomic_fetch_xor = atomic_fetch_xor_impl; /// alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; /// alias atomic_fetch_and = atomic_fetch_and_impl; /// alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; /// }}else{ alias atomic_flag_clear = atomic_flag_clear_impl; /// alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; /// alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; /// alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; /// alias atomic_signal_fence = atomic_signal_fence_impl; /// alias atomic_thread_fence = atomic_thread_fence_impl; /// alias atomic_store = atomic_store_impl; /// alias atomic_store_explicit = atomic_store_explicit_impl; /// alias atomic_load = atomic_load_impl; /// alias atomic_load_explicit = atomic_load_explicit_impl; /// alias atomic_exchange = atomic_exchange_impl; /// alias atomic_exchange_explicit = atomic_exchange_explicit_impl; /// alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; /// alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; /// alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; /// alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; /// alias atomic_fetch_add = atomic_fetch_add_impl; /// alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; /// alias atomic_fetch_sub = atomic_fetch_sub_impl; /// alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; /// alias atomic_fetch_or = atomic_fetch_or_impl; /// alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; /// alias atomic_fetch_xor = atomic_fetch_xor_impl; /// alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; /// alias atomic_fetch_and = atomic_fetch_and_impl; /// alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; ///} ///pragma(inline, true)bool atomic_is_lock_free(A)(const shared(A)* obj){ return IsAtomicLockFree!A;} /// Guaranteed to be a atomic boolean typestruct atomic_flag{ private bool b;} ///enum ATOMIC_FLAG_INIT = atomic_flag.init; ///pragma(inline, true)void atomic_flag_clear_impl()(atomic_flag* obj){ assert(obj !is null); atomicStore(&obj.b, false);} ///pragma(inline, true)void atomic_flag_clear_explicit_impl()(atomic_flag* obj, memory_order order){ assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? atomicStore!(memory_order.memory_order_relaxed)(&obj.b, false) : order == memory_order.memory_order_acquire || order == memory_order.memory_order_acq_rel ? // Ideally this would error at compile time but alas it is not an intrinsic. // Note: this is not a valid memory order for this operation. atomicStore!(memory_order.memory_order_seq_cst)(&obj.b, false) : order == memory_order.memory_order_release ? atomicStore!(memory_order.memory_order_release)(&obj.b, false) : order == memory_order.memory_order_seq_cst ? atomicStore(&obj.b, false) : cast(void) assert(0);} ///pragma(inline, true)bool atomic_flag_test_and_set_impl()(atomic_flag* obj){ assert(obj !is null); return atomicExchange(&obj.b, true);} ///@trusted unittest{ atomic_flag flag; assert(!atomic_flag_test_and_set_impl(&flag)); atomic_flag_clear_impl(&flag);} ///pragma(inline, true)bool atomic_flag_test_and_set_explicit_impl()(atomic_flag* obj, memory_order order){ assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner return order == memory_order.memory_order_relaxed ? atomicExchange!(memory_order.memory_order_relaxed)(&obj.b, true) : order == memory_order.memory_order_acquire ? // Ideally this would error at compile time but alas it is not an intrinsic. // Note: this is not a valid memory order for this operation. atomicExchange!(memory_order.memory_order_seq_cst)(&obj.b, true) : order == memory_order.memory_order_release ? atomicExchange!(memory_order.memory_order_release)(&obj.b, true) : order == memory_order.memory_order_acq_rel ? atomicExchange!(memory_order.memory_order_acq_rel)(&obj.b, true) : order == memory_order.memory_order_seq_cst ? atomicExchange(&obj.b, true) : assert(0);} ///@trusted unittest{ atomic_flag flag; assert(!atomic_flag_test_and_set_explicit_impl(&flag, memory_order.memory_order_seq_cst)); atomic_flag_clear_explicit_impl(&flag, memory_order.memory_order_seq_cst);} /** * Initializes an atomic variable, the destination should not have any expression associated with it prior to this call. * * We use an out parameter instead of a pointer for destination in an attempt to communicate to the compiler that it initializers. */pragma(inline, true)void atomic_init(A, C)(out shared(A) obj, C desired) @trusted{ // C11 atomic_init is a low-level initialization primitive for atomic storage // before it is published for concurrent access, so it must be able to write // the backing object without demonstrating ordinary shared access. *cast(A*) &obj = cast(A) desired;} ///unittest{ shared int val; atomic_init(val, 2); shared float valF; atomic_init(valF, 3.2);} /// No-op function, doesn't apply to Dpragma(inline, true)A kill_dependency(A)(A y) @trusted{ return y;} /// Don't allow reordering, does not emit any instructions.pragma(inline, true)void atomic_signal_fence_impl()(memory_order order){ // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? // This is a no-op operation for relaxed memory orders. cast(void)0 : order == memory_order.memory_order_acquire ? atomicSignalFence!(memory_order.memory_order_acquire) : order == memory_order.memory_order_release ? atomicSignalFence!(memory_order.memory_order_release) : order == memory_order.memory_order_acq_rel ? atomicSignalFence!(memory_order.memory_order_acq_rel) : order == memory_order.memory_order_seq_cst ? atomicSignalFence!(memory_order.memory_order_seq_cst) : cast(void) assert(0);} ///unittest{ atomic_signal_fence_impl(memory_order.memory_order_seq_cst);} /// Don't allow reordering, and emit a fence instruction.pragma(inline, true)void atomic_thread_fence_impl()(memory_order order){ // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? // This is a no-op operation for relaxed memory orders. cast(void)0 : order == memory_order.memory_order_acquire ? atomicFence!(memory_order.memory_order_acquire) : order == memory_order.memory_order_release ? atomicFence!(memory_order.memory_order_release) : order == memory_order.memory_order_acq_rel ? atomicFence!(memory_order.memory_order_acq_rel) : order == memory_order.memory_order_seq_cst ? atomicFence!(memory_order.memory_order_seq_cst) : cast(void) assert(0);} ///unittest{ atomic_thread_fence_impl(memory_order.memory_order_seq_cst);} ///alias atomic_bool = shared(bool);///alias atomic_char = shared(char);///alias atomic_schar = shared(byte);///alias atomic_uchar = shared(ubyte);///alias atomic_short = shared(short);///alias atomic_ushort = shared(ushort);///alias atomic_int = shared(int);///alias atomic_uint = shared(uint);///alias atomic_long = shared(c_long);///alias atomic_ulong = shared(c_ulong);///alias atomic_llong = shared(long);///alias atomic_ullong = shared(ulong);///alias atomic_char8_t = shared(char);///alias atomic_char16_t = shared(wchar);///alias atomic_char32_t = shared(dchar);///alias atomic_wchar_t = shared(wchar_t); ///alias atomic_int_least8_t = shared(int_least8_t);///alias atomic_uint_least8_t = shared(uint_least8_t);///alias atomic_int_least16_t = shared(int_least16_t);///alias atomic_uint_least16_t = shared(uint_least16_t);///alias atomic_int_least32_t = shared(int_least32_t);///alias atomic_uint_least32_t = shared(uint_least32_t);///alias atomic_int_least64_t = shared(int_least64_t);///alias atomic_uint_least64_t = shared(uint_least64_t);///alias atomic_int_fast8_t = shared(int_fast8_t);///alias atomic_uint_fast8_t = shared(uint_fast8_t);///alias atomic_int_fast16_t = shared(int_fast16_t);///alias atomic_uint_fast16_t = shared(uint_fast16_t);///alias atomic_int_fast32_t = shared(int_fast32_t);///alias atomic_uint_fast32_t = shared(uint_fast32_t);///alias atomic_int_fast64_t = shared(int_fast64_t);///alias atomic_uint_fast64_t = shared(uint_fast64_t);///alias atomic_intptr_t = shared(intptr_t);///alias atomic_uintptr_t = shared(uintptr_t);///alias atomic_size_t = shared(size_t);///alias atomic_ptrdiff_t = shared(ptrdiff_t);///alias atomic_intmax_t = shared(intmax_t);///alias atomic_uintmax_t = shared(uintmax_t); ///pragma(inline, true)void atomic_store_impl(A, C)(shared(A)* obj, C desired) @trusted{ assert(obj !is null); atomicStore(cast(A*)obj, cast(A)desired);} ///@trusted unittest{ shared(int) obj; atomic_store_impl(&obj, 3); shared(float) objF; atomic_store_impl(&objF, 3.21);} ///pragma(inline, true)void atomic_store_explicit_impl(A, C)(shared(A)* obj, C desired, memory_order order) @trusted{ assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? atomicStore!(memory_order.memory_order_relaxed)(cast(A*)obj, cast(A)desired) : order == memory_order.memory_order_acquire || order == memory_order.memory_order_acq_rel ? // Ideally this would error at compile time but alas it is not an intrinsic. // Note: this is not a valid memory order for this operation. atomicStore!(memory_order.memory_order_release)(cast(A*)obj, cast(A)desired) : order == memory_order.memory_order_release ? atomicStore!(memory_order.memory_order_release)(cast(A*)obj, cast(A)desired) : order == memory_order.memory_order_seq_cst ? atomicStore!(memory_order.memory_order_seq_cst)(cast(A*)obj, cast(A)desired) : cast(void) assert(0);} ///@trusted unittest{ shared(int) obj; atomic_store_explicit_impl(&obj, 3, memory_order.memory_order_seq_cst); shared(float) objF; atomic_store_explicit_impl(&objF, 3.21, memory_order.memory_order_seq_cst);} ///pragma(inline, true)A atomic_load_impl(A)(const shared(A)* obj) @trusted{ assert(obj !is null); return atomicLoad(cast(A*)obj);} ///@trusted unittest{ shared(int) obj = 3; assert(atomic_load_impl(&obj) == 3); shared(float) objF = 3.5; assert(atomic_load_impl(&objF) > 3); static struct S2 { size_t[2] values; } align(S2.sizeof) shared(S2) objS2 = {[1, 2]}; assert(atomic_load_impl(&objS2).values == [1, 2]);} ///pragma(inline, true)A atomic_load_explicit_impl(A)(const shared(A)* obj, memory_order order) @trusted{ assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner return order == memory_order.memory_order_relaxed ? atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj) : order == memory_order.memory_order_acquire ? atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj) : order == memory_order.memory_order_release ||Lines 1–500 of 986. Load more
/** * A D implementation of the C stdatomic.h header. * * $(NOTE If it compiles it should produce similar assembly to the system C toolchain * and should not introduce when optimizing unnecessary behaviors, * if you do not care about this guarantee use the _impl suffix.) * * $(NOTE The D shared type qualifier is the closest to the _Atomic type qualifier from C. It may be changed from shared in the future.) * * $(NOTE Fail memory order is currently ignored due to limitations with internal implementation of atomics.) * * Copyright: Copyright Richard (Rikki) Andrew Cattermole 2023. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Richard (Rikki) Andrew cattermole * Source: $(DRUNTIMESRC core/stdc/stdatomic.d) */ module core.stdc.stdatomic; import core.atomic : MemoryOrder; import core.internal.atomic; import core.stdc.config; import core.stdc.stddef; import core.stdc.stdint; @safe nothrow @nogc: /// enum memory_order { /// No ordering provided memory_order_relaxed = MemoryOrder.raw, /// As per cppreference.com circa 2015 no compiler supports consume memory order and in practice it devolves to acquire. memory_order_consume = MemoryOrder.acq, /// Prevent reordering before operation memory_order_acquire = MemoryOrder.acq, /// Prevent reordering after operation memory_order_release = MemoryOrder.rel, /// Prevent reordering before and after operation memory_order_acq_rel = MemoryOrder.acq_rel, /// Prevent reordering before for read operations and after for writes. memory_order_seq_cst = MemoryOrder.seq } /// enum { /// __STDC_VERSION_STDATOMIC_H__ = 202311, /// ATOMIC_BOOL_LOCK_FREE = IsAtomicLockFree!bool ? 2 : 0, /// ATOMIC_CHAR_LOCK_FREE = IsAtomicLockFree!char ? 2 : 0, /// ATOMIC_CHAR16_T_LOCK_FREE = IsAtomicLockFree!wchar ? 2 : 0, /// ATOMIC_CHAR32_T_LOCK_FREE = IsAtomicLockFree!dchar ? 2 : 0, /// ATOMIC_WCHAR_T_LOCK_FREE = IsAtomicLockFree!wchar_t ? 2 : 0, /// ATOMIC_SHORT_LOCK_FREE = IsAtomicLockFree!short ? 2 : 0, /// ATOMIC_INT_LOCK_FREE = IsAtomicLockFree!int ? 2 : 0, /// ATOMIC_LONG_LOCK_FREE = IsAtomicLockFree!c_long ? 2 : 0, /// ATOMIC_LLONG_LOCK_FREE = IsAtomicLockFree!ulong ? 2 : 0, /// ATOMIC_POINTER_LOCK_FREE = IsAtomicLockFree!(void*) ? 2 : 0, /// ATOMIC_CHAR8_T_LOCK_FREE = ATOMIC_CHAR_LOCK_FREE, } version (DigitalMars) { alias atomic_signal_fence = atomic_signal_fence_impl; /// // these all use inline assembly, so will unlikely produce the codegen a user will expect version(none) { alias atomic_flag_clear = atomic_flag_clear_impl; /// alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; /// alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; /// alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; /// alias atomic_thread_fence = atomic_thread_fence_impl; /// alias atomic_store = atomic_store_impl; /// alias atomic_store_explicit = atomic_store_explicit_impl; /// alias atomic_load = atomic_load_impl; /// alias atomic_load_explicit = atomic_load_explicit_impl; /// alias atomic_exchange = atomic_exchange_impl; /// alias atomic_exchange_explicit = atomic_exchange_explicit_impl; /// alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; /// alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; /// alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; /// alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; /// alias atomic_fetch_add = atomic_fetch_add_impl; /// alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; /// alias atomic_fetch_sub = atomic_fetch_sub_impl; /// alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; /// alias atomic_fetch_or = atomic_fetch_or_impl; /// alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; /// alias atomic_fetch_xor = atomic_fetch_xor_impl; /// alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; /// alias atomic_fetch_and = atomic_fetch_and_impl; /// alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; /// } } else { alias atomic_flag_clear = atomic_flag_clear_impl; /// alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; /// alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; /// alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; /// alias atomic_signal_fence = atomic_signal_fence_impl; /// alias atomic_thread_fence = atomic_thread_fence_impl; /// alias atomic_store = atomic_store_impl; /// alias atomic_store_explicit = atomic_store_explicit_impl; /// alias atomic_load = atomic_load_impl; /// alias atomic_load_explicit = atomic_load_explicit_impl; /// alias atomic_exchange = atomic_exchange_impl; /// alias atomic_exchange_explicit = atomic_exchange_explicit_impl; /// alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; /// alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; /// alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; /// alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; /// alias atomic_fetch_add = atomic_fetch_add_impl; /// alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; /// alias atomic_fetch_sub = atomic_fetch_sub_impl; /// alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; /// alias atomic_fetch_or = atomic_fetch_or_impl; /// alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; /// alias atomic_fetch_xor = atomic_fetch_xor_impl; /// alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; /// alias atomic_fetch_and = atomic_fetch_and_impl; /// alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; /// } /// pragma(inline, true) bool atomic_is_lock_free(A)(const shared(A)* obj) { return IsAtomicLockFree!A; } /// Guaranteed to be a atomic boolean type struct atomic_flag { private bool b; } /// enum ATOMIC_FLAG_INIT = atomic_flag.init; /// pragma(inline, true) void atomic_flag_clear_impl()(atomic_flag* obj) { assert(obj !is null); atomicStore(&obj.b, false); } /// pragma(inline, true) void atomic_flag_clear_explicit_impl()(atomic_flag* obj, memory_order order) { assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? atomicStore!(memory_order.memory_order_relaxed)(&obj.b, false) : order == memory_order.memory_order_acquire || order == memory_order.memory_order_acq_rel ? // Ideally this would error at compile time but alas it is not an intrinsic. // Note: this is not a valid memory order for this operation. atomicStore!(memory_order.memory_order_seq_cst)(&obj.b, false) : order == memory_order.memory_order_release ? atomicStore!(memory_order.memory_order_release)(&obj.b, false) : order == memory_order.memory_order_seq_cst ? atomicStore(&obj.b, false) : cast(void) assert(0); } /// pragma(inline, true) bool atomic_flag_test_and_set_impl()(atomic_flag* obj) { assert(obj !is null); return atomicExchange(&obj.b, true); } /// @trusted unittest { atomic_flag flag; assert(!atomic_flag_test_and_set_impl(&flag)); atomic_flag_clear_impl(&flag); } /// pragma(inline, true) bool atomic_flag_test_and_set_explicit_impl()(atomic_flag* obj, memory_order order) { assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner return order == memory_order.memory_order_relaxed ? atomicExchange!(memory_order.memory_order_relaxed)(&obj.b, true) : order == memory_order.memory_order_acquire ? // Ideally this would error at compile time but alas it is not an intrinsic. // Note: this is not a valid memory order for this operation. atomicExchange!(memory_order.memory_order_seq_cst)(&obj.b, true) : order == memory_order.memory_order_release ? atomicExchange!(memory_order.memory_order_release)(&obj.b, true) : order == memory_order.memory_order_acq_rel ? atomicExchange!(memory_order.memory_order_acq_rel)(&obj.b, true) : order == memory_order.memory_order_seq_cst ? atomicExchange(&obj.b, true) : assert(0); } /// @trusted unittest { atomic_flag flag; assert(!atomic_flag_test_and_set_explicit_impl(&flag, memory_order.memory_order_seq_cst)); atomic_flag_clear_explicit_impl(&flag, memory_order.memory_order_seq_cst); } /** * Initializes an atomic variable, the destination should not have any expression associated with it prior to this call. * * We use an out parameter instead of a pointer for destination in an attempt to communicate to the compiler that it initializers. */ pragma(inline, true) void atomic_init(A, C)(out shared(A) obj, C desired) @trusted { // C11 atomic_init is a low-level initialization primitive for atomic storage // before it is published for concurrent access, so it must be able to write // the backing object without demonstrating ordinary shared access. *cast(A*) &obj = cast(A) desired; } /// unittest { shared int val; atomic_init(val, 2); shared float valF; atomic_init(valF, 3.2); } /// No-op function, doesn't apply to D pragma(inline, true) A kill_dependency(A)(A y) @trusted { return y; } /// Don't allow reordering, does not emit any instructions. pragma(inline, true) void atomic_signal_fence_impl()(memory_order order) { // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? // This is a no-op operation for relaxed memory orders. cast(void)0 : order == memory_order.memory_order_acquire ? atomicSignalFence!(memory_order.memory_order_acquire) : order == memory_order.memory_order_release ? atomicSignalFence!(memory_order.memory_order_release) : order == memory_order.memory_order_acq_rel ? atomicSignalFence!(memory_order.memory_order_acq_rel) : order == memory_order.memory_order_seq_cst ? atomicSignalFence!(memory_order.memory_order_seq_cst) : cast(void) assert(0); } /// unittest { atomic_signal_fence_impl(memory_order.memory_order_seq_cst); } /// Don't allow reordering, and emit a fence instruction. pragma(inline, true) void atomic_thread_fence_impl()(memory_order order) { // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? // This is a no-op operation for relaxed memory orders. cast(void)0 : order == memory_order.memory_order_acquire ? atomicFence!(memory_order.memory_order_acquire) : order == memory_order.memory_order_release ? atomicFence!(memory_order.memory_order_release) : order == memory_order.memory_order_acq_rel ? atomicFence!(memory_order.memory_order_acq_rel) : order == memory_order.memory_order_seq_cst ? atomicFence!(memory_order.memory_order_seq_cst) : cast(void) assert(0); } /// unittest { atomic_thread_fence_impl(memory_order.memory_order_seq_cst); } /// alias atomic_bool = shared(bool); /// alias atomic_char = shared(char); /// alias atomic_schar = shared(byte); /// alias atomic_uchar = shared(ubyte); /// alias atomic_short = shared(short); /// alias atomic_ushort = shared(ushort); /// alias atomic_int = shared(int); /// alias atomic_uint = shared(uint); /// alias atomic_long = shared(c_long); /// alias atomic_ulong = shared(c_ulong); /// alias atomic_llong = shared(long); /// alias atomic_ullong = shared(ulong); /// alias atomic_char8_t = shared(char); /// alias atomic_char16_t = shared(wchar); /// alias atomic_char32_t = shared(dchar); /// alias atomic_wchar_t = shared(wchar_t); /// alias atomic_int_least8_t = shared(int_least8_t); /// alias atomic_uint_least8_t = shared(uint_least8_t); /// alias atomic_int_least16_t = shared(int_least16_t); /// alias atomic_uint_least16_t = shared(uint_least16_t); /// alias atomic_int_least32_t = shared(int_least32_t); /// alias atomic_uint_least32_t = shared(uint_least32_t); /// alias atomic_int_least64_t = shared(int_least64_t); /// alias atomic_uint_least64_t = shared(uint_least64_t); /// alias atomic_int_fast8_t = shared(int_fast8_t); /// alias atomic_uint_fast8_t = shared(uint_fast8_t); /// alias atomic_int_fast16_t = shared(int_fast16_t); /// alias atomic_uint_fast16_t = shared(uint_fast16_t); /// alias atomic_int_fast32_t = shared(int_fast32_t); /// alias atomic_uint_fast32_t = shared(uint_fast32_t); /// alias atomic_int_fast64_t = shared(int_fast64_t); /// alias atomic_uint_fast64_t = shared(uint_fast64_t); /// alias atomic_intptr_t = shared(intptr_t); /// alias atomic_uintptr_t = shared(uintptr_t); /// alias atomic_size_t = shared(size_t); /// alias atomic_ptrdiff_t = shared(ptrdiff_t); /// alias atomic_intmax_t = shared(intmax_t); /// alias atomic_uintmax_t = shared(uintmax_t); /// pragma(inline, true) void atomic_store_impl(A, C)(shared(A)* obj, C desired) @trusted { assert(obj !is null); atomicStore(cast(A*)obj, cast(A)desired); } /// @trusted unittest { shared(int) obj; atomic_store_impl(&obj, 3); shared(float) objF; atomic_store_impl(&objF, 3.21); } /// pragma(inline, true) void atomic_store_explicit_impl(A, C)(shared(A)* obj, C desired, memory_order order) @trusted { assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner order == memory_order.memory_order_relaxed ? atomicStore!(memory_order.memory_order_relaxed)(cast(A*)obj, cast(A)desired) : order == memory_order.memory_order_acquire || order == memory_order.memory_order_acq_rel ? // Ideally this would error at compile time but alas it is not an intrinsic. // Note: this is not a valid memory order for this operation. atomicStore!(memory_order.memory_order_release)(cast(A*)obj, cast(A)desired) : order == memory_order.memory_order_release ? atomicStore!(memory_order.memory_order_release)(cast(A*)obj, cast(A)desired) : order == memory_order.memory_order_seq_cst ? atomicStore!(memory_order.memory_order_seq_cst)(cast(A*)obj, cast(A)desired) : cast(void) assert(0); } /// @trusted unittest { shared(int) obj; atomic_store_explicit_impl(&obj, 3, memory_order.memory_order_seq_cst); shared(float) objF; atomic_store_explicit_impl(&objF, 3.21, memory_order.memory_order_seq_cst); } /// pragma(inline, true) A atomic_load_impl(A)(const shared(A)* obj) @trusted { assert(obj !is null); return atomicLoad(cast(A*)obj); } /// @trusted unittest { shared(int) obj = 3; assert(atomic_load_impl(&obj) == 3); shared(float) objF = 3.5; assert(atomic_load_impl(&objF) > 3); static struct S2 { size_t[2] values; } align(S2.sizeof) shared(S2) objS2 = {[1, 2]}; assert(atomic_load_impl(&objS2).values == [1, 2]); } /// pragma(inline, true) A atomic_load_explicit_impl(A)(const shared(A)* obj, memory_order order) @trusted { assert(obj !is null); // use series of ternary expressions instead of switch to help the dmd inliner return order == memory_order.memory_order_relaxed ? atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj) : order == memory_order.memory_order_acquire ? atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj) : order == memory_order.memory_order_release ||