diff --git a/include/etl/atomic/atomic_gcc_sync.h b/include/etl/atomic/atomic_gcc_sync.h index 7d0d2d47..d01aff14 100644 --- a/include/etl/atomic/atomic_gcc_sync.h +++ b/include/etl/atomic/atomic_gcc_sync.h @@ -34,18 +34,960 @@ SOFTWARE. #include "../static_assert.h" #include "../nullptr.h" #include "../char_traits.h" +#include "../mutex.h" #include #include +// Select the amtomic builtins based on the version of the GCC compiler. #if defined(ETL_COMPILER_GCC) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-value" + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + #pragma GCC diagnostic ignored "-Wunused-value" + + #if ETL_COMPILER_FULL_VERSION >= 40700 + #define ETL_USE_ATOMIC_BUILTINS + #else + #define ETL_USE_SYNC_BUILTINS + #endif +#endif + +// Select the amtomic builtins based on the version of the Clang compiler. +#if defined(ETL_COMPILER_CLANG) + #if ETL_COMPILER_FULL_VERSION >= 50000 + #define ETL_USE_ATOMIC_BUILTINS + #else + #define ETL_USE_SYNC_BUILTINS + #endif #endif namespace etl { +#if defined(ETL_USE_ATOMIC_BUILTINS) + +#define ETL_BUILTIN_LOCK while (__atomic_test_and_set(&flag, etl::memory_order_seq_cst)) {} +#define ETL_BUILTIN_UNLOCK __atomic_clear(&flag, etl::memory_order_seq_cst); + + + //*************************************************************************** + // Atomic type for pre C++11 GCC compilers that support the builtin '__atomic' functions. + // Only integral and pointer types are supported. + //*************************************************************************** + + enum memory_order + { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST + }; + + //*************************************************************************** + /// For all types except bool, pointers and types that are always lock free. + //*************************************************************************** + template ::value> + class atomic + { + public: + + atomic() + : value(T()) + { + } + + atomic(T v) + : value(v) + { + } + + // Assignment + T operator =(T v) + { + store(v); + + return v; + } + + T operator =(T v) volatile + { + store(v); + + return v; + } + + // Pre-increment + T operator ++() + { + return __atomic_add_fetch(&value, 1, etl::memory_order_seq_cst); + } + + T operator ++() volatile + { + return __atomic_add_fetch(&value, 1, etl::memory_order_seq_cst); + } + + // Post-increment + T operator ++(int) + { + return __atomic_fetch_add(&value, 1, etl::memory_order_seq_cst); + } + + T operator ++(int) volatile + { + return __atomic_fetch_add(&value, 1, etl::memory_order_seq_cst); + } + + // Pre-decrement + T operator --() + { + return __atomic_sub_fetch(&value, 1, etl::memory_order_seq_cst); + } + + T operator --() volatile + { + return __atomic_sub_fetch(&value, 1, etl::memory_order_seq_cst); + } + + // Post-decrement + T operator --(int) + { + return __atomic_fetch_sub(&value, 1, etl::memory_order_seq_cst); + } + + T operator --(int) volatile + { + return __atomic_fetch_sub(&value, 1), etl::memory_order_seq_cst; + } + + // Add + T operator +=(T v) + { + return __atomic_fetch_add(&value, v, etl::memory_order_seq_cst); + } + + T operator +=(T v) volatile + { + return __atomic_fetch_add(&value, v, etl::memory_order_seq_cst); + } + + // Subtract + T operator -=(T v) + { + return __atomic_fetch_sub(&value, v, etl::memory_order_seq_cst); + } + + T operator -=(T v) volatile + { + return __atomic_fetch_sub(&value, v, etl::memory_order_seq_cst); + } + + // And + T operator &=(T v) + { + return __atomic_fetch_and(&value, v, etl::memory_order_seq_cst); + } + + T operator &=(T v) volatile + { + return __atomic_fetch_and(&value, v, etl::memory_order_seq_cst); + } + + // Or + T operator |=(T v) + { + return __atomic_fetch_or(&value, v, etl::memory_order_seq_cst); + } + + T operator |=(T v) volatile + { + return __atomic_fetch_or(&value, v, etl::memory_order_seq_cst); + } + + // Exclusive or + T operator ^=(T v) + { + return __atomic_fetch_xor(&value, v, etl::memory_order_seq_cst); + } + + T operator ^=(T v) volatile + { + return __atomic_fetch_xor(&value, v, etl::memory_order_seq_cst); + } + + // Conversion operator + operator T () const + { + return __atomic_fetch_add(&value, 0, etl::memory_order_seq_cst); + } + + operator T() volatile const + { + return __atomic_fetch_add(&value, 0, etl::memory_order_seq_cst); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + __atomic_store_n(&value, v, order); + } + + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __atomic_store_n(&value, v, order); + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return __atomic_load_n(&value, order); + } + + T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return __atomic_load_n(&value, order); + } + + // Fetch add + T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_add(&value, v, order); + } + + T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_add(&value, v, order); + } + + // Fetch subtract + T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_sub(&value, v, order); + } + + T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_sub(&value, v, order); + } + + // Fetch or + T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_or(&value, v, order); + } + + T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_or(&value, v, order); + } + + // Fetch and + T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_and(&value, v, order); + } + + T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_and(&value, v, order); + } + + // Fetch exclusive or + T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_xor(&value, v, order); + } + + T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_xor(&value, v, order); + } + + // Exchange + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_exchange_n(&value, v, order); + } + + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_exchange_n(&value, v, order); + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, order, order); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, order, order); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, success, failure); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, success, failure); + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, order, order); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, order, order); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, success, failure); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, success, failure); + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable T value; + }; + + //*************************************************************************** + /// Specialisation for pointers + //*************************************************************************** + template + class atomic + { + public: + + atomic() + : value(0U) + { + } + + atomic(T* v) + : value(uintptr_t(v)) + { + } + + // Assignment + T* operator =(T* v) + { + store(v); + + return v; + } + + T* operator =(T* v) volatile + { + store(v); + + return v; + } + + // Pre-increment + T* operator ++() + { + return reinterpret_cast(__atomic_add_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator ++() volatile + { + return reinterpret_cast(__atomic_add_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Post-increment + T* operator ++(int) + { + return reinterpret_cast(__atomic_fetch_add(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator ++(int) volatile + { + return reinterpret_cast(__atomic_fetch_add(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Pre-decrement + T* operator --() + { + return reinterpret_cast(__atomic_sub_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator --() volatile + { + return reinterpret_cast(__atomic_sub_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Post-decrement + T* operator --(int) + { + return reinterpret_cast(__atomic_fetch_sub(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator --(int) volatile + { + return reinterpret_cast(__atomic_fetch_sub(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Add + T* operator +=(ptrdiff_t v) + { + return reinterpret_cast(__atomic_fetch_add(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator +=(ptrdiff_t v) volatile + { + return reinterpret_cast(__atomic_fetch_add(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + // Subtract + T* operator -=(ptrdiff_t v) + { + return reinterpret_cast(__atomic_fetch_sub(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator -=(ptrdiff_t v) volatile + { + return reinterpret_cast(__atomic_fetch_sub(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + // Conversion operator + operator T* () const + { + return reinterpret_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + operator T*() volatile const + { + return reinterpret_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) + { + __atomic_store_n(&value, uintptr_t(v), order); + } + + void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __atomic_store_n(&value, uintptr_t(v), order); + } + + // Load + T* load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return reinterpret_cast(__atomic_load_n(&value, order)); + } + + T* load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return reinterpret_cast(__atomic_load_n(&value, order)); + } + + // Fetch add + T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__atomic_fetch_add(&value, v, order)); + } + + T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__atomic_fetch_add(&value, v, order)); + } + + // Fetch subtract + T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__atomic_fetch_sub(&value, v, order)); + } + + T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__atomic_fetch_sub(&value, v, order)); + } + + // Exchange + T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__atomic_exchange_n(&value, uintptr_t(v), order)); + } + + T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__atomic_exchange_n(&value, uintptr_t(v), order)); + } + + // Compare exchange weak + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, order, order); + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, order, order); + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, success, failure); + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, success, failure); + } + + // Compare exchange strong + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, order, order); + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, order, order); + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, success, failure); + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, success, failure); + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable uintptr_t value; + }; + + //*************************************************************************** + /// Specialisation for bool + //*************************************************************************** + template <> + class atomic + { + public: + + atomic() + : value(0U) + { + } + + atomic(bool v) + : value(char(v)) + { + } + + // Assignment + bool operator =(bool v) + { + store(v); + + return v; + } + + bool operator =(bool v) volatile + { + store(v); + + return v; + } + + // Conversion operator + operator bool () const + { + return static_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + operator bool() volatile const + { + return static_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) + { + __atomic_store_n(&value, char(v), order); + } + + void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __atomic_store_n(&value, char(v), order); + } + + // Load + bool load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return static_cast(__atomic_load_n(&value, order)); + } + + bool load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return static_cast(__atomic_load_n(&value, order)); + } + + // Exchange + bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) + { + return static_cast(__atomic_exchange_n(&value, char(v), order)); + } + + bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return static_cast(__atomic_exchange_n(&value, char(v), order)); + } + + // Compare exchange weak + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, order, order); + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, order, order); + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, success, failure); + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, success, failure); + } + + // Compare exchange strong + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, order, order); + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, order, order); + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, success, failure); + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, success, failure); + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable char value; + }; + + //*************************************************************************** + /// Specialisation for type that are not integral, pointer or bool. + /// Uses a mutex to control access. + //*************************************************************************** + template + class atomic + { + public: + + atomic() + : flag(0) + , value(T()) + { + } + + atomic(T v) + : flag(0) + , value(v) + { + } + + // Assignment + T operator =(T v) + { + store(v); + + return v; + } + + T operator =(T v) volatile + { + store(v); + + return v; + } + + // Conversion operator + operator T () const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + operator T() volatile const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Is lock free? + bool is_lock_free() const + { + return false; + } + + bool is_lock_free() const volatile + { + return false; + } + + // Store + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Exchange + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + bool result; + + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + bool result; + + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return compare_exchange_weak(expected, desired); + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return compare_exchange_weak(expected, desired); + } + + private: + + mutable char flag; + mutable T value; + }; + +#undef ETL_BUILTIN_LOCK +#undef ETL_BUILTIN_UNLOCK + +#endif + +#if defined(ETL_USE_SYNC_BUILTINS) + +#define ETL_BUILTIN_LOCK while (__sync_lock_test_and_set(&flag, 1U)) {} +#define ETL_BUILTIN_UNLOCK __sync_lock_release(&flag); + //*************************************************************************** // Atomic type for pre C++11 GCC compilers that support the builtin '__sync' functions. // Only integral and pointer types are supported. @@ -64,7 +1006,7 @@ namespace etl //*************************************************************************** /// For all types except bool and pointers //*************************************************************************** - template + template ::value> class atomic { public: @@ -471,7 +1413,7 @@ namespace etl /// Specialisation for pointers //*************************************************************************** template - class atomic + class atomic { public: @@ -572,7 +1514,7 @@ namespace etl return reinterpret_cast(__sync_fetch_and_add(&value, 0)); } - operator T*() volatile const + operator T* () volatile const { return reinterpret_cast(__sync_fetch_and_add(&value, 0)); } @@ -781,7 +1723,7 @@ namespace etl /// Specialisation for bool //*************************************************************************** template <> - class atomic + class atomic { public: @@ -810,74 +1752,8 @@ namespace etl return v; } - // Pre-increment - bool operator ++() - { - return static_cast(__sync_add_and_fetch(&value, sizeof(char))); - } - - bool operator ++() volatile - { - return static_cast(__sync_add_and_fetch(&value, sizeof(char))); - } - - // Post-increment - bool operator ++(int) - { - return static_cast(__sync_fetch_and_add(&value, sizeof(char))); - } - - bool operator ++(int) volatile - { - return static_cast(__sync_fetch_and_add(&value, sizeof(char))); - } - - // Pre-decrement - bool operator --() - { - return static_cast(__sync_sub_and_fetch(&value, sizeof(char))); - } - - bool operator --() volatile - { - return static_cast(__sync_sub_and_fetch(&value, sizeof(char))); - } - - // Post-decrement - bool operator --(int) - { - return static_cast(__sync_fetch_and_sub(&value, sizeof(char))); - } - - bool operator --(int) volatile - { - return static_cast(__sync_fetch_and_sub(&value, sizeof(char))); - } - - // Add - bool operator +=(ptrdiff_t v) - { - return static_cast(__sync_fetch_and_add(&value, v * sizeof(char))); - } - - bool operator +=(ptrdiff_t v) volatile - { - return static_cast(__sync_fetch_and_add(&value, v * sizeof(char))); - } - - // Subtract - bool operator -=(ptrdiff_t v) - { - return static_cast(__sync_fetch_and_sub(&value, v * sizeof(char))); - } - - bool operator -=(ptrdiff_t v) volatile - { - return static_cast(__sync_fetch_and_sub(&value, v * sizeof(char))); - } - // Conversion operator - operator bool () const + operator bool() const { return static_cast(__sync_fetch_and_add(&value, 0)); } @@ -920,28 +1796,6 @@ namespace etl return static_cast(__sync_fetch_and_add(&value, 0)); } - // Fetch add - bool fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) - { - return static_cast(__sync_fetch_and_add(&value, v)); - } - - bool fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return static_cast(__sync_fetch_and_add(&value, v)); - } - - // Fetch subtract - bool fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) - { - return static_cast(__sync_fetch_and_sub(&value, v)); - } - - bool fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return static_cast(__sync_fetch_and_sub(&value, v)); - } - // Exchange bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) { @@ -1087,6 +1941,209 @@ namespace etl mutable char value; }; + //*************************************************************************** + /// Specialisation for type that are not integral, pointer or bool. + /// Uses a mutex to control access. + //*************************************************************************** + template + class atomic + { + public: + + atomic() + : flag(0) + , value(T()) + { + } + + atomic(T v) + : flag(0) + , value(v) + { + } + + // Assignment + T operator =(T v) + { + store(v); + + return v; + } + + T operator =(T v) volatile + { + store(v); + + return v; + } + + // Conversion operator + operator T () const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + operator T() volatile const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Is lock free? + bool is_lock_free() const + { + return false; + } + + bool is_lock_free() const volatile + { + return false; + } + + // Store + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Exchange + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + bool result; + + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + bool result; + + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return compare_exchange_weak(expected, desired); + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return compare_exchange_weak(expected, desired); + } + + private: + + mutable char flag; + mutable T value; + }; + +#undef ETL_SYNC_BUILTIN_LOCK +#undef ETL_SYNC_BUILTIN_UNLOCK + +#endif + typedef etl::atomic atomic_bool; typedef etl::atomic atomic_char; typedef etl::atomic atomic_schar; diff --git a/include/etl/atomic/atomic_std.h b/include/etl/atomic/atomic_std.h index 6492764d..c7a9c08f 100644 --- a/include/etl/atomic/atomic_std.h +++ b/include/etl/atomic/atomic_std.h @@ -43,7 +43,10 @@ namespace etl // etl::atomic is a simple wrapper around std::atomic. //*************************************************************************** - typedef std::memory_order memory_order; + template + using atomic = std::atomic; + + using memory_order = std::memory_order; static ETL_CONSTANT etl::memory_order memory_order_relaxed = std::memory_order_relaxed; static ETL_CONSTANT etl::memory_order memory_order_consume = std::memory_order_consume; @@ -52,570 +55,66 @@ namespace etl static ETL_CONSTANT etl::memory_order memory_order_acq_rel = std::memory_order_acq_rel; static ETL_CONSTANT etl::memory_order memory_order_seq_cst = std::memory_order_seq_cst; - template - class atomic - { - public: - - atomic() - : value(0) - { - } - - atomic(T v) - : value(v) - { - } - - // Assignment - T operator =(T v) - { - return value = v; - } - - T operator =(T v) volatile - { - return value = v; - } - - // Pre-increment - T operator ++() - { - return ++value; - } - - T operator ++() volatile - { - return ++value; - } - - // Post-increment - T operator ++(int) - { - return value++; - } - - T operator ++(int) volatile - { - return value++; - } - - // Pre-decrement - T operator --() - { - return --value; - } - - T operator --() volatile - { - return --value; - } - - // Post-decrement - T operator --(int) - { - return value--; - } - - T operator --(int) volatile - { - return value--; - } - - // Add - T operator +=(T v) - { - return value += v; - } - - T operator +=(T v) volatile - { - return value += v; - } - - // Subtract - T operator -=(T v) - { - return value -= v; - } - - T operator -=(T v) volatile - { - return value -= v; - } - - // And - T operator &=(T v) - { - return value &= v; - } - - T operator &=(T v) volatile - { - return value &= v; - } - - // Or - T operator |=(T v) - { - return value |= v; - } - - T operator |=(T v) volatile - { - return value |= v; - } - - // Exclusive or - T operator ^=(T v) - { - return value ^= v; - } - - T operator ^=(T v) volatile - { - return value ^= v; - } - - // Conversion operator - operator T () const - { - return T(value); - } - - operator T() volatile const - { - return T(value); - } - - // Is lock free? - bool is_lock_free() const - { - return value.is_lock_free(); - } - - bool is_lock_free() const volatile - { - return value.is_lock_free(); - } - - // Store - void store(T v, etl::memory_order order = etl::memory_order_seq_cst) - { - value.store(v, order); - } - - void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - value.store(v, order); - } - - // Load - T load(etl::memory_order order = etl::memory_order_seq_cst) const - { - return value.load(order); - } - - T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile - { - return value.load(order); - } - - // Fetch add - T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.fetch_add(v, order); - } - - T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.fetch_add(v, order); - } - - // Fetch subtract - T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.fetch_sub(v, order); - } - - T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.fetch_sub(v, order); - } - - // Fetch or - T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.fetch_or(v, order); - } - - T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.fetch_or(v, order); - } - - // Fetch and - T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.fetch_and(v, order); - } - - T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.fetch_and(v, order); - } - - // Fetch exclusive or - T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.fetch_xor(v, order); - } - - T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.fetch_xor(v, order); - } - - // Exchange - T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.exchange(v, order); - } - - T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.exchange(v, order); - } - - // Compare exchange weak - bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.compare_exchange_weak(expected, desired, order); - } - - bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.compare_exchange_weak(expected, desired, order); - } - - bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) - { - return value.compare_exchange_weak(expected, desired, success, failure); - } - - bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile - { - return value.compare_exchange_weak(expected, desired, success, failure); - } - - // Compare exchange strong - bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.compare_exchange_strong(expected, desired, order); - } - - bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.compare_exchange_strong(expected, desired, order); - } - - bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) - { - return value.compare_exchange_strong(expected, desired, success, failure); - } - - bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile - { - return value.compare_exchange_strong(expected, desired, success, failure); - } - - private: - - atomic& operator =(const atomic&); - //atomic& operator =(const atomic&) volatile; - - std::atomic value; - }; - - template - class atomic - { - public: - - atomic() - : value(ETL_NULLPTR) - { - } - - atomic(T* v) - : value(v) - { - } - - // Assignment - T* operator =(T* v) - { - return value = v; - } - - T* operator =(T* v) volatile - { - return value = v; - } - - // Pre-increment - T* operator ++() - { - return ++value; - } - - T* operator ++() volatile - { - return ++value; - } - - // Post-increment - T* operator ++(int) - { - return value++; - } - - T* operator ++(int) volatile - { - return value++; - } - - // Pre-decrement - T* operator --() - { - return --value; - } - - T* operator --() volatile - { - return --value; - } - - // Post-decrement - T* operator --(int) - { - return value--; - } - - T* operator --(int) volatile - { - return value--; - } - - // Add - T* operator +=(ptrdiff_t v) - { - return value += v; - } - - T* operator +=(ptrdiff_t v) volatile - { - return value += v; - } - - // Subtract - T* operator -=(ptrdiff_t v) - { - return value -= v; - } - - T* operator -=(ptrdiff_t v) volatile - { - return value -= v; - } - - // Conversion operator - operator T* () const - { - return static_cast(value); - } - - operator T*() volatile const - { - return static_cast(value); - } - - // Is lock free? - bool is_lock_free() const - { - return value.is_lock_free(); - } - - bool is_lock_free() const volatile - { - return value.is_lock_free(); - } - - // Store - void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) - { - value.store(v, order); - } - - void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - value.store(v, order); - } - - // Load - T* load(etl::memory_order order = etl::memory_order_seq_cst) - { - return value.load(order); - } - - T* load(etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.load(order); - } - - // Fetch add - T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.fetch_add(v, order); - } - - T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.fetch_add(v, order); - } - - // Fetch subtract - T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.fetch_sub(v, order); - } - - T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.fetch_sub(v, order); - } - - // Exchange - T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.exchange(v, order); - } - - T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.exchange(v, order); - } - - // Compare exchange weak - bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.compare_exchange_weak(expected, desired, order); - } - - bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.compare_exchange_weak(expected, desired, order); - } - - bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) - { - return value.compare_exchange_weak(expected, desired, success, failure); - } - - bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile - { - return value.compare_exchange_weak(expected, desired, success, failure); - } - - // Compare exchange strong - bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) - { - return value.compare_exchange_strong(expected, desired, order); - } - - bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile - { - return value.compare_exchange_strong(expected, desired, order); - } - - bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) - { - return value.compare_exchange_strong(expected, desired, success, failure); - } - - bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile - { - return value.compare_exchange_strong(expected, desired, success, failure); - } - - private: - - atomic & operator =(const atomic&) ETL_DELETE; - atomic& operator =(const atomic&) volatile ETL_DELETE; - - std::atomic value; - }; - - typedef std::atomic atomic_bool; - typedef std::atomic atomic_char; - typedef std::atomic atomic_schar; - typedef std::atomic atomic_uchar; - typedef std::atomic atomic_short; - typedef std::atomic atomic_ushort; - typedef std::atomic atomic_int; - typedef std::atomic atomic_uint; - typedef std::atomic atomic_long; - typedef std::atomic atomic_ulong; - typedef std::atomic atomic_llong; - typedef std::atomic atomic_ullong; - typedef std::atomic atomic_wchar_t; + using atomic_bool = std::atomic; + using atomic_char = std::atomic; + using atomic_schar = std::atomic; + using atomic_uchar = std::atomic; + using atomic_short = std::atomic; + using atomic_ushort = std::atomic; + using atomic_int = std::atomic; + using atomic_uint = std::atomic; + using atomic_long = std::atomic; + using atomic_ulong = std::atomic; + using atomic_llong = std::atomic; + using atomic_ullong = std::atomic; + using atomic_wchar_t = std::atomic; #if ETL_HAS_NATIVE_CHAR8_T - typedef std::atomic atomic_char8_t; + using atomic_char8_t = std::atomic; #endif #if ETL_HAS_NATIVE_CHAR16_T - typedef std::atomic atomic_char16_t; + using atomic_char16_t = std::atomic; #endif #if ETL_HAS_NATIVE_CHAR32_T - typedef std::atomic atomic_char32_t; + using atomic_char32_t = std::atomic; #endif #if ETL_USING_8BIT_TYPES - typedef std::atomic atomic_uint8_t; - typedef std::atomic atomic_int8_t; + using atomic_uint8_t = std::atomic; + using atomic_int8_t = std::atomic; #endif - typedef std::atomic atomic_uint16_t; - typedef std::atomic atomic_int16_t; - typedef std::atomic atomic_uint32_t; - typedef std::atomic atomic_int32_t; + using atomic_uint16_t = std::atomic; + using atomic_int16_t = std::atomic; + using atomic_uint32_t = std::atomic; + using atomic_int32_t = std::atomic; #if ETL_USING_64BIT_TYPES - typedef std::atomic atomic_uint64_t; - typedef std::atomic atomic_int64_t; + using atomic_uint64_t = std::atomic; + using atomic_int64_t = std::atomic; #endif - typedef std::atomic atomic_int_least8_t; - typedef std::atomic atomic_uint_least8_t; - typedef std::atomic atomic_int_least16_t; - typedef std::atomic atomic_uint_least16_t; - typedef std::atomic atomic_int_least32_t; - typedef std::atomic atomic_uint_least32_t; + using atomic_int_least8_t = std::atomic; + using atomic_uint_least8_t = std::atomic; + using atomic_int_least16_t = std::atomic; + using atomic_uint_least16_t = std::atomic; + using atomic_int_least32_t = std::atomic; + using atomic_uint_least32_t = std::atomic; #if ETL_USING_64BIT_TYPES - typedef std::atomic atomic_int_least64_t; - typedef std::atomic atomic_uint_least64_t; + using atomic_int_least64_t = std::atomic; + using atomic_uint_least64_t = std::atomic; #endif - typedef std::atomic atomic_int_fast8_t; - typedef std::atomic atomic_uint_fast8_t; - typedef std::atomic atomic_int_fast16_t; - typedef std::atomic atomic_uint_fast16_t; - typedef std::atomic atomic_int_fast32_t; - typedef std::atomic atomic_uint_fast32_t; + using atomic_int_fast8_t = std::atomic; + using atomic_uint_fast8_t = std::atomic; + using atomic_int_fast16_t = std::atomic; + using atomic_uint_fast16_t = std::atomic; + using atomic_int_fast32_t = std::atomic; + using atomic_uint_fast32_t = std::atomic; #if ETL_USING_64BIT_TYPES - typedef std::atomic atomic_int_fast64_t; - typedef std::atomic atomic_uint_fast64_t; + using atomic_int_fast64_t = std::atomic; + using atomic_uint_fast64_t = std::atomic; #endif - typedef std::atomic atomic_intptr_t; - typedef std::atomic atomic_uintptr_t; - typedef std::atomic atomic_size_t; - typedef std::atomic atomic_ptrdiff_t; - typedef std::atomic atomic_intmax_t; - typedef std::atomic atomic_uintmax_t; + using atomic_intptr_t = std::atomic; + using atomic_uintptr_t = std::atomic; + using atomic_size_t = std::atomic; + using atomic_ptrdiff_t = std::atomic; + using atomic_intmax_t = std::atomic; + using atomic_uintmax_t = std::atomic; } #endif diff --git a/include/etl/enum_type.h b/include/etl/enum_type.h index 23210a24..01019a77 100644 --- a/include/etl/enum_type.h +++ b/include/etl/enum_type.h @@ -85,9 +85,7 @@ SOFTWARE. #define ETL_DECLARE_ENUM_TYPE(TypeName, ValueType) \ typedef ValueType value_type; \ ETL_CONSTEXPR TypeName() : value(static_cast(value_type())) {} \ - ETL_CONSTEXPR TypeName(const TypeName &other) : value(other.value) {} \ ETL_CONSTEXPR TypeName(enum_type value_) : value(value_) {} \ - ETL_CONSTEXPR14 TypeName& operator=(const TypeName &other) {value = other.value; return *this;} \ ETL_CONSTEXPR explicit TypeName(value_type value_) : value(static_cast(value_)) {} \ ETL_CONSTEXPR operator value_type() const {return static_cast(value);} \ ETL_CONSTEXPR value_type get_value() const {return static_cast(value);} \ diff --git a/include/etl/mutex.h b/include/etl/mutex.h index e153a21c..c1cfb5a9 100644 --- a/include/etl/mutex.h +++ b/include/etl/mutex.h @@ -59,6 +59,45 @@ namespace etl { static ETL_CONSTANT bool has_mutex = (ETL_HAS_MUTEX == 1); } + + //*************************************************************************** + /// lock_guard + /// A mutex wrapper that provides an RAII mechanism for owning a mutex for + /// the duration of a scoped block. + //*************************************************************************** + template + class lock_guard + { + public: + + typedef TMutex mutex_type; + + //***************************************************** + /// Constructor + /// Locks the mutex. + //***************************************************** + explicit lock_guard(mutex_type& m_) + : m(m_) + { + m.lock(); + } + + //***************************************************** + /// Destructor + //***************************************************** + ~lock_guard() + { + m.unlock(); + } + + private: + + // Deleted. + lock_guard(const lock_guard&) ETL_DELETE; + + mutex_type& m; + }; + } #endif diff --git a/include/etl/mutex/mutex_gcc_sync.h b/include/etl/mutex/mutex_gcc_sync.h index d2cc5ade..302e2dc7 100644 --- a/include/etl/mutex/mutex_gcc_sync.h +++ b/include/etl/mutex/mutex_gcc_sync.h @@ -53,9 +53,6 @@ namespace etl { while (__sync_lock_test_and_set(&flag, 1U)) { - while (flag) - { - } } } diff --git a/include/etl/mutex/mutex_std.h b/include/etl/mutex/mutex_std.h index 730cf5ec..6738e14e 100644 --- a/include/etl/mutex/mutex_std.h +++ b/include/etl/mutex/mutex_std.h @@ -39,37 +39,7 @@ namespace etl ///\ingroup mutex ///\brief This mutex class is implemented using std::mutex. //*************************************************************************** - class mutex - { - public: - - mutex() - : access() - { - } - - void lock() - { - access.lock(); - } - - bool try_lock() - { - return access.try_lock(); - } - - void unlock() - { - access.unlock(); - } - - private: - - mutex(const mutex&) ETL_DELETE; - mutex& operator=(const mutex&) ETL_DELETE; - - std::mutex access; - }; + using mutex = std::mutex; } #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0c139f2a..a5f3407d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -42,7 +42,7 @@ set(TEST_SOURCE_FILES test_array.cpp test_array_view.cpp test_array_wrapper.cpp - test_atomic_std.cpp + test_atomic.cpp test_binary.cpp test_bip_buffer_spsc_atomic.cpp test_bit.cpp @@ -324,16 +324,12 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") message(STATUS "Using GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") - message(STATUS "Including test_atomic_gcc_sync") - list(APPEND TEST_SOURCE_FILES "test_atomic_gcc_sync.cpp") endif() if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(STATUS "Using Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") - message(STATUS "Including test_atomic_clang_sync") - list(APPEND TEST_SOURCE_FILES "test_atomic_clang_sync.cpp") endif() add_executable(etl_tests ${TEST_SOURCE_FILES}) diff --git a/test/test_atomic_clang_sync.cpp b/test/test_atomic.cpp similarity index 76% rename from test/test_atomic_clang_sync.cpp rename to test/test_atomic.cpp index 80877d75..3975074e 100644 --- a/test/test_atomic_clang_sync.cpp +++ b/test/test_atomic.cpp @@ -5,7 +5,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl https://www.etlcpp.com -Copyright(c) 2017 jwellbelove +Copyright(c) 2022 jwellbelove Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal @@ -29,10 +29,15 @@ SOFTWARE. #include "unit_test_framework.h" #include "etl/platform.h" +#include "etl/enum_type.h" -#if defined(ETL_COMPILER_CLANG) - -#include "etl/atomic/atomic_clang_sync.h" +#if defined(ETL_COMPILER_MICROSOFT) + #include "etl/atomic/atomic_std.h" +#elif defined(ETL_COMPILER_GCC) + #include "etl/atomic/atomic_gcc_sync.h" +#elif defined(ETL_COMPILER_CLANG) + #include "etl/atomic/atomic_clang_sync.h" +#endif #include #include @@ -45,7 +50,21 @@ SOFTWARE. namespace { - SUITE(test_atomic_clang) + struct Enum + { + enum enum_type + { + One = 1, + Two = 2 + }; + + ETL_DECLARE_ENUM_TYPE(Enum, int) + ETL_ENUM_TYPE(One, "1") + ETL_ENUM_TYPE(Two, "2") + ETL_END_ENUM_TYPE + }; + + SUITE(test_atomic_std) { //************************************************************************* TEST(test_atomic_integer_is_lock_free) @@ -65,15 +84,6 @@ namespace CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free()); } - //************************************************************************* - TEST(test_atomic_bool_is_lock_free) - { - std::atomic compare; - etl::atomic test; - - CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free()); - } - //************************************************************************* TEST(test_atomic_integer_load) { @@ -83,10 +93,19 @@ namespace CHECK_EQUAL((int)compare.load(), (int)test.load()); } + //************************************************************************* + TEST(test_atomic_enum_load) + { + std::atomic compare(Enum::One); + etl::atomic test(Enum::One); + + CHECK_EQUAL((Enum)compare.load(), (Enum::value_type)test.load()); + } + //************************************************************************* TEST(test_atomic_pointer_load) { - int i = 1; + int i; std::atomic compare(&i); etl::atomic test(&i); @@ -97,10 +116,10 @@ namespace //************************************************************************* TEST(test_atomic_bool_load) { - bool i = true; + bool i; - std::atomic compare(i); - etl::atomic test(i); + std::atomic compare(&i); + etl::atomic test(&i); CHECK_EQUAL((bool)compare.load(), (bool)test.load()); } @@ -116,6 +135,17 @@ namespace CHECK_EQUAL((int)compare.load(), (int)test.load()); } + //************************************************************************* + TEST(test_atomic_enum_store) + { + std::atomic compare(Enum::One); + etl::atomic test(Enum::One); + + compare.store(Enum::Two); + test.store(Enum::Two); + CHECK_EQUAL((Enum::value_type)compare.load(), (Enum::value_type)test.load()); + } + //************************************************************************* TEST(test_atomic_pointer_store) { @@ -133,14 +163,11 @@ namespace //************************************************************************* TEST(test_atomic_bool_store) { - bool i = true; - bool j = false; + std::atomic compare(false); + etl::atomic test(false); - std::atomic compare(i); - etl::atomic test(i); - - compare.store(j); - test.store(j); + compare.store(true); + test.store(true); CHECK_EQUAL((bool)compare.load(), (bool)test.load()); } @@ -155,6 +182,17 @@ namespace CHECK_EQUAL((int)compare.load(), (int)test.load()); } + //************************************************************************* + TEST(test_atomic_enum_assignment) + { + std::atomic compare(Enum::One); + etl::atomic test(Enum::One); + + compare = Enum::Two; + test = Enum::Two; + CHECK_EQUAL((Enum::value_type)compare.load(), (Enum::value_type)test.load()); + } + //************************************************************************* TEST(test_atomic_pointer_assignment) { @@ -172,14 +210,11 @@ namespace //************************************************************************* TEST(test_atomic_bool_assignment) { - bool i = true; - bool j = false; + std::atomic compare(false); + etl::atomic test(false); - std::atomic compare(i); - etl::atomic test(i); - - compare = j; - test = j; + compare = true; + test = true; CHECK_EQUAL((bool)compare.load(), (bool)test.load()); } @@ -435,6 +470,15 @@ namespace CHECK_EQUAL((int)compare.exchange(2), (int)test.exchange(2)); } + //************************************************************************* + TEST(test_atomic_enum_exchange) + { + std::atomic compare(Enum::One); + etl::atomic test(Enum::One); + + CHECK_EQUAL((Enum)compare.exchange(Enum::Two), (Enum)test.exchange(Enum::Two)); + } + //************************************************************************* TEST(test_atomic_pointer_exchange) { @@ -450,13 +494,10 @@ namespace //************************************************************************* TEST(test_atomic_bool_exchange) { - bool i = true; - bool j = false; + std::atomic compare(false); + etl::atomic test(false); - std::atomic compare(i); - etl::atomic test(i); - - CHECK_EQUAL((bool)compare.exchange(j), (bool)test.exchange(j)); + CHECK_EQUAL((bool)compare.exchange(true), (bool)test.exchange(true)); } //************************************************************************* @@ -505,6 +546,52 @@ namespace CHECK_EQUAL(compare.load(), test.load()); } + //************************************************************************* + TEST(test_atomic_compare_exchange_weak_pass_for_enum) + { + std::atomic compare; + etl::atomic test; + + Enum actual = Enum::One; + + compare = actual; + test = actual; + + Enum compare_expected = actual; + Enum test_expected = actual; + Enum desired = Enum::Two; + + bool compare_result = compare.compare_exchange_weak(compare_expected, desired); + bool test_result = test.compare_exchange_weak(test_expected, desired); + + CHECK_EQUAL(compare_result, test_result); + CHECK_EQUAL(compare_expected, test_expected); + CHECK_EQUAL(compare.load(), test.load()); + } + + //************************************************************************* + TEST(test_atomic_compare_exchange_weak_pass_for_bool) + { + std::atomic compare; + etl::atomic test; + + bool actual = false; + + compare = actual; + test = actual; + + bool compare_expected = actual; + bool test_expected = actual; + bool desired = true; + + bool compare_result = compare.compare_exchange_weak(compare_expected, desired); + bool test_result = test.compare_exchange_weak(test_expected, desired); + + CHECK_EQUAL(compare_result, test_result); + CHECK_EQUAL(compare_expected, test_expected); + CHECK_EQUAL(compare.load(), test.load()); + } + //************************************************************************* TEST(test_atomic_compare_exchange_strong_fail) { @@ -551,6 +638,52 @@ namespace CHECK_EQUAL(compare.load(), test.load()); } + //************************************************************************* + TEST(test_atomic_compare_exchange_strong_pass_for_enum) + { + std::atomic compare; + etl::atomic test; + + Enum actual = Enum::One; + + compare = actual; + test = actual; + + Enum compare_expected = actual; + Enum test_expected = actual; + Enum desired = Enum::Two; + + bool compare_result = compare.compare_exchange_strong(compare_expected, desired); + bool test_result = test.compare_exchange_strong(test_expected, desired); + + CHECK_EQUAL(compare_result, test_result); + CHECK_EQUAL(compare_expected, test_expected); + CHECK_EQUAL(compare.load(), test.load()); + } + + //************************************************************************* + TEST(test_atomic_compare_exchange_strong_pass_for_bool) + { + std::atomic compare; + etl::atomic test; + + bool actual = false; + + compare = actual; + test = actual; + + bool compare_expected = actual; + bool test_expected = actual; + bool desired = true; + + bool compare_result = compare.compare_exchange_strong(compare_expected, desired); + bool test_result = test.compare_exchange_strong(test_expected, desired); + + CHECK_EQUAL(compare_result, test_result); + CHECK_EQUAL(compare_expected, test_expected); + CHECK_EQUAL(compare.load(), test.load()); + } + //************************************************************************* #if REALTIME_TEST @@ -608,5 +741,3 @@ namespace #endif }; } - -#endif diff --git a/test/test_atomic_gcc_sync.cpp b/test/test_atomic_gcc_sync.cpp deleted file mode 100644 index 7720b35f..00000000 --- a/test/test_atomic_gcc_sync.cpp +++ /dev/null @@ -1,531 +0,0 @@ -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2017 jwellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#include "UnitTest++/UnitTest++.h" - -#include "etl/platform.h" - -#if defined(ETL_COMPILER_GCC) - -#include "etl/atomic/atomic_gcc_sync.h" - -#include -#include - -#define REALTIME_TEST 0 - -namespace -{ - SUITE(test_atomic_std) - { - //========================================================================= - TEST(test_atomic_integer_is_lock_free) - { - std::atomic compare; - etl::atomic test; - - CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free()); - } - - //========================================================================= - TEST(test_atomic_pointer_is_lock_free) - { - std::atomic compare; - etl::atomic test; - - CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free()); - } - - //========================================================================= - TEST(test_atomic_integer_load) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.load(), (int)test.load()); - } - - //========================================================================= - TEST(test_atomic_pointer_load) - { - int i; - - std::atomic compare(&i); - etl::atomic test(&i); - - CHECK_EQUAL((int*)compare.load(), (int*)test.load()); - } - - //========================================================================= - TEST(test_atomic_integer_store) - { - std::atomic compare(1); - etl::atomic test(1); - - compare.store(2); - test.store(2); - CHECK_EQUAL((int)compare.load(), (int)test.load()); - } - - //========================================================================= - TEST(test_atomic_pointer_store) - { - int i; - int j; - - std::atomic compare(&i); - etl::atomic test(&i); - - compare.store(&j); - test.store(&j); - CHECK_EQUAL((int*)compare.load(), (int*)test.load()); - } - - //========================================================================= - TEST(test_atomic_integer_assignment) - { - std::atomic compare(1); - etl::atomic test(1); - - compare = 2; - test = 2; - CHECK_EQUAL((int)compare.load(), (int)test.load()); - } - - //========================================================================= - TEST(test_atomic_pointer_assignment) - { - int i; - int j; - - std::atomic compare(&i); - etl::atomic test(&i); - - compare = &j; - test = &j; - CHECK_EQUAL((int*)compare.load(), (int*)test.load()); - } - - //========================================================================= - TEST(test_atomic_operator_integer_pre_increment) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)++compare, (int)++test); - CHECK_EQUAL((int)++compare, (int)++test); - } - - //========================================================================= - TEST(test_atomic_operator_integer_post_increment) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare++, (int)test++); - CHECK_EQUAL((int)compare++, (int)test++); - } - - //========================================================================= - TEST(test_atomic_operator_integer_pre_decrement) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)--compare, (int)--test); - CHECK_EQUAL((int)--compare, (int)--test); - } - - //========================================================================= - TEST(test_atomic_operator_integer_post_decrement) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare--, (int)test--); - CHECK_EQUAL((int)compare--, (int)test--); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_pre_increment) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)++compare, (int*)++test); - CHECK_EQUAL((int*)++compare, (int*)++test); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_post_increment) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)compare++, (int*)test++); - CHECK_EQUAL((int*)compare++, (int*)test++); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_pre_decrement) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[3]); - etl::atomic test(&data[3]); - - CHECK_EQUAL((int*)--compare, (int*)--test); - CHECK_EQUAL((int*)--compare, (int*)--test); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_post_decrement) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[3]); - etl::atomic test(&data[3]); - - CHECK_EQUAL((int*)compare--, (int*)test--); - CHECK_EQUAL((int*)compare--, (int*)test--); - } - - //========================================================================= - TEST(test_atomic_operator_integer_fetch_add) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.fetch_add(2), (int)test.fetch_add(2)); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_fetch_add) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)compare.fetch_add(std::ptrdiff_t(10)), (int*)test.fetch_add(std::ptrdiff_t(10))); - } - - //========================================================================= - TEST(test_atomic_operator_integer_plus_equals) - { - std::atomic compare(1); - etl::atomic test(1); - - compare += 2; - test += 2; - - CHECK_EQUAL((int)compare, (int)test); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_plus_equals) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - compare += 2; - test += 2; - - CHECK_EQUAL((int*)compare, (int*)test); - } - - //========================================================================= - TEST(test_atomic_operator_integer_minus_equals) - { - std::atomic compare(1); - etl::atomic test(1); - - compare -= 2; - test -= 2; - - CHECK_EQUAL((int)compare, (int)test); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_minus_equals) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[3]); - etl::atomic test(&data[3]); - - compare -= 2; - test -= 2; - - CHECK_EQUAL((int*)compare, (int*)test); - } - - //========================================================================= - TEST(test_atomic_operator_integer_and_equals) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - compare &= 0x55AA55AAUL; - test &= 0x55AA55AAUL; - - CHECK_EQUAL((int)compare, (int)test); - } - - //========================================================================= - TEST(test_atomic_operator_integer_or_equals) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - compare |= 0x55AA55AAUL; - test |= 0x55AA55AAUL; - - CHECK_EQUAL((int)compare, (int)test); - } - - //========================================================================= - TEST(test_atomic_operator_integer_xor_equals) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - compare ^= 0x55AA55AAUL; - test ^= 0x55AA55AAUL; - - CHECK_EQUAL((int)compare, (int)test); - } - - //========================================================================= - TEST(test_atomic_operator_integer_fetch_sub) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.fetch_sub(2), (int)test.fetch_sub(2)); - } - - //========================================================================= - TEST(test_atomic_operator_pointer_fetch_sub) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)compare.fetch_add(std::ptrdiff_t(10)), (int*)test.fetch_add(std::ptrdiff_t(10))); - } - - //========================================================================= - TEST(test_atomic_operator_fetch_and) - { - std::atomic compare(0xFFFFFFFFUL); - etl::atomic test(0xFFFFFFFFUL); - - CHECK_EQUAL((int)compare.fetch_and(0x55AA55AAUL), (int)test.fetch_and(0x55AA55AAUL)); - } - - //========================================================================= - TEST(test_atomic_operator_fetch_or) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - CHECK_EQUAL((int)compare.fetch_or(0x55AA55AAUL), (int)test.fetch_or(0x55AA55AAUL)); - } - - //========================================================================= - TEST(test_atomic_operator_fetch_xor) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - CHECK_EQUAL((int)compare.fetch_xor(0x55AA55AAUL), (int)test.fetch_xor(0x55AA55AAUL)); - } - - //========================================================================= - TEST(test_atomic_integer_exchange) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.exchange(2), (int)test.exchange(2)); - } - - //========================================================================= - TEST(test_atomic_pointer_exchange) - { - int i; - int j; - - std::atomic compare(&i); - etl::atomic test(&i); - - CHECK_EQUAL((int*)compare.exchange(&j), (int*)test.exchange(&j)); - } - - //========================================================================= - TEST(test_atomic_compare_exchange_weak_fail) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = 2; - int test_expected = 2; - int desired = 3; - - bool compare_result = compare.compare_exchange_weak(compare_expected, desired); - bool test_result = test.compare_exchange_weak(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //========================================================================= - TEST(test_atomic_compare_exchange_weak_pass) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = actual; - int test_expected = actual; - int desired = 3; - - bool compare_result = compare.compare_exchange_weak(compare_expected, desired); - bool test_result = test.compare_exchange_weak(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //========================================================================= - TEST(test_atomic_compare_exchange_strong_fail) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = 2; - int test_expected = 2; - int desired = 3; - - bool compare_result = compare.compare_exchange_strong(compare_expected, desired); - bool test_result = test.compare_exchange_strong(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //========================================================================= - TEST(test_atomic_compare_exchange_strong_pass) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = actual; - int test_expected = actual; - int desired = 3; - - bool compare_result = compare.compare_exchange_strong(compare_expected, desired); - bool test_result = test.compare_exchange_strong(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //========================================================================= - #if REALTIME_TEST - etl::atomic_int32_t atomic_value = 0U; - etl::atomic atomic_flag = false; - - void thread1() - { - while (!atomic_flag.load()); - - for (int i = 0; i < 10000000; ++i) - { - ++atomic_value; - } - } - - void thread2() - { - while (!atomic_flag.load()); - - for (int i = 0; i < 10000000; ++i) - { - --atomic_value; - } - } - - TEST(test_atomic_multi_thread) - { - std::thread t1(thread1); - std::thread t2(thread2); - - atomic_flag.store(true); - - t1.join(); - t2.join(); - - CHECK_EQUAL(0, atomic_value.load()); - } - #endif - }; -} - -#endif diff --git a/test/test_atomic_std.cpp b/test/test_atomic_std.cpp deleted file mode 100644 index 04b8c865..00000000 --- a/test/test_atomic_std.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2017 jwellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#include "unit_test_framework.h" - -#include "etl/platform.h" -#include "etl/atomic/atomic_std.h" - -#include -#include - -#if defined(ETL_TARGET_OS_WINDOWS) - #include -#endif - -#define REALTIME_TEST 0 - -namespace -{ - SUITE(test_atomic_std) - { - //************************************************************************* - TEST(test_atomic_integer_is_lock_free) - { - std::atomic compare; - etl::atomic test; - - CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free()); - } - - //************************************************************************* - TEST(test_atomic_pointer_is_lock_free) - { - std::atomic compare; - etl::atomic test; - - CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free()); - } - - //************************************************************************* - TEST(test_atomic_integer_load) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.load(), (int)test.load()); - } - - //************************************************************************* - TEST(test_atomic_pointer_load) - { - int i; - - std::atomic compare(&i); - etl::atomic test(&i); - - CHECK_EQUAL((int*)compare.load(), (int*)test.load()); - } - - //************************************************************************* - TEST(test_atomic_integer_store) - { - std::atomic compare(1); - etl::atomic test(1); - - compare.store(2); - test.store(2); - CHECK_EQUAL((int)compare.load(), (int)test.load()); - } - - //************************************************************************* - TEST(test_atomic_pointer_store) - { - int i; - int j; - - std::atomic compare(&i); - etl::atomic test(&i); - - compare.store(&j); - test.store(&j); - CHECK_EQUAL((int*)compare.load(), (int*)test.load()); - } - - //************************************************************************* - TEST(test_atomic_integer_assignment) - { - std::atomic compare(1); - etl::atomic test(1); - - compare = 2; - test = 2; - CHECK_EQUAL((int)compare.load(), (int)test.load()); - } - - //************************************************************************* - TEST(test_atomic_pointer_assignment) - { - int i; - int j; - - std::atomic compare(&i); - etl::atomic test(&i); - - compare = &j; - test = &j; - CHECK_EQUAL((int*)compare.load(), (int*)test.load()); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_pre_increment) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)++compare, (int)++test); - CHECK_EQUAL((int)++compare, (int)++test); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_post_increment) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare++, (int)test++); - CHECK_EQUAL((int)compare++, (int)test++); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_pre_decrement) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)--compare, (int)--test); - CHECK_EQUAL((int)--compare, (int)--test); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_post_decrement) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare--, (int)test--); - CHECK_EQUAL((int)compare--, (int)test--); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_pre_increment) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)++compare, (int*)++test); - CHECK_EQUAL((int*)++compare, (int*)++test); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_post_increment) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)compare++, (int*)test++); - CHECK_EQUAL((int*)compare++, (int*)test++); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_pre_decrement) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[3]); - etl::atomic test(&data[3]); - - CHECK_EQUAL((int*)--compare, (int*)--test); - CHECK_EQUAL((int*)--compare, (int*)--test); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_post_decrement) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[3]); - etl::atomic test(&data[3]); - - CHECK_EQUAL((int*)compare--, (int*)test--); - CHECK_EQUAL((int*)compare--, (int*)test--); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_fetch_add) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.fetch_add(2), (int)test.fetch_add(2)); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_fetch_add) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)compare.fetch_add(ptrdiff_t(10)), (int*)test.fetch_add(ptrdiff_t(10))); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_plus_equals) - { - std::atomic compare(1); - etl::atomic test(1); - - compare += 2; - test += 2; - - CHECK_EQUAL((int)compare, (int)test); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_plus_equals) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - compare += 2; - test += 2; - - CHECK_EQUAL((int*)compare, (int*)test); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_minus_equals) - { - std::atomic compare(1); - etl::atomic test(1); - - compare -= 2; - test -= 2; - - CHECK_EQUAL((int)compare, (int)test); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_minus_equals) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[3]); - etl::atomic test(&data[3]); - - compare -= 2; - test -= 2; - - CHECK_EQUAL((int*)compare, (int*)test); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_and_equals) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - compare &= 0x55AA55AAUL; - test &= 0x55AA55AAUL; - - CHECK_EQUAL((int)compare, (int)test); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_or_equals) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - compare |= 0x55AA55AAUL; - test |= 0x55AA55AAUL; - - CHECK_EQUAL((int)compare, (int)test); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_xor_equals) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - compare ^= 0x55AA55AAUL; - test ^= 0x55AA55AAUL; - - CHECK_EQUAL((int)compare, (int)test); - } - - //************************************************************************* - TEST(test_atomic_operator_integer_fetch_sub) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.fetch_sub(2), (int)test.fetch_sub(2)); - } - - //************************************************************************* - TEST(test_atomic_operator_pointer_fetch_sub) - { - int data[] = { 1, 2, 3, 4 }; - - std::atomic compare(&data[0]); - etl::atomic test(&data[0]); - - CHECK_EQUAL((int*)compare.fetch_add(ptrdiff_t(10)), (int*)test.fetch_add(ptrdiff_t(10))); - } - - //************************************************************************* - TEST(test_atomic_operator_fetch_and) - { - std::atomic compare(0xFFFFFFFFUL); - etl::atomic test(0xFFFFFFFFUL); - - CHECK_EQUAL((int)compare.fetch_and(0x55AA55AAUL), (int)test.fetch_and(0x55AA55AAUL)); - } - - //************************************************************************* - TEST(test_atomic_operator_fetch_or) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - CHECK_EQUAL((int)compare.fetch_or(0x55AA55AAUL), (int)test.fetch_or(0x55AA55AAUL)); - } - - //************************************************************************* - TEST(test_atomic_operator_fetch_xor) - { - std::atomic compare(0x0000FFFFUL); - etl::atomic test(0x0000FFFFUL); - - CHECK_EQUAL((int)compare.fetch_xor(0x55AA55AAUL), (int)test.fetch_xor(0x55AA55AAUL)); - } - - //************************************************************************* - TEST(test_atomic_integer_exchange) - { - std::atomic compare(1); - etl::atomic test(1); - - CHECK_EQUAL((int)compare.exchange(2), (int)test.exchange(2)); - } - - //************************************************************************* - TEST(test_atomic_pointer_exchange) - { - int i; - int j; - - std::atomic compare(&i); - etl::atomic test(&i); - - CHECK_EQUAL((int*)compare.exchange(&j), (int*)test.exchange(&j)); - } - - //************************************************************************* - TEST(test_atomic_compare_exchange_weak_fail) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = 2; - int test_expected = 2; - int desired = 3; - - bool compare_result = compare.compare_exchange_weak(compare_expected, desired); - bool test_result = test.compare_exchange_weak(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //************************************************************************* - TEST(test_atomic_compare_exchange_weak_pass) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = actual; - int test_expected = actual; - int desired = 3; - - bool compare_result = compare.compare_exchange_weak(compare_expected, desired); - bool test_result = test.compare_exchange_weak(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //************************************************************************* - TEST(test_atomic_compare_exchange_strong_fail) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = 2; - int test_expected = 2; - int desired = 3; - - bool compare_result = compare.compare_exchange_strong(compare_expected, desired); - bool test_result = test.compare_exchange_strong(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //************************************************************************* - TEST(test_atomic_compare_exchange_strong_pass) - { - std::atomic compare; - etl::atomic test; - - int actual = 1; - - compare = actual; - test = actual; - - int compare_expected = actual; - int test_expected = actual; - int desired = 3; - - bool compare_result = compare.compare_exchange_strong(compare_expected, desired); - bool test_result = test.compare_exchange_strong(test_expected, desired); - - CHECK_EQUAL(compare_result, test_result); - CHECK_EQUAL(compare_expected, test_expected); - CHECK_EQUAL(compare.load(), test.load()); - } - - //************************************************************************* -#if REALTIME_TEST - -#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported - #define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) - #define FIX_PROCESSOR_AFFINITY1 SetThreadAffinityMask(GetCurrentThread(), 1) - #define FIX_PROCESSOR_AFFINITY2 SetThreadAffinityMask(GetCurrentThread(), 2) -#else - #define RAISE_THREAD_PRIORITY - #define FIX_PROCESSOR_AFFINITY1 - #define FIX_PROCESSOR_AFFINITY2 -#endif - - etl::atomic_int32_t atomic_value = 0U; - etl::atomic start = false; - - void thread1() - { - RAISE_THREAD_PRIORITY; - FIX_PROCESSOR_AFFINITY1; - - while (!start.load()); - - for (int i = 0; i < 10000000; ++i) - { - ++atomic_value; - } - } - - void thread2() - { - RAISE_THREAD_PRIORITY; - FIX_PROCESSOR_AFFINITY2; - - while (!start.load()); - - for (int i = 0; i < 10000000; ++i) - { - --atomic_value; - } - } - - TEST(test_atomic_multi_thread) - { - std::thread t1(thread1); - std::thread t2(thread2); - - start.store(true); - - t1.join(); - t2.join(); - - CHECK_EQUAL(0, atomic_value.load()); - } -#endif - }; -} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index ac4d0cf3..f45c96ac 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -10909,8 +10909,7 @@ - - + @@ -11009,7 +11008,6 @@ - diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index f37e8a61..ec70972c 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1931,15 +1931,6 @@ Tests\Queues - - Tests\Atomic - - - Tests\Atomic - - - Tests\Atomic - Tests\CRC @@ -3254,6 +3245,9 @@ Tests\Sanity Checks\Source + + Tests\Atomic +