mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-28 21:38:44 +08:00
Merge remote-tracking branch 'origin/development'
This commit is contained in:
commit
d84a08e475
@ -31,21 +31,17 @@ SOFTWARE.
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if ETL_ATOMIC_SUPPORTED == 1
|
||||
#include <atomic>
|
||||
|
||||
namespace etl
|
||||
{
|
||||
typedef std::atomic<uint32_t> atomic_uint32_t;
|
||||
}
|
||||
#if ETL_CPP11_SUPPORTED == 1
|
||||
#include "atomic/atomic_std.h"
|
||||
#define ETL_HAS_ATOMIC 1
|
||||
#elif defined(ETL_COMPILER_ARM)
|
||||
#include "atomic/atomic_arm.h"
|
||||
#define ETL_HAS_ATOMIC 1
|
||||
#elif defined(ETL_COMPILER_GCC)
|
||||
#include "atomic/atomic_gcc.h"
|
||||
#elif defined(ETL_COMPILER_MSVC)
|
||||
#include "atomic/atomic_windows.h"
|
||||
#include "atomic/atomic_gcc_sync.h"
|
||||
#define ETL_HAS_ATOMIC 1
|
||||
#else
|
||||
#warning NO ATOMIC SUPPORT DEFINED!
|
||||
#define ETL_HAS_ATOMIC 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -29,6 +29,6 @@ SOFTWARE.
|
||||
#ifndef __ETL_ATOMIC_ARM__
|
||||
#define __ETL_ATOMIC_ARM__
|
||||
|
||||
#include "atomic_gcc.h"
|
||||
#include "atomic_gcc_sync.h"
|
||||
|
||||
#endif
|
||||
|
||||
@ -26,23 +26,37 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_ATOMIC_GCC__
|
||||
#define __ETL_ATOMIC_GCC__
|
||||
#ifndef __ETL_ATOMIC_GCC_SYNC__
|
||||
#define __ETL_ATOMIC_GCC_SYNC__
|
||||
|
||||
#include "../platform.h"
|
||||
#include "../type_traits.h"
|
||||
#include "../char_traits.h"
|
||||
#include "../static_assert.h"
|
||||
#include "../nullptr.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***************************************************************************
|
||||
// Atomic type for pre C++11 GCC compilers that support the builtin 'fetch' functions.
|
||||
// Atomic type for pre C++11 GCC compilers that support the builtin '__sync' functions.
|
||||
// Only integral and pointer types are supported.
|
||||
//***************************************************************************
|
||||
|
||||
typedef enum memory_order
|
||||
{
|
||||
memory_order_relaxed,
|
||||
memory_order_consume,
|
||||
memory_order_acquire,
|
||||
memory_order_release,
|
||||
memory_order_acq_rel,
|
||||
memory_order_seq_cst
|
||||
} memory_order;
|
||||
|
||||
template <typename T>
|
||||
class atomic
|
||||
{
|
||||
@ -63,14 +77,14 @@ namespace etl
|
||||
// Assignment
|
||||
T operator =(T v)
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
store(v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
T operator =(T v) volatile
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
store(v);
|
||||
|
||||
return v;
|
||||
}
|
||||
@ -177,12 +191,12 @@ namespace etl
|
||||
// Conversion operator
|
||||
operator T () const
|
||||
{
|
||||
return __sync_fetch_and_add(const_cast<T*>(&value), 0);
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
operator T() volatile const
|
||||
{
|
||||
return __sync_fetch_and_add(const_cast<T*>(&value), 0);
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
// Is lock free?
|
||||
@ -197,95 +211,95 @@ namespace etl
|
||||
}
|
||||
|
||||
// Store
|
||||
void store(T v)
|
||||
void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
void store(T v) volatile
|
||||
void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
// Load
|
||||
T load()
|
||||
T load(etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
T load() volatile
|
||||
T load(etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
// Fetch add
|
||||
T fetch_add(T v)
|
||||
T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_add(&value, v);
|
||||
}
|
||||
|
||||
T fetch_add(T v) volatile
|
||||
T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_add(&value, v);
|
||||
}
|
||||
|
||||
// Fetch subtract
|
||||
T fetch_sub(T v)
|
||||
T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_sub(&value, v);
|
||||
}
|
||||
|
||||
T fetch_sub(T v) volatile
|
||||
T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_sub(&value, v);
|
||||
}
|
||||
|
||||
// Fetch or
|
||||
T fetch_or(T v)
|
||||
T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_or(&value, v);
|
||||
}
|
||||
|
||||
T fetch_or(T v) volatile
|
||||
T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_or(&value, v);
|
||||
}
|
||||
|
||||
// Fetch and
|
||||
T fetch_and(T v)
|
||||
T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_and(&value, v);
|
||||
}
|
||||
|
||||
T fetch_and(T v) volatile
|
||||
T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_and(&value, v);
|
||||
}
|
||||
|
||||
// Fetch exclusive or
|
||||
T fetch_xor(T v)
|
||||
T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_xor(&value, v);
|
||||
}
|
||||
|
||||
T fetch_xor(T v) volatile
|
||||
T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_xor(&value, v);
|
||||
}
|
||||
|
||||
// Exchange
|
||||
T exchange(T v)
|
||||
T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
T exchange(T v) volatile
|
||||
T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
// Compare exchange weak
|
||||
bool compare_exchange_weak(T& expected, T desired)
|
||||
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
T old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
@ -300,7 +314,37 @@ namespace etl
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T& expected, T desired) volatile
|
||||
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
T old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
if (old == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
|
||||
{
|
||||
T old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
if (old == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
|
||||
{
|
||||
T old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
@ -316,7 +360,7 @@ namespace etl
|
||||
}
|
||||
|
||||
// Compare exchange strong
|
||||
bool compare_exchange_strong(T& expected, T desired)
|
||||
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
T old = expected;
|
||||
|
||||
@ -332,7 +376,39 @@ namespace etl
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T& expected, T desired) volatile
|
||||
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
T old = expected;
|
||||
|
||||
while (!compare_exchange_weak(old, desired))
|
||||
{
|
||||
if (memcmp(&old, &expected, sizeof(T)))
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
|
||||
{
|
||||
T old = expected;
|
||||
|
||||
while (!compare_exchange_weak(old, desired))
|
||||
{
|
||||
if (memcmp(&old, &expected, sizeof(T)))
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
|
||||
{
|
||||
T old = expected;
|
||||
|
||||
@ -353,12 +429,9 @@ namespace etl
|
||||
atomic& operator =(const atomic&);
|
||||
atomic& operator =(const atomic&) volatile;
|
||||
|
||||
T value;
|
||||
volatile T value;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
// Specialisation for pointers.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
class atomic<T*>
|
||||
{
|
||||
@ -369,66 +442,66 @@ namespace etl
|
||||
{
|
||||
}
|
||||
|
||||
atomic(T v)
|
||||
atomic(T* v)
|
||||
: value(v)
|
||||
{
|
||||
}
|
||||
|
||||
// Assignment
|
||||
T operator =(T* v)
|
||||
T* operator =(T* v)
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
store(v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
T operator =(T* v) volatile
|
||||
T* operator =(T* v) volatile
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
store(v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
// Pre-increment
|
||||
T operator ++()
|
||||
T* operator ++()
|
||||
{
|
||||
return fetch_add(1) + 1;
|
||||
}
|
||||
|
||||
T operator ++() volatile
|
||||
T* operator ++() volatile
|
||||
{
|
||||
return fetch_add(1) + 1;
|
||||
}
|
||||
|
||||
// Post-increment
|
||||
T operator ++(int)
|
||||
T* operator ++(int)
|
||||
{
|
||||
return fetch_add(1);
|
||||
}
|
||||
|
||||
T operator ++(int) volatile
|
||||
T* operator ++(int) volatile
|
||||
{
|
||||
return fetch_add(1);
|
||||
}
|
||||
|
||||
// Pre-decrement
|
||||
T operator --()
|
||||
T* operator --()
|
||||
{
|
||||
return fetch_sub(1) + 1;
|
||||
}
|
||||
|
||||
T operator --() volatile
|
||||
T* operator --() volatile
|
||||
{
|
||||
return fetch_sub(1) + 1;
|
||||
}
|
||||
|
||||
// Post-decrement
|
||||
T operator --(int)
|
||||
T* operator --(int)
|
||||
{
|
||||
return fetch_sub(1);
|
||||
}
|
||||
|
||||
T operator --(int) volatile
|
||||
T* operator --(int) volatile
|
||||
{
|
||||
return fetch_sub(1);
|
||||
}
|
||||
@ -456,14 +529,14 @@ namespace etl
|
||||
}
|
||||
|
||||
// Conversion operator
|
||||
operator T () const
|
||||
operator T* () const
|
||||
{
|
||||
return __sync_fetch_and_add(const_cast<T**>(&value), 0);
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
operator T() volatile const
|
||||
operator T*() volatile const
|
||||
{
|
||||
return __sync_fetch_and_add(const_cast<T**>(&value), 0);
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
// Is lock free?
|
||||
@ -478,79 +551,129 @@ namespace etl
|
||||
}
|
||||
|
||||
// Store
|
||||
void store(T v)
|
||||
void store(T* v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
void store(T v) volatile
|
||||
void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
__sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
// Load
|
||||
T load()
|
||||
T* load(etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
T load() volatile
|
||||
T* load(etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_add(&value, 0);
|
||||
}
|
||||
|
||||
// Fetch add
|
||||
T* fetch_add(std::ptrdiff_t v)
|
||||
T* fetch_add(std::ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_add(&value, v);
|
||||
}
|
||||
|
||||
T* fetch_add(std::ptrdiff_t v) volatile
|
||||
T* fetch_add(std::ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_add(&value, v);
|
||||
}
|
||||
|
||||
// Fetch subtract
|
||||
T* fetch_sub(std::ptrdiff_t v)
|
||||
T* fetch_sub(std::ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_fetch_and_sub(&value, v);
|
||||
}
|
||||
|
||||
T* fetch_sub(std::ptrdiff_t v) volatile
|
||||
T* fetch_sub(std::ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_fetch_and_sub(&value, v);
|
||||
}
|
||||
|
||||
// Exchange
|
||||
T exchange(T v)
|
||||
T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
T exchange(T v) volatile
|
||||
T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_lock_test_and_set(&value, v);
|
||||
}
|
||||
|
||||
// Compare exchange weak
|
||||
bool compare_exchange_weak(T& expected, T desired)
|
||||
bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return __sync_bool_compare_and_swap(&value, expected, desired);
|
||||
T* old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
if (old == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T& expected, T desired) volatile
|
||||
bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return __sync_bool_compare_and_swap(&value, expected, desired);
|
||||
T* old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
if (old == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure)
|
||||
{
|
||||
T* old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
if (old == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile
|
||||
{
|
||||
T* old = __sync_val_compare_and_swap(&value, expected, desired);
|
||||
|
||||
if (old == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare exchange strong
|
||||
bool compare_exchange_strong(T& expected, T desired)
|
||||
bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
T old = expected;
|
||||
T* old = expected;
|
||||
|
||||
while (!compare_exchange_weak(old, desired))
|
||||
{
|
||||
if (memcmp(&old, &expected, sizeof(T)))
|
||||
if (memcmp(&old, &expected, sizeof(T*)))
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
@ -560,13 +683,45 @@ namespace etl
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T& expected, T desired) volatile
|
||||
bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
T old = expected;
|
||||
T* old = expected;
|
||||
|
||||
while (!compare_exchange_weak(old, desired))
|
||||
{
|
||||
if (memcmp(&old, &expected, sizeof(T)))
|
||||
if (memcmp(&old, &expected, sizeof(T*)))
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure)
|
||||
{
|
||||
T* old = expected;
|
||||
|
||||
while (!compare_exchange_weak(old, desired))
|
||||
{
|
||||
if (memcmp(&old, &expected, sizeof(T*)))
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile
|
||||
{
|
||||
T* old = expected;
|
||||
|
||||
while (!compare_exchange_weak(old, desired))
|
||||
{
|
||||
if (memcmp(&old, &expected, sizeof(T*)))
|
||||
{
|
||||
expected = old;
|
||||
return false;
|
||||
@ -581,7 +736,7 @@ namespace etl
|
||||
atomic& operator =(const atomic&);
|
||||
atomic& operator =(const atomic&) volatile;
|
||||
|
||||
T* value;
|
||||
volatile T* value;
|
||||
};
|
||||
|
||||
typedef etl::atomic<char> atomic_char;
|
||||
@ -630,4 +785,6 @@ namespace etl
|
||||
typedef etl::atomic<uintmax_t> atomic_uintmax_t;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif
|
||||
604
include/etl/atomic/atomic_std.h
Normal file
604
include/etl/atomic/atomic_std.h
Normal file
@ -0,0 +1,604 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_ATOMIC_STD__
|
||||
#define __ETL_ATOMIC_STD__
|
||||
|
||||
#include "../platform.h"
|
||||
#include "../nullptr.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***************************************************************************
|
||||
// ETL Atomic type for compilers that support std::atomic.
|
||||
// etl::atomic is a simple wrapper around std::atomic.
|
||||
//***************************************************************************
|
||||
|
||||
typedef std::memory_order memory_order;
|
||||
|
||||
static const etl::memory_order memory_order_relaxed = std::memory_order_relaxed;
|
||||
static const etl::memory_order memory_order_consume = std::memory_order_consume;
|
||||
static const etl::memory_order memory_order_acquire = std::memory_order_acquire;
|
||||
static const etl::memory_order memory_order_release = std::memory_order_release;
|
||||
static const etl::memory_order memory_order_acq_rel = std::memory_order_acq_rel;
|
||||
static const etl::memory_order memory_order_seq_cst = std::memory_order_seq_cst;
|
||||
|
||||
template <typename T>
|
||||
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)
|
||||
{
|
||||
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(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<T> value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class atomic<T*>
|
||||
{
|
||||
public:
|
||||
|
||||
atomic()
|
||||
: value(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 +=(std::ptrdiff_t v)
|
||||
{
|
||||
return value += v;
|
||||
}
|
||||
|
||||
T* operator +=(std::ptrdiff_t v) volatile
|
||||
{
|
||||
return value += v;
|
||||
}
|
||||
|
||||
// Subtract
|
||||
T* operator -=(std::ptrdiff_t v)
|
||||
{
|
||||
return value -= v;
|
||||
}
|
||||
|
||||
T* operator -=(std::ptrdiff_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)
|
||||
{
|
||||
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(std::ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return value.fetch_add(v, order);
|
||||
}
|
||||
|
||||
T* fetch_add(std::ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile
|
||||
{
|
||||
return value.fetch_add(v, order);
|
||||
}
|
||||
|
||||
// Fetch subtract
|
||||
T* fetch_sub(std::ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
|
||||
{
|
||||
return value.fetch_sub(v, order);
|
||||
}
|
||||
|
||||
T* fetch_sub(std::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&);
|
||||
//atomic& operator =(const atomic&) volatile;
|
||||
|
||||
std::atomic<T*> value;
|
||||
};
|
||||
|
||||
typedef std::atomic<char> atomic_char;
|
||||
typedef std::atomic<signed char> atomic_schar;
|
||||
typedef std::atomic<unsigned char> atomic_uchar;
|
||||
typedef std::atomic<short> atomic_short;
|
||||
typedef std::atomic<unsigned short> atomic_ushort;
|
||||
typedef std::atomic<int> atomic_int;
|
||||
typedef std::atomic<unsigned int> atomic_uint;
|
||||
typedef std::atomic<long> atomic_long;
|
||||
typedef std::atomic<unsigned long> atomic_ulong;
|
||||
typedef std::atomic<long long> atomic_llong;
|
||||
typedef std::atomic<unsigned long long> atomic_ullong;
|
||||
typedef std::atomic<wchar_t> atomic_wchar_t;
|
||||
typedef std::atomic<char16_t> atomic_char16_t;
|
||||
typedef std::atomic<char32_t> atomic_char32_t;
|
||||
typedef std::atomic<uint8_t> atomic_uint8_t;
|
||||
typedef std::atomic<int8_t> atomic_int8_t;
|
||||
typedef std::atomic<uint16_t> atomic_uint16_t;
|
||||
typedef std::atomic<int16_t> atomic_int16_t;
|
||||
typedef std::atomic<uint32_t> atomic_uint32_t;
|
||||
typedef std::atomic<int32_t> atomic_int32_t;
|
||||
typedef std::atomic<uint64_t> atomic_uint64_t;
|
||||
typedef std::atomic<int64_t> atomic_int64_t;
|
||||
typedef std::atomic<int_least8_t> atomic_int_least8_t;
|
||||
typedef std::atomic<uint_least8_t> atomic_uint_least8_t;
|
||||
typedef std::atomic<int_least16_t> atomic_int_least16_t;
|
||||
typedef std::atomic<uint_least16_t> atomic_uint_least16_t;
|
||||
typedef std::atomic<int_least32_t> atomic_int_least32_t;
|
||||
typedef std::atomic<uint_least32_t> atomic_uint_least32_t;
|
||||
typedef std::atomic<int_least64_t> atomic_int_least64_t;
|
||||
typedef std::atomic<uint_least64_t> atomic_uint_least64_t;
|
||||
typedef std::atomic<int_fast8_t> atomic_int_fast8_t;
|
||||
typedef std::atomic<uint_fast8_t> atomic_uint_fast8_t;
|
||||
typedef std::atomic<int_fast16_t> atomic_int_fast16_t;
|
||||
typedef std::atomic<uint_fast16_t> atomic_uint_fast16_t;
|
||||
typedef std::atomic<int_fast32_t> atomic_int_fast32_t;
|
||||
typedef std::atomic<uint_fast32_t> atomic_uint_fast32_t;
|
||||
typedef std::atomic<int_fast64_t> atomic_int_fast64_t;
|
||||
typedef std::atomic<uint_fast64_t> atomic_uint_fast64_t;
|
||||
typedef std::atomic<intptr_t> atomic_intptr_t;
|
||||
typedef std::atomic<uintptr_t> atomic_uintptr_t;
|
||||
typedef std::atomic<size_t> atomic_size_t;
|
||||
typedef std::atomic<ptrdiff_t> atomic_ptrdiff_t;
|
||||
typedef std::atomic<intmax_t> atomic_intmax_t;
|
||||
typedef std::atomic<uintmax_t> atomic_uintmax_t;
|
||||
};
|
||||
|
||||
#endif
|
||||
55
include/etl/combinations.h
Normal file
55
include/etl/combinations.h
Normal file
@ -0,0 +1,55 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_COMBINATIONS__
|
||||
#define __ETL_COMBINATIONS__
|
||||
|
||||
#include "platform.h"
|
||||
#include "permutations.h"
|
||||
#include "factorial.h"
|
||||
|
||||
///\defgroup combinations combinations
|
||||
/// combinations<N, K> : Calculates K combinations from N.
|
||||
///\ingroup maths
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***************************************************************************
|
||||
///\ingroup combinations
|
||||
/// Calculates combinations.
|
||||
//***************************************************************************
|
||||
template <const size_t NV, const size_t KV>
|
||||
struct combinations
|
||||
{
|
||||
static const size_t value = etl::permutations<NV, KV>::value / etl::factorial<KV>::value;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,57 +0,0 @@
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "atomic.h"
|
||||
|
||||
struct spsc_queue_implementation
|
||||
{
|
||||
enum
|
||||
{
|
||||
UNKNOWN,
|
||||
STD_ATOMIC,
|
||||
ETL_ATOMIC,
|
||||
CMSIS_RTOS2,
|
||||
FREERTOS,
|
||||
GCC,
|
||||
WIN32
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, const size_t IMPLEMENTATION = spsc_queue_implementation::UNKNOWN>
|
||||
class ispsc_queue;
|
||||
|
||||
template <typename T, const size_t SIZE, const size_t IMPLEMENTATION = spsc_queue_implementation::UNKNOWN>
|
||||
class spsc_queue : public ispsc_queue;
|
||||
|
||||
#if ETL_ATOMIC_AVAILABLE
|
||||
template <typename T>
|
||||
class ispsc_queue<T, spsc_queue_implementation::STD_ATOMIC>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
template <typename T, const size_t SIZE>
|
||||
class spsc_queue<T, SIZE, spsc_queue_implementation::STD_ATOMIC>
|
||||
: public ispsc_queue<T, spsc_queue_implementation::STD_ATOMIC>
|
||||
{
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#if ETL_OPERATING_SYSTEM == ETL_CMSIS_RTOS2
|
||||
template <typename T, const size_t SIZE>
|
||||
class spsc_queue<T, SIZE, spsc_queue_implementation::CMSIS_RTOS2>
|
||||
: public ispsc_queue<T, spsc_queue_implementation::CMSIS_RTOS2>
|
||||
{
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#if ETL_OPERATING_SYSTEM == ETL_FREERTOS
|
||||
template <typename T, const size_t SIZE>
|
||||
class spsc_queue<T, SIZE, spsc_queue_implementation::FREERTOS>
|
||||
: public ispsc_queue<T, spsc_queue_implementation::FREERTOS>
|
||||
{
|
||||
|
||||
};
|
||||
#endif
|
||||
@ -42,4 +42,7 @@
|
||||
42 string_view
|
||||
43 callback_timer
|
||||
44 message_timer
|
||||
45 type_lookup
|
||||
45 type_lookup
|
||||
46 queue_spsc_isr
|
||||
47 queue_spsc_atomic
|
||||
48 queue_mpmc_mutex
|
||||
|
||||
47
include/etl/mutex.h
Normal file
47
include/etl/mutex.h
Normal file
@ -0,0 +1,47 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_MUTEX__
|
||||
#define __ETL_MUTEX__
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if ETL_CPP11_SUPPORTED == 1
|
||||
#include "mutex/mutex_std.h"
|
||||
#define ETL_HAS_MUTEX 1
|
||||
#elif defined(ETL_COMPILER_ARM)
|
||||
#include "mutex/mutex_arm.h"
|
||||
#define ETL_HAS_MUTEX 1
|
||||
#elif defined(ETL_COMPILER_GCC)
|
||||
#include "mutex/mutex_gcc_sync.h"
|
||||
#define ETL_HAS_MUTEX 1
|
||||
#else
|
||||
#define ETL_HAS_MUTEX 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
34
include/etl/mutex/mutex_arm.h
Normal file
34
include/etl/mutex/mutex_arm.h
Normal file
@ -0,0 +1,34 @@
|
||||
/******************************************************************************
|
||||
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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_MUTEX_ARM__
|
||||
#define __ETL_MUTEX_ARM__
|
||||
|
||||
#include "mutex_gcc_sync.h"
|
||||
|
||||
#endif
|
||||
@ -26,78 +26,51 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_ATOMIC_WINDOWS__
|
||||
#define __ETL_ATOMIC_WINDOWS__
|
||||
#ifndef __ETL_MUTEX_GCC_SYNC__
|
||||
#define __ETL_MUTEX_GCC_SYNC__
|
||||
|
||||
#include "../platform.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace etl
|
||||
{
|
||||
class atomic_uint32_t
|
||||
//***************************************************************************
|
||||
///\ingroup mutex
|
||||
///\brief This mutex class is implemented using GCC's __sync functions.
|
||||
//***************************************************************************
|
||||
class mutex
|
||||
{
|
||||
public:
|
||||
|
||||
atomic_uint32_t()
|
||||
mutex()
|
||||
: flag(0)
|
||||
{
|
||||
InterlockedExchange(&value, 0);
|
||||
__sync_lock_release(flag);
|
||||
}
|
||||
|
||||
atomic_uint32_t(uint32_t v)
|
||||
void lock()
|
||||
{
|
||||
InterlockedExchange(&value, v);
|
||||
while (__sync_lock_test_and_set(&flag, 1U))
|
||||
{
|
||||
while (flag)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
atomic_uint32_t& operator =(uint32_t v)
|
||||
bool try_lock()
|
||||
{
|
||||
InterlockedExchange(&value, v);
|
||||
|
||||
return *this;
|
||||
return (__sync_lock_test_and_set(&flag, 1U) == 1U);
|
||||
}
|
||||
|
||||
atomic_uint32_t& operator ++()
|
||||
void unlock()
|
||||
{
|
||||
InterlockedIncrement(&value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
volatile atomic_uint32_t& operator ++() volatile
|
||||
{
|
||||
InterlockedIncrement(&value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
atomic_uint32_t& operator --()
|
||||
{
|
||||
InterlockedDecrement(&value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
volatile atomic_uint32_t& operator --() volatile
|
||||
{
|
||||
InterlockedDecrement(&value);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator uint32_t () const
|
||||
{
|
||||
return InterlockedAdd((volatile long*)&value, 0);
|
||||
}
|
||||
|
||||
operator uint32_t() volatile const
|
||||
{
|
||||
return InterlockedAdd((volatile long*)&value, 0);
|
||||
__sync_lock_release(flag);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint32_t value;
|
||||
volatile uint32_t flag;
|
||||
};
|
||||
}
|
||||
|
||||
72
include/etl/mutex/mutex_std.h
Normal file
72
include/etl/mutex/mutex_std.h
Normal file
@ -0,0 +1,72 @@
|
||||
/******************************************************************************
|
||||
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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_MUTEX_STD__
|
||||
#define __ETL_MUTEX_STD__
|
||||
|
||||
#include "../platform.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
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:
|
||||
|
||||
std::mutex access;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
63
include/etl/permutations.h
Normal file
63
include/etl/permutations.h
Normal file
@ -0,0 +1,63 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_PERMUTATIONS__
|
||||
#define __ETL_PERMUTATIONS__
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
///\defgroup permutations permutations
|
||||
/// permutations<N, K> : Calculates K permutations from N.
|
||||
///\ingroup maths
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***************************************************************************
|
||||
///\ingroup permutations
|
||||
/// Calculates permutaions.
|
||||
//***************************************************************************
|
||||
template <const size_t NV, const size_t KV>
|
||||
struct permutations
|
||||
{
|
||||
static const size_t value = NV * permutations<NV - 1, KV - 1>::value;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Calculates permutations.
|
||||
/// Specialisation for KV == 0.
|
||||
//***************************************************************************
|
||||
template <const size_t NV>
|
||||
struct permutations<NV, 0>
|
||||
{
|
||||
static const size_t value = 1;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -51,7 +51,7 @@ SOFTWARE.
|
||||
#undef ETL_NO_NULLPTR_SUPPORT
|
||||
#undef ETL_NO_LARGE_CHAR_SUPPORT
|
||||
#undef ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
|
||||
#undef ETL_ATOMIC_SUPPORTED
|
||||
#undef ETL_STD_ATOMIC_SUPPORTED
|
||||
|
||||
// Determine the bit width of the platform.
|
||||
#define ETL_PLATFORM_16BIT (UINT16_MAX == UINTPTR_MAX)
|
||||
@ -67,6 +67,10 @@ SOFTWARE.
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
#if defined(ETL_COMPILER_GCC)
|
||||
#define GCC_VERSION ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
#define ETL_CONSTEXPR constexpr
|
||||
#else
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT 1
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT 1
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
|
||||
#define ETL_ATOMIC_SUPPORTED 0
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT 1
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT 1
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
|
||||
#define ETL_ATOMIC_SUPPORTED 0
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT 0
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT 0
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1
|
||||
#define ETL_ATOMIC_SUPPORTED 1
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT 1
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT 1
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
|
||||
#define ETL_ATOMIC_SUPPORTED 0
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT 0
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT 0
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1
|
||||
#define ETL_ATOMIC_SUPPORTED 1
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT 0
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT 0
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1
|
||||
#define ETL_ATOMIC_SUPPORTED 1
|
||||
|
||||
#endif
|
||||
|
||||
@ -52,6 +52,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
|
||||
#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED
|
||||
|
||||
#endif
|
||||
|
||||
@ -52,6 +52,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
|
||||
#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED
|
||||
|
||||
#endif
|
||||
|
||||
@ -52,6 +52,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
|
||||
#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED
|
||||
#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED
|
||||
|
||||
#endif
|
||||
|
||||
@ -46,6 +46,5 @@ SOFTWARE.
|
||||
#define ETL_NO_NULLPTR_SUPPORT 1
|
||||
#define ETL_NO_LARGE_CHAR_SUPPORT 1
|
||||
#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0
|
||||
#define ETL_ATOMIC_SUPPORTED 0
|
||||
|
||||
#endif
|
||||
|
||||
376
include/etl/queue_mpmc_mutex.h
Normal file
376
include/etl/queue_mpmc_mutex.h
Normal file
@ -0,0 +1,376 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_MPMC_QUEUE_MUTEX__
|
||||
#define __ETL_MPMC_QUEUE_MUTEX__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "alignment.h"
|
||||
#include "parameter_type.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#undef ETL_FILE
|
||||
#define ETL_FILE "48"
|
||||
|
||||
namespace etl
|
||||
{
|
||||
class queue_mpmc_mutex_base
|
||||
{
|
||||
public:
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_t capacity() const
|
||||
{
|
||||
return MAX_SIZE;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_t max_size() const
|
||||
{
|
||||
return MAX_SIZE;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
queue_mpmc_mutex_base(size_t max_size_)
|
||||
: write_index(0),
|
||||
read_index(0),
|
||||
current_size(0),
|
||||
MAX_SIZE(max_size_)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Calculate the next index.
|
||||
//*************************************************************************
|
||||
static size_t get_next_index(size_t index, size_t maximum)
|
||||
{
|
||||
++index;
|
||||
|
||||
if (index == maximum)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
size_t write_index; ///< Where to input new data.
|
||||
size_t read_index; ///< Where to get the oldest data.
|
||||
size_t current_size; ///< The current size of the queue.
|
||||
const size_t MAX_SIZE; ///< The maximum number of items in the queue.
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
#if defined(ETL_POLYMORPHIC_MPMC_QUEUE_MUTEX) || defined(ETL_POLYMORPHIC_CONTAINERS)
|
||||
public:
|
||||
virtual ~queue_mpmc_mutex_base()
|
||||
{
|
||||
}
|
||||
#else
|
||||
protected:
|
||||
~queue_mpmc_mutex_base()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\ingroup queue_mpmc
|
||||
///\brief This is the base for all queue_mpmc_mutexs that contain a particular type.
|
||||
///\details Normally a reference to this type will be taken from a derived queue_mpmc_mutex.
|
||||
///\code
|
||||
/// etl::queue_mpmc_mutex<int, 10> myQueue;
|
||||
/// etl::iqueue_mpmc_mutex<int>& iQueue = myQueue;
|
||||
///\endcode
|
||||
/// This queue supports concurrent access by one producer and one consumer.
|
||||
/// \tparam T The type of value that the queue_mpmc_mutex holds.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
class iqueue_mpmc_mutex : public queue_mpmc_mutex_base
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef typename etl::parameter_type<T>::type parameter_t;
|
||||
|
||||
public:
|
||||
|
||||
typedef T value_type; ///< The type stored in the queue.
|
||||
typedef T& reference; ///< A reference to the type used in the queue.
|
||||
typedef const T& const_reference; ///< A const reference to the type used in the queue.
|
||||
typedef size_t size_type; ///< The type used for determining the size of the queue.
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push(parameter_t value)
|
||||
{
|
||||
access.lock();
|
||||
|
||||
bool result = push_implementation(value);
|
||||
|
||||
access.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop(reference value)
|
||||
{
|
||||
access.lock();
|
||||
|
||||
bool result = pop_implementation(value);
|
||||
|
||||
access.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue and discard.
|
||||
//*************************************************************************
|
||||
bool pop()
|
||||
{
|
||||
access.lock();
|
||||
|
||||
bool result = pop_implementation();
|
||||
|
||||
access.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Clear the queue.
|
||||
//*************************************************************************
|
||||
void clear()
|
||||
{
|
||||
access.lock();
|
||||
|
||||
while (pop_implementation())
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
access.unlock();
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue empty?
|
||||
//*************************************************************************
|
||||
bool empty() const
|
||||
{
|
||||
access.lock();
|
||||
|
||||
size_t result = (current_size == 0);
|
||||
|
||||
access.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue full?
|
||||
//*************************************************************************
|
||||
bool full() const
|
||||
{
|
||||
access.lock();
|
||||
|
||||
size_t result = (current_size == MAX_SIZE);
|
||||
|
||||
access.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items in the queue?
|
||||
//*************************************************************************
|
||||
size_t size() const
|
||||
{
|
||||
access.lock();
|
||||
|
||||
size_t result = current_size;
|
||||
|
||||
access.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How much free space available in the queue.
|
||||
//*************************************************************************
|
||||
size_t available() const
|
||||
{
|
||||
access.lock();
|
||||
|
||||
size_t result = MAX_SIZE - current_size;
|
||||
|
||||
access.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//*************************************************************************
|
||||
/// The constructor that is called from derived classes.
|
||||
//*************************************************************************
|
||||
iqueue_mpmc_mutex(T* p_buffer_, size_type max_size_)
|
||||
: queue_mpmc_mutex_base(max_size_),
|
||||
p_buffer(p_buffer_)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push_implementation(parameter_t value)
|
||||
{
|
||||
if (current_size != MAX_SIZE)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value);
|
||||
|
||||
write_index = get_next_index(write_index, MAX_SIZE);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop_implementation(reference value)
|
||||
{
|
||||
if (current_size == 0)
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
value = p_buffer[read_index];
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read_index = get_next_index(read_index, MAX_SIZE);;
|
||||
|
||||
--current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue and discard.
|
||||
//*************************************************************************
|
||||
bool pop_implementation()
|
||||
{
|
||||
if (current_size == 0)
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read_index = get_next_index(read_index, MAX_SIZE);
|
||||
|
||||
--current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable copy construction and assignment.
|
||||
iqueue_mpmc_mutex(const iqueue_mpmc_mutex&);
|
||||
iqueue_mpmc_mutex& operator =(const iqueue_mpmc_mutex&);
|
||||
|
||||
T* p_buffer; ///< The internal buffer.
|
||||
|
||||
mutable etl::mutex access; ///< The object that locks/unlocks access.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\ingroup queue_mpmc
|
||||
/// A fixed capacity mpmc queue.
|
||||
/// This queue supports concurrent access by one producer and one consumer.
|
||||
/// \tparam T The type this queue should support.
|
||||
/// \tparam SIZE The maximum capacity of the queue.
|
||||
//***************************************************************************
|
||||
template <typename T, size_t SIZE>
|
||||
class queue_mpmc_mutex : public etl::iqueue_mpmc_mutex<T>
|
||||
{
|
||||
typedef etl::iqueue_mpmc_mutex<T> base_t;
|
||||
|
||||
public:
|
||||
|
||||
static const size_t MAX_SIZE = SIZE;
|
||||
|
||||
//*************************************************************************
|
||||
/// Default constructor.
|
||||
//*************************************************************************
|
||||
queue_mpmc_mutex()
|
||||
: base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
~queue_mpmc_mutex()
|
||||
{
|
||||
base_t::clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
queue_mpmc_mutex(const queue_mpmc_mutex&);
|
||||
queue_mpmc_mutex& operator = (const queue_mpmc_mutex&);
|
||||
|
||||
/// The uninitialised buffer of T used in the queue_mpmc_mutex.
|
||||
typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
332
include/etl/queue_spsc_atomic.h
Normal file
332
include/etl/queue_spsc_atomic.h
Normal file
@ -0,0 +1,332 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_SPSC_QUEUE_ATOMIC__
|
||||
#define __ETL_SPSC_QUEUE_ATOMIC__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "alignment.h"
|
||||
#include "parameter_type.h"
|
||||
#include "atomic.h"
|
||||
|
||||
#undef ETL_FILE
|
||||
#define ETL_FILE "47"
|
||||
|
||||
namespace etl
|
||||
{
|
||||
class queue_spsc_atomic_base
|
||||
{
|
||||
public:
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue empty?
|
||||
/// Accurate from the 'pop' thread.
|
||||
/// 'Not empty' is a guess from the 'push' thread.
|
||||
//*************************************************************************
|
||||
bool empty() const
|
||||
{
|
||||
return read.load(etl::memory_order_acquire) == write.load(etl::memory_order_acquire);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue full?
|
||||
/// Accurate from the 'push' thread.
|
||||
/// 'Not full' is a guess from the 'pop' thread.
|
||||
//*************************************************************************
|
||||
bool full() const
|
||||
{
|
||||
size_t next_index = get_next_index(write.load(etl::memory_order_acquire), RESERVED);
|
||||
|
||||
return (next_index == read.load(etl::memory_order_acquire));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items in the queue?
|
||||
/// Due to concurrency, this is a guess.
|
||||
//*************************************************************************
|
||||
size_t size() const
|
||||
{
|
||||
size_t write_index = write.load(etl::memory_order_acquire);
|
||||
size_t read_index = read.load(etl::memory_order_acquire);
|
||||
|
||||
size_t n;
|
||||
|
||||
if (write_index >= read_index)
|
||||
{
|
||||
n = write_index - read_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
n = RESERVED - read_index + write_index - 1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How much free space available in the queue.
|
||||
/// Due to concurrency, this is a guess.
|
||||
//*************************************************************************
|
||||
size_t available() const
|
||||
{
|
||||
return RESERVED - size() - 1;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_t capacity() const
|
||||
{
|
||||
return RESERVED - 1;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_t max_size() const
|
||||
{
|
||||
return RESERVED - 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
queue_spsc_atomic_base(size_t reserved_)
|
||||
: write(0),
|
||||
read(0),
|
||||
RESERVED(reserved_)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Calculate the next index.
|
||||
//*************************************************************************
|
||||
static size_t get_next_index(size_t index, size_t maximum)
|
||||
{
|
||||
++index;
|
||||
|
||||
if (index == maximum)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
etl::atomic_size_t write; ///< Where to input new data.
|
||||
etl::atomic_size_t read; ///< Where to get the oldest data.
|
||||
const size_t RESERVED; ///< The maximum number of items in the queue.
|
||||
|
||||
private:
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
#if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ATOMIC) || defined(ETL_POLYMORPHIC_CONTAINERS)
|
||||
public:
|
||||
virtual ~queue_spsc_atomic_base()
|
||||
{
|
||||
}
|
||||
#else
|
||||
protected:
|
||||
~queue_spsc_atomic_base()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\ingroup queue_spsc_atomic
|
||||
///\brief This is the base for all queue_spscs that contain a particular type.
|
||||
///\details Normally a reference to this type will be taken from a derived queue_spsc.
|
||||
///\code
|
||||
/// etl::queue_spsc_atomic<int, 10> myQueue;
|
||||
/// etl::iqueue_spsc_atomic<int>& iQueue = myQueue;
|
||||
///\endcode
|
||||
/// This queue supports concurrent access by one producer and one consumer.
|
||||
/// \tparam T The type of value that the queue_spsc_atomic holds.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
class iqueue_spsc_atomic : public queue_spsc_atomic_base
|
||||
{
|
||||
private:
|
||||
|
||||
typedef typename etl::parameter_type<T>::type parameter_t;
|
||||
|
||||
public:
|
||||
|
||||
typedef T value_type; ///< The type stored in the queue.
|
||||
typedef T& reference; ///< A reference to the type used in the queue.
|
||||
typedef const T& const_reference; ///< A const reference to the type used in the queue.
|
||||
typedef size_t size_type; ///< The type used for determining the size of the queue.
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push(parameter_t value)
|
||||
{
|
||||
size_t write_index = write.load(etl::memory_order_relaxed);
|
||||
size_t next_index = get_next_index(write_index, RESERVED);
|
||||
|
||||
if (next_index != read.load(etl::memory_order_acquire))
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value);
|
||||
|
||||
write.store(next_index, etl::memory_order_release);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop(reference value)
|
||||
{
|
||||
size_t read_index = read.load(etl::memory_order_relaxed);
|
||||
|
||||
if (read_index == write.load(etl::memory_order_acquire))
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t next_index = get_next_index(read_index, RESERVED);
|
||||
|
||||
value = p_buffer[read_index];
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read.store(next_index, etl::memory_order_release);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue and discard.
|
||||
//*************************************************************************
|
||||
bool pop()
|
||||
{
|
||||
size_t read_index = read.load(etl::memory_order_relaxed);
|
||||
|
||||
if (read_index == write.load(etl::memory_order_acquire))
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t next_index = get_next_index(read_index, RESERVED);
|
||||
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read.store(next_index, etl::memory_order_release);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Clear the queue.
|
||||
/// Must be called from thread that pops the queue or when there is no
|
||||
/// possibility of concurrent access.
|
||||
//*************************************************************************
|
||||
void clear()
|
||||
{
|
||||
while (pop())
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//*************************************************************************
|
||||
/// The constructor that is called from derived classes.
|
||||
//*************************************************************************
|
||||
iqueue_spsc_atomic(T* p_buffer_, size_type reserved_)
|
||||
: queue_spsc_atomic_base(reserved_),
|
||||
p_buffer(p_buffer_)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Disable copy construction and assignment.
|
||||
iqueue_spsc_atomic(const iqueue_spsc_atomic&);
|
||||
iqueue_spsc_atomic& operator =(const iqueue_spsc_atomic&);
|
||||
|
||||
T* p_buffer; ///< The internal buffer.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\ingroup queue_spsc
|
||||
/// A fixed capacity spsc queue.
|
||||
/// This queue supports concurrent access by one producer and one consumer.
|
||||
/// \tparam T The type this queue should support.
|
||||
/// \tparam SIZE The maximum capacity of the queue.
|
||||
//***************************************************************************
|
||||
template <typename T, size_t SIZE>
|
||||
class queue_spsc_atomic : public iqueue_spsc_atomic<T>
|
||||
{
|
||||
typedef etl::iqueue_spsc_atomic<T> base_t;
|
||||
|
||||
static const size_t RESERVED_SIZE = SIZE + 1;
|
||||
|
||||
public:
|
||||
|
||||
static const size_t MAX_SIZE = SIZE;
|
||||
|
||||
//*************************************************************************
|
||||
/// Default constructor.
|
||||
//*************************************************************************
|
||||
queue_spsc_atomic()
|
||||
: base_t(reinterpret_cast<T*>(&buffer[0]), RESERVED_SIZE)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
~queue_spsc_atomic()
|
||||
{
|
||||
base_t::clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// The uninitialised buffer of T used in the queue_spsc.
|
||||
typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[RESERVED_SIZE];
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
458
include/etl/queue_spsc_isr.h
Normal file
458
include/etl/queue_spsc_isr.h
Normal file
@ -0,0 +1,458 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_SPSC_QUEUE_ISR__
|
||||
#define __ETL_SPSC_QUEUE_ISR__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "alignment.h"
|
||||
#include "parameter_type.h"
|
||||
|
||||
#undef ETL_FILE
|
||||
#define ETL_FILE "46"
|
||||
|
||||
namespace etl
|
||||
{
|
||||
template <typename T>
|
||||
class queue_spsc_isr_base
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef typename etl::parameter_type<T>::type parameter_t;
|
||||
|
||||
public:
|
||||
|
||||
typedef T value_type; ///< The type stored in the queue.
|
||||
typedef T& reference; ///< A reference to the type used in the queue.
|
||||
typedef const T& const_reference; ///< A const reference to the type used in the queue.
|
||||
typedef size_t size_type; ///< The type used for determining the size of the queue.
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue from an ISR.
|
||||
//*************************************************************************
|
||||
bool push_from_isr(parameter_t value)
|
||||
{
|
||||
return push_implementation(value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue from an ISR
|
||||
//*************************************************************************
|
||||
bool pop_from_isr(reference value)
|
||||
{
|
||||
return pop_implementation(value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue from an ISR, and discard.
|
||||
//*************************************************************************
|
||||
bool pop_from_isr()
|
||||
{
|
||||
return pop_implementation();
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How much free space available in the queue.
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
size_t available_from_isr() const
|
||||
{
|
||||
return MAX_SIZE - current_size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Clear the queue from the ISR.
|
||||
//*************************************************************************
|
||||
void clear_from_isr()
|
||||
{
|
||||
while (pop_implementation())
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue empty?
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
bool empty_from_isr() const
|
||||
{
|
||||
return (current_size == 0);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue full?
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
bool full_from_isr() const
|
||||
{
|
||||
return (current_size == MAX_SIZE);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items in the queue?
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
size_t size_from_isr() const
|
||||
{
|
||||
return current_size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_t capacity() const
|
||||
{
|
||||
return MAX_SIZE;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_t max_size() const
|
||||
{
|
||||
return MAX_SIZE;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
queue_spsc_isr_base(T* p_buffer_, size_type max_size_)
|
||||
: p_buffer(p_buffer_),
|
||||
write_index(0),
|
||||
read_index(0),
|
||||
current_size(0),
|
||||
MAX_SIZE(max_size_)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push_implementation(parameter_t value)
|
||||
{
|
||||
if (current_size != MAX_SIZE)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value);
|
||||
|
||||
write_index = get_next_index(write_index, MAX_SIZE);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop_implementation(reference value)
|
||||
{
|
||||
if (current_size == 0)
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
value = p_buffer[read_index];
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read_index = get_next_index(read_index, MAX_SIZE);;
|
||||
|
||||
--current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue and discard.
|
||||
//*************************************************************************
|
||||
bool pop_implementation()
|
||||
{
|
||||
if (current_size == 0)
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read_index = get_next_index(read_index, MAX_SIZE);
|
||||
|
||||
--current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Calculate the next index.
|
||||
//*************************************************************************
|
||||
static size_t get_next_index(size_t index, size_t maximum)
|
||||
{
|
||||
++index;
|
||||
|
||||
if (index == maximum)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
T* p_buffer; ///< The internal buffer.
|
||||
size_type write_index; ///< Where to input new data.
|
||||
size_type read_index; ///< Where to get the oldest data.
|
||||
size_type current_size; ///< The current size of the queue.
|
||||
const size_type MAX_SIZE; ///< The maximum number of items in the queue.
|
||||
|
||||
private:
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
#if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ISR) || defined(ETL_POLYMORPHIC_CONTAINERS)
|
||||
public:
|
||||
virtual ~queue_spsc_isr_base()
|
||||
{
|
||||
}
|
||||
#else
|
||||
protected:
|
||||
~queue_spsc_isr_base()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\ingroup queue_spsc
|
||||
///\brief This is the base for all queue_spsc_isrs that contain a particular type.
|
||||
///\details Normally a reference to this type will be taken from a derived queue_spsc_isr.
|
||||
///\code
|
||||
/// etl::queue_spsc_isr_isr<int, 10> myQueue;
|
||||
/// etl::iqueue_isr<int>& iQueue = myQueue;
|
||||
///\endcode
|
||||
/// This queue supports concurrent access by one producer and one consumer.
|
||||
/// \tparam T The type of value that the queue_spsc_isr holds.
|
||||
//***************************************************************************
|
||||
template <typename T, typename TAccess>
|
||||
class iqueue_spsc_isr : public queue_spsc_isr_base<T>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef typename queue_spsc_isr_base<T>::parameter_t parameter_t;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename queue_spsc_isr_base<T>::value_type value_type; ///< The type stored in the queue.
|
||||
typedef typename queue_spsc_isr_base<T>::reference reference; ///< A reference to the type used in the queue.
|
||||
typedef typename queue_spsc_isr_base<T>::const_reference const_reference; ///< A const reference to the type used in the queue.
|
||||
typedef typename queue_spsc_isr_base<T>::size_type size_type; ///< The type used for determining the size of the queue.
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push(parameter_t value)
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
bool result = this->push_implementation(value);
|
||||
|
||||
TAccess::unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop(reference value)
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
bool result = this->pop_implementation(value);
|
||||
|
||||
TAccess::unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue and discard.
|
||||
//*************************************************************************
|
||||
bool pop()
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
bool result = this->pop_implementation();
|
||||
|
||||
TAccess::unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Clear the queue.
|
||||
//*************************************************************************
|
||||
void clear()
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
while (this->pop_implementation())
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
TAccess::unlock();
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue empty?
|
||||
//*************************************************************************
|
||||
bool empty() const
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
size_t result = (this->current_size == 0);
|
||||
|
||||
TAccess::unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue full?
|
||||
//*************************************************************************
|
||||
bool full() const
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
size_t result = (this->current_size == this->MAX_SIZE);
|
||||
|
||||
TAccess::unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items in the queue?
|
||||
//*************************************************************************
|
||||
size_t size() const
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
size_t result = this->current_size;
|
||||
|
||||
TAccess::unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How much free space available in the queue.
|
||||
//*************************************************************************
|
||||
size_t available() const
|
||||
{
|
||||
TAccess::lock();
|
||||
|
||||
size_t result = this->MAX_SIZE - this->current_size;
|
||||
|
||||
TAccess::unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//*************************************************************************
|
||||
/// The constructor that is called from derived classes.
|
||||
//*************************************************************************
|
||||
iqueue_spsc_isr(T* p_buffer_, size_type max_size_)
|
||||
: queue_spsc_isr_base<T>(p_buffer_, max_size_)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Disable copy construction and assignment.
|
||||
iqueue_spsc_isr(const iqueue_spsc_isr&);
|
||||
iqueue_spsc_isr& operator =(const iqueue_spsc_isr&);
|
||||
|
||||
TAccess access; ///< The object that locks/unlocks interrupts.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\ingroup queue_spsc
|
||||
/// A fixed capacity spsc queue.
|
||||
/// This queue supports concurrent access by one producer and one consumer.
|
||||
/// \tparam T The type this queue should support.
|
||||
/// \tparam SIZE The maximum capacity of the queue.
|
||||
/// \tparam TAccess The type that will lock and unlock interrupts.
|
||||
//***************************************************************************
|
||||
template <typename T, size_t SIZE, typename TAccess>
|
||||
class queue_spsc_isr : public etl::iqueue_spsc_isr<T, TAccess>
|
||||
{
|
||||
typedef etl::iqueue_spsc_isr<T, TAccess> base_t;
|
||||
|
||||
public:
|
||||
|
||||
static const size_t MAX_SIZE = SIZE;
|
||||
|
||||
//*************************************************************************
|
||||
/// Default constructor.
|
||||
//*************************************************************************
|
||||
queue_spsc_isr()
|
||||
: base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
~queue_spsc_isr()
|
||||
{
|
||||
base_t::clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
queue_spsc_isr(const queue_spsc_isr&);
|
||||
queue_spsc_isr& operator = (const queue_spsc_isr&);
|
||||
|
||||
/// The uninitialised buffer of T used in the queue_spsc_isr.
|
||||
typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
47
include/etl/spsc_queue.h
Normal file
47
include/etl/spsc_queue.h
Normal file
@ -0,0 +1,47 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 jwellbelove, Mark Kitson
|
||||
|
||||
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.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __ETL_SPSC_QUEUE__
|
||||
#define __ETL_SPSC_QUEUE__
|
||||
|
||||
#include "platform.h"
|
||||
#include "atomic.h"
|
||||
|
||||
#if ETL_HAS_ATOMIC
|
||||
#include "spsc_queue_atomic.h"
|
||||
#endif
|
||||
|
||||
#if defined(ETL_OS_FREERTOS)
|
||||
#include "spsc_queue_freertos.h"
|
||||
#endif
|
||||
|
||||
#include "spsc_queue_isr.h"
|
||||
|
||||
#endif
|
||||
@ -37,9 +37,9 @@ SOFTWARE.
|
||||
/// Definitions of the ETL version
|
||||
///\ingroup utilities
|
||||
|
||||
#define ETL_VERSION "11.4.0"
|
||||
#define ETL_VERSION "11.5.0"
|
||||
#define ETL_VERSION_MAJOR 11
|
||||
#define ETL_VERSION_MINOR 4
|
||||
#define ETL_VERSION_MINOR 5
|
||||
#define ETL_VERSION_PATCH 0
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
===============================================================================
|
||||
11.5.0
|
||||
Added etl::permutations and etl::combinations constant templates.
|
||||
|
||||
===============================================================================
|
||||
11.4.0
|
||||
Added improved atomics.
|
||||
|
||||
@ -81,8 +81,8 @@
|
||||
<Unit filename="../../include/etl/array_wrapper.h" />
|
||||
<Unit filename="../../include/etl/atomic.h" />
|
||||
<Unit filename="../../include/etl/atomic/atomic_arm.h" />
|
||||
<Unit filename="../../include/etl/atomic/atomic_gcc.h" />
|
||||
<Unit filename="../../include/etl/atomic/atomic_windows.h" />
|
||||
<Unit filename="../../include/etl/atomic/atomic_gcc_sync.h" />
|
||||
<Unit filename="../../include/etl/atomic/atomic_std.h" />
|
||||
<Unit filename="../../include/etl/basic_string.h" />
|
||||
<Unit filename="../../include/etl/binary.h" />
|
||||
<Unit filename="../../include/etl/bitset.h" />
|
||||
@ -92,6 +92,7 @@
|
||||
<Unit filename="../../include/etl/callback_timer.h" />
|
||||
<Unit filename="../../include/etl/char_traits.h" />
|
||||
<Unit filename="../../include/etl/checksum.h" />
|
||||
<Unit filename="../../include/etl/combinations.h" />
|
||||
<Unit filename="../../include/etl/compare.h" />
|
||||
<Unit filename="../../include/etl/constant.h" />
|
||||
<Unit filename="../../include/etl/container.h" />
|
||||
@ -163,6 +164,7 @@
|
||||
<Unit filename="../../include/etl/packet.h" />
|
||||
<Unit filename="../../include/etl/parameter_type.h" />
|
||||
<Unit filename="../../include/etl/pearson.h" />
|
||||
<Unit filename="../../include/etl/permutations.h" />
|
||||
<Unit filename="../../include/etl/platform.h" />
|
||||
<Unit filename="../../include/etl/pool.h" />
|
||||
<Unit filename="../../include/etl/power.h" />
|
||||
@ -183,6 +185,9 @@
|
||||
<Unit filename="../../include/etl/profiles/msvc_x86.h" />
|
||||
<Unit filename="../../include/etl/profiles/ticc.h" />
|
||||
<Unit filename="../../include/etl/queue.h" />
|
||||
<Unit filename="../../include/etl/queue_mpmc_mutex.h" />
|
||||
<Unit filename="../../include/etl/queue_spsc_atomic.h" />
|
||||
<Unit filename="../../include/etl/queue_spsc_isr.h" />
|
||||
<Unit filename="../../include/etl/radix.h" />
|
||||
<Unit filename="../../include/etl/random.h" />
|
||||
<Unit filename="../../include/etl/ratio.h" />
|
||||
@ -194,6 +199,10 @@
|
||||
<Unit filename="../../include/etl/set.h" />
|
||||
<Unit filename="../../include/etl/smallest.h" />
|
||||
<Unit filename="../../include/etl/smallest_generator.h" />
|
||||
<Unit filename="../../include/etl/spsc_queue.h" />
|
||||
<Unit filename="../../include/etl/spsc_queue_atomic.h" />
|
||||
<Unit filename="../../include/etl/spsc_queue_isr.h" />
|
||||
<Unit filename="../../include/etl/spsc_queue_mutex.h" />
|
||||
<Unit filename="../../include/etl/sqrt.h" />
|
||||
<Unit filename="../../include/etl/stack.h" />
|
||||
<Unit filename="../../include/etl/static_assert.h" />
|
||||
@ -317,6 +326,8 @@
|
||||
<Unit filename="../test_array.cpp" />
|
||||
<Unit filename="../test_array_view.cpp" />
|
||||
<Unit filename="../test_array_wrapper.cpp" />
|
||||
<Unit filename="../test_atomic_gcc_sync.cpp" />
|
||||
<Unit filename="../test_atomic_std.cpp" />
|
||||
<Unit filename="../test_binary.cpp" />
|
||||
<Unit filename="../test_bitset.cpp" />
|
||||
<Unit filename="../test_bloom_filter.cpp" />
|
||||
@ -376,6 +387,9 @@
|
||||
<Unit filename="../test_pool.cpp" />
|
||||
<Unit filename="../test_priority_queue.cpp" />
|
||||
<Unit filename="../test_queue.cpp" />
|
||||
<Unit filename="../test_queue_mpmc_mutex.cpp" />
|
||||
<Unit filename="../test_queue_spsc_atomic.cpp" />
|
||||
<Unit filename="../test_queue_spsc_isr.cpp" />
|
||||
<Unit filename="../test_random.cpp" />
|
||||
<Unit filename="../test_reference_flat_map.cpp" />
|
||||
<Unit filename="../test_reference_flat_multimap.cpp" />
|
||||
|
||||
@ -1,87 +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++.h"
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "atomic/atomic_gcc.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_atomic_gcc)
|
||||
{
|
||||
//=========================================================================
|
||||
TEST(test_atomic_compare_exchange_weak_fail)
|
||||
{
|
||||
std::atomic<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = 2U;
|
||||
int test_expected = 2U;
|
||||
int desired = 3U;
|
||||
|
||||
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<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = actual;
|
||||
int test_expected = actual;
|
||||
int desired = 3U;
|
||||
|
||||
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());
|
||||
}
|
||||
};
|
||||
}
|
||||
484
test/test_atomic_gcc_sync.cpp
Normal file
484
test/test_atomic_gcc_sync.cpp
Normal file
@ -0,0 +1,484 @@
|
||||
/******************************************************************************
|
||||
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++.h"
|
||||
|
||||
#include "platform.h"
|
||||
#include "atomic/atomic_std.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_atomic_std)
|
||||
{
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_is_lock_free)
|
||||
{
|
||||
std::atomic<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_pointer_is_lock_free)
|
||||
{
|
||||
std::atomic<int*> compare;
|
||||
etl::atomic<int*> test;
|
||||
|
||||
CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_load)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)compare.load(), (int)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_pointer_load)
|
||||
{
|
||||
int i;
|
||||
|
||||
std::atomic<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
CHECK_EQUAL((int*)compare.load(), (int*)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_store)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
compare.store(&j);
|
||||
test.store(&j);
|
||||
CHECK_EQUAL((int*)compare.load(), (int*)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_assignment)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
compare = &j;
|
||||
test = &j;
|
||||
CHECK_EQUAL((int*)compare.load(), (int*)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_pre_increment)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)++compare, (int)++test);
|
||||
CHECK_EQUAL((int)++compare, (int)++test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_post_increment)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)compare++, (int)test++);
|
||||
CHECK_EQUAL((int)compare++, (int)test++);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_pre_decrement)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)--compare, (int)--test);
|
||||
CHECK_EQUAL((int)--compare, (int)--test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_post_decrement)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int*> compare(&data[3]);
|
||||
etl::atomic<int*> 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<int*> compare(&data[3]);
|
||||
etl::atomic<int*> test(&data[3]);
|
||||
|
||||
CHECK_EQUAL((int*)compare--, (int*)test--);
|
||||
CHECK_EQUAL((int*)compare--, (int*)test--);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_fetch_add)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> test(&data[0]);
|
||||
|
||||
compare += 2;
|
||||
test += 2;
|
||||
|
||||
CHECK_EQUAL((int*)compare, (int*)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_minus_equals)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[3]);
|
||||
etl::atomic<int*> test(&data[3]);
|
||||
|
||||
compare += 2;
|
||||
test += 2;
|
||||
|
||||
CHECK_EQUAL((int*)compare, (int*)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_and_equals)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
compare &= 0x55AA55AA;
|
||||
test &= 0x55AA55AA;
|
||||
|
||||
CHECK_EQUAL((int)compare, (int)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_or_equals)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
compare |= 0x55AA55AA;
|
||||
test |= 0x55AA55AA;
|
||||
|
||||
CHECK_EQUAL((int)compare, (int)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_xor_equals)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
compare ^= 0x55AA55AA;
|
||||
test ^= 0x55AA55AA;
|
||||
|
||||
CHECK_EQUAL((int)compare, (int)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_fetch_sub)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int> compare(0xFFFFFFFF);
|
||||
etl::atomic<int> test(0xFFFFFFFF);
|
||||
|
||||
CHECK_EQUAL((int)compare.fetch_and(0x55AA55AA), (int)test.fetch_and(0x55AA55AA));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_fetch_or)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
CHECK_EQUAL((int)compare.fetch_or(0x55AA55AA), (int)test.fetch_or(0x55AA55AA));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_fetch_xor)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
CHECK_EQUAL((int)compare.fetch_xor(0x55AA55AA), (int)test.fetch_xor(0x55AA55AA));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_exchange)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)compare.exchange(2), (int)test.exchange(2));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_pointer_exchange)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
std::atomic<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
CHECK_EQUAL((int*)compare.exchange(&j), (int*)test.exchange(&j));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_compare_exchange_weak_fail)
|
||||
{
|
||||
std::atomic<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = 2U;
|
||||
int test_expected = 2U;
|
||||
int desired = 3U;
|
||||
|
||||
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<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = actual;
|
||||
int test_expected = actual;
|
||||
int desired = 3U;
|
||||
|
||||
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<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = 2U;
|
||||
int test_expected = 2U;
|
||||
int desired = 3U;
|
||||
|
||||
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<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = actual;
|
||||
int test_expected = actual;
|
||||
int desired = 3U;
|
||||
|
||||
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());
|
||||
}
|
||||
};
|
||||
}
|
||||
484
test/test_atomic_std.cpp
Normal file
484
test/test_atomic_std.cpp
Normal file
@ -0,0 +1,484 @@
|
||||
/******************************************************************************
|
||||
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++.h"
|
||||
|
||||
#include "platform.h"
|
||||
#include "atomic/atomic_std.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_atomic_std)
|
||||
{
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_is_lock_free)
|
||||
{
|
||||
std::atomic<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_pointer_is_lock_free)
|
||||
{
|
||||
std::atomic<int*> compare;
|
||||
etl::atomic<int*> test;
|
||||
|
||||
CHECK_EQUAL(compare.is_lock_free(), test.is_lock_free());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_load)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)compare.load(), (int)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_pointer_load)
|
||||
{
|
||||
int i;
|
||||
|
||||
std::atomic<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
CHECK_EQUAL((int*)compare.load(), (int*)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_store)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
compare.store(&j);
|
||||
test.store(&j);
|
||||
CHECK_EQUAL((int*)compare.load(), (int*)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_assignment)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
compare = &j;
|
||||
test = &j;
|
||||
CHECK_EQUAL((int*)compare.load(), (int*)test.load());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_pre_increment)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)++compare, (int)++test);
|
||||
CHECK_EQUAL((int)++compare, (int)++test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_post_increment)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)compare++, (int)test++);
|
||||
CHECK_EQUAL((int)compare++, (int)test++);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_pre_decrement)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)--compare, (int)--test);
|
||||
CHECK_EQUAL((int)--compare, (int)--test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_post_decrement)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int*> compare(&data[3]);
|
||||
etl::atomic<int*> 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<int*> compare(&data[3]);
|
||||
etl::atomic<int*> test(&data[3]);
|
||||
|
||||
CHECK_EQUAL((int*)compare--, (int*)test--);
|
||||
CHECK_EQUAL((int*)compare--, (int*)test--);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_fetch_add)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> test(&data[0]);
|
||||
|
||||
compare += 2;
|
||||
test += 2;
|
||||
|
||||
CHECK_EQUAL((int*)compare, (int*)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_minus_equals)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[3]);
|
||||
etl::atomic<int*> test(&data[3]);
|
||||
|
||||
compare += 2;
|
||||
test += 2;
|
||||
|
||||
CHECK_EQUAL((int*)compare, (int*)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_and_equals)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
compare &= 0x55AA55AA;
|
||||
test &= 0x55AA55AA;
|
||||
|
||||
CHECK_EQUAL((int)compare, (int)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_or_equals)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
compare |= 0x55AA55AA;
|
||||
test |= 0x55AA55AA;
|
||||
|
||||
CHECK_EQUAL((int)compare, (int)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_xor_equals)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
compare ^= 0x55AA55AA;
|
||||
test ^= 0x55AA55AA;
|
||||
|
||||
CHECK_EQUAL((int)compare, (int)test);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_integer_fetch_sub)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> 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<int*> compare(&data[0]);
|
||||
etl::atomic<int*> 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<int> compare(0xFFFFFFFF);
|
||||
etl::atomic<int> test(0xFFFFFFFF);
|
||||
|
||||
CHECK_EQUAL((int)compare.fetch_and(0x55AA55AA), (int)test.fetch_and(0x55AA55AA));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_fetch_or)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
CHECK_EQUAL((int)compare.fetch_or(0x55AA55AA), (int)test.fetch_or(0x55AA55AA));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_operator_fetch_xor)
|
||||
{
|
||||
std::atomic<int> compare(0x0000FFFF);
|
||||
etl::atomic<int> test(0x0000FFFF);
|
||||
|
||||
CHECK_EQUAL((int)compare.fetch_xor(0x55AA55AA), (int)test.fetch_xor(0x55AA55AA));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_integer_exchange)
|
||||
{
|
||||
std::atomic<int> compare(1);
|
||||
etl::atomic<int> test(1);
|
||||
|
||||
CHECK_EQUAL((int)compare.exchange(2), (int)test.exchange(2));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_pointer_exchange)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
std::atomic<int*> compare(&i);
|
||||
etl::atomic<int*> test(&i);
|
||||
|
||||
CHECK_EQUAL((int*)compare.exchange(&j), (int*)test.exchange(&j));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
TEST(test_atomic_compare_exchange_weak_fail)
|
||||
{
|
||||
std::atomic<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = 2U;
|
||||
int test_expected = 2U;
|
||||
int desired = 3U;
|
||||
|
||||
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<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = actual;
|
||||
int test_expected = actual;
|
||||
int desired = 3U;
|
||||
|
||||
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<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = 2U;
|
||||
int test_expected = 2U;
|
||||
int desired = 3U;
|
||||
|
||||
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<int> compare;
|
||||
etl::atomic<int> test;
|
||||
|
||||
int actual = 1U;
|
||||
|
||||
compare = actual;
|
||||
test = actual;
|
||||
|
||||
int compare_expected = actual;
|
||||
int test_expected = actual;
|
||||
int desired = 3U;
|
||||
|
||||
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());
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -33,6 +33,8 @@ SOFTWARE.
|
||||
#include "fibonacci.h"
|
||||
#include "factorial.h"
|
||||
#include "sqrt.h"
|
||||
#include "permutations.h"
|
||||
#include "combinations.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -53,6 +55,36 @@ namespace
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t factorial(size_t n)
|
||||
{
|
||||
if (n == 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n * factorial(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t permutations(size_t n, size_t k)
|
||||
{
|
||||
size_t p = 1;
|
||||
|
||||
for (size_t i = 0; i < k; ++i)
|
||||
{
|
||||
p *= n;
|
||||
--n;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t combinations(size_t n, size_t k)
|
||||
{
|
||||
return permutations(n, k) / factorial(k);
|
||||
}
|
||||
|
||||
SUITE(test_maths)
|
||||
{
|
||||
//*************************************************************************
|
||||
@ -380,5 +412,38 @@ namespace
|
||||
CHECK_EQUAL(sqrt(9), etl::sqrt<9>::value);
|
||||
CHECK_EQUAL(sqrt(10), etl::sqrt<10>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_permutations)
|
||||
{
|
||||
size_t actual;
|
||||
|
||||
|
||||
CHECK_EQUAL((permutations( 6, 2)), (actual = etl::permutations< 6, 2>::value));
|
||||
CHECK_EQUAL((permutations( 7, 3)), (actual = etl::permutations< 7, 3>::value));
|
||||
CHECK_EQUAL((permutations( 8, 4)), (actual = etl::permutations< 8, 4>::value));
|
||||
CHECK_EQUAL((permutations( 9, 5)), (actual = etl::permutations< 9, 5>::value));
|
||||
CHECK_EQUAL((permutations(10, 6)), (actual = etl::permutations<10, 6>::value));
|
||||
CHECK_EQUAL((permutations(11, 7)), (actual = etl::permutations<11, 7>::value));
|
||||
CHECK_EQUAL((permutations(12, 8)), (actual = etl::permutations<12, 8>::value));
|
||||
CHECK_EQUAL((permutations(13, 9)), (actual = etl::permutations<13, 9>::value));
|
||||
CHECK_EQUAL((permutations(14, 10)), (actual = etl::permutations<14, 10>::value));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_combinations)
|
||||
{
|
||||
size_t actual;
|
||||
|
||||
CHECK_EQUAL((combinations( 6, 2)), (actual = etl::combinations< 6, 2>::value));
|
||||
CHECK_EQUAL((combinations( 7, 3)), (actual = etl::combinations< 7, 3>::value));
|
||||
CHECK_EQUAL((combinations( 8, 4)), (actual = etl::combinations< 8, 4>::value));
|
||||
CHECK_EQUAL((combinations( 9, 5)), (actual = etl::combinations< 9, 5>::value));
|
||||
CHECK_EQUAL((combinations(10, 6)), (actual = etl::combinations<10, 6>::value));
|
||||
CHECK_EQUAL((combinations(11, 7)), (actual = etl::combinations<11, 7>::value));
|
||||
CHECK_EQUAL((combinations(12, 8)), (actual = etl::combinations<12, 8>::value));
|
||||
CHECK_EQUAL((combinations(13, 9)), (actual = etl::combinations<13, 9>::value));
|
||||
CHECK_EQUAL((combinations(14, 10)), (actual = etl::combinations<14, 10>::value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
406
test/test_queue_mpmc_mutex.cpp
Normal file
406
test/test_queue_mpmc_mutex.cpp
Normal file
@ -0,0 +1,406 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
http://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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++.h"
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
|
||||
#include "queue_mpmc_mutex.h"
|
||||
|
||||
#if defined(ETL_COMPILER_MICROSOFT)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#define REALTIME_TEST 1
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_queue_mpmc_mutex)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_constructor)
|
||||
{
|
||||
etl::queue_mpmc_mutex<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(4U, queue.max_size());
|
||||
CHECK_EQUAL(4U, queue.capacity());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop)
|
||||
{
|
||||
etl::queue_mpmc_mutex<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK_EQUAL(4U, queue.available());
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
CHECK_EQUAL(3U, queue.available());
|
||||
|
||||
queue.push(2);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
CHECK_EQUAL(2U, queue.available());
|
||||
|
||||
queue.push(3);
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
CHECK_EQUAL(1U, queue.available());
|
||||
|
||||
queue.push(4);
|
||||
CHECK_EQUAL(4U, queue.size());
|
||||
CHECK_EQUAL(0U, queue.available());
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push(5));
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(!queue.pop(i));
|
||||
CHECK(!queue.pop(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_iqueue)
|
||||
{
|
||||
etl::queue_mpmc_mutex<int, 4> queue;
|
||||
|
||||
etl::iqueue_mpmc_mutex<int>& iqueue = queue;
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size());
|
||||
|
||||
iqueue.push(1);
|
||||
CHECK_EQUAL(1U, iqueue.size());
|
||||
|
||||
iqueue.push(2);
|
||||
CHECK_EQUAL(2U, iqueue.size());
|
||||
|
||||
iqueue.push(3);
|
||||
CHECK_EQUAL(3U, iqueue.size());
|
||||
|
||||
iqueue.push(4);
|
||||
CHECK_EQUAL(4U, iqueue.size());
|
||||
|
||||
CHECK(!iqueue.push(5));
|
||||
CHECK(!iqueue.push(5));
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK_EQUAL(3U, iqueue.size());
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK_EQUAL(2U, iqueue.size());
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK_EQUAL(1U, iqueue.size());
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK_EQUAL(0U, iqueue.size());
|
||||
|
||||
CHECK(!iqueue.pop(i));
|
||||
CHECK(!iqueue.pop(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_void)
|
||||
{
|
||||
etl::queue_mpmc_mutex<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
|
||||
queue.push(2);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
|
||||
queue.push(3);
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
|
||||
queue.push(4);
|
||||
CHECK_EQUAL(4U, queue.size());
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push(5));
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(!queue.pop());
|
||||
CHECK(!queue.pop());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_clear)
|
||||
{
|
||||
etl::queue_mpmc_mutex<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.clear();
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
// Do it again to check that clear() didn't screw up the internals.
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
queue.clear();
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_empty)
|
||||
{
|
||||
etl::queue_mpmc_mutex<int, 4> queue;
|
||||
CHECK(queue.empty());
|
||||
|
||||
queue.push(1);
|
||||
CHECK(!queue.empty());
|
||||
|
||||
queue.clear();
|
||||
CHECK(queue.empty());
|
||||
|
||||
queue.push(1);
|
||||
CHECK(!queue.empty());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_full)
|
||||
{
|
||||
etl::queue_mpmc_mutex<int, 4> queue;
|
||||
CHECK(!queue.full());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
CHECK(queue.full());
|
||||
|
||||
queue.clear();
|
||||
CHECK(!queue.full());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
CHECK(queue.full());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
#if REALTIME_TEST && defined(ETL_COMPILER_MICROSOFT)
|
||||
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
|
||||
#define SET_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL)
|
||||
#define FIX_PROCESSOR_AFFINITY1 SetThreadAffinityMask(GetCurrentThread(), 1);
|
||||
#define FIX_PROCESSOR_AFFINITY2 SetThreadAffinityMask(GetCurrentThread(), 2);
|
||||
#define FIX_PROCESSOR_AFFINITY3 SetThreadAffinityMask(GetCurrentThread(), 4);
|
||||
#define FIX_PROCESSOR_AFFINITY4 SetThreadAffinityMask(GetCurrentThread(), 8);
|
||||
#else
|
||||
#error No thread priority modifier defined
|
||||
#endif
|
||||
|
||||
etl::queue_mpmc_mutex<int, 10> queue;
|
||||
|
||||
const size_t LENGTH = 100000;
|
||||
|
||||
std::vector<int> push1;
|
||||
std::vector<int> push2;
|
||||
|
||||
std::vector<int> pop1;
|
||||
std::vector<int> pop2;
|
||||
|
||||
volatile std::atomic_bool start;
|
||||
|
||||
void push_thread1()
|
||||
{
|
||||
FIX_PROCESSOR_AFFINITY1;
|
||||
SET_THREAD_PRIORITY;
|
||||
|
||||
size_t count = 0;
|
||||
int value = 0;
|
||||
|
||||
while (!start.load());
|
||||
|
||||
while (count < (LENGTH / 2))
|
||||
{
|
||||
if (queue.push(value))
|
||||
{
|
||||
push1.push_back(value);
|
||||
++count;
|
||||
++value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void push_thread2()
|
||||
{
|
||||
FIX_PROCESSOR_AFFINITY2;
|
||||
SET_THREAD_PRIORITY;
|
||||
|
||||
size_t count = 0;
|
||||
int value = LENGTH / 2;
|
||||
|
||||
while (!start.load());
|
||||
|
||||
while (count < (LENGTH / 2))
|
||||
{
|
||||
if (queue.push(value))
|
||||
{
|
||||
push2.push_back(value);
|
||||
++count;
|
||||
++value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop_thread1()
|
||||
{
|
||||
FIX_PROCESSOR_AFFINITY3;
|
||||
SET_THREAD_PRIORITY;
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while (!start.load());
|
||||
|
||||
while (count < (LENGTH / 2))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (queue.pop(i))
|
||||
{
|
||||
pop1.push_back(i);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop_thread2()
|
||||
{
|
||||
FIX_PROCESSOR_AFFINITY4;
|
||||
SET_THREAD_PRIORITY;
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while (!start.load());
|
||||
|
||||
while (count < (LENGTH / 2))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (queue.pop(i))
|
||||
{
|
||||
pop2.push_back(i);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(queue_threads)
|
||||
{
|
||||
push1.reserve(LENGTH / 2);
|
||||
push2.reserve(LENGTH / 2);;
|
||||
|
||||
pop1.reserve(LENGTH / 2);;
|
||||
pop2.reserve(LENGTH / 2);;
|
||||
|
||||
start = false;
|
||||
|
||||
std::thread t1(push_thread1);
|
||||
std::thread t2(push_thread2);
|
||||
std::thread t3(pop_thread1);
|
||||
std::thread t4(pop_thread2);
|
||||
|
||||
start.store(true);
|
||||
|
||||
// Join the threads with the main thread
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
t4.join();
|
||||
|
||||
// Combine input vectors.
|
||||
std::vector<int> push;
|
||||
push.insert(push.end(), push1.begin(), push1.end());
|
||||
push.insert(push.end(), push2.begin(), push2.end());
|
||||
std::sort(push.begin(), push.end());
|
||||
|
||||
// Combine output vectors.
|
||||
std::vector<int> pop;
|
||||
pop.insert(pop.end(), pop1.begin(), pop1.end());
|
||||
pop.insert(pop.end(), pop2.begin(), pop2.end());
|
||||
std::sort(pop.begin(), pop.end());
|
||||
|
||||
CHECK_EQUAL(LENGTH, push.size());
|
||||
CHECK_EQUAL(LENGTH, pop.size());
|
||||
|
||||
for (size_t i = 0; i < LENGTH; ++i)
|
||||
{
|
||||
CHECK_EQUAL(push[i], pop[i]);
|
||||
CHECK_EQUAL(i, pop[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
312
test/test_queue_spsc_atomic.cpp
Normal file
312
test/test_queue_spsc_atomic.cpp
Normal file
@ -0,0 +1,312 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
http://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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++.h"
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
|
||||
#include "queue_spsc_atomic.h"
|
||||
|
||||
#if defined(ETL_COMPILER_MICROSOFT)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#define REALTIME_TEST 0
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_queue_atomic)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_constructor)
|
||||
{
|
||||
etl::queue_spsc_atomic<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(4U, queue.max_size());
|
||||
CHECK_EQUAL(4U, queue.capacity());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop)
|
||||
{
|
||||
etl::queue_spsc_atomic<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK_EQUAL(4U, queue.available());
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
CHECK_EQUAL(3U, queue.available());
|
||||
|
||||
queue.push(2);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
CHECK_EQUAL(2U, queue.available());
|
||||
|
||||
queue.push(3);
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
CHECK_EQUAL(1U, queue.available());
|
||||
|
||||
queue.push(4);
|
||||
CHECK_EQUAL(4U, queue.size());
|
||||
CHECK_EQUAL(0U, queue.available());
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push(5));
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(!queue.pop(i));
|
||||
CHECK(!queue.pop(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_iqueue)
|
||||
{
|
||||
etl::queue_spsc_atomic<int, 4> queue;
|
||||
|
||||
etl::iqueue_spsc_atomic<int>& iqueue = queue;
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size());
|
||||
|
||||
iqueue.push(1);
|
||||
CHECK_EQUAL(1U, iqueue.size());
|
||||
|
||||
iqueue.push(2);
|
||||
CHECK_EQUAL(2U, iqueue.size());
|
||||
|
||||
iqueue.push(3);
|
||||
CHECK_EQUAL(3U, iqueue.size());
|
||||
|
||||
iqueue.push(4);
|
||||
CHECK_EQUAL(4U, iqueue.size());
|
||||
|
||||
CHECK(!iqueue.push(5));
|
||||
CHECK(!iqueue.push(5));
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK_EQUAL(3U, iqueue.size());
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK_EQUAL(2U, iqueue.size());
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK_EQUAL(1U, iqueue.size());
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK_EQUAL(0U, iqueue.size());
|
||||
|
||||
CHECK(!iqueue.pop(i));
|
||||
CHECK(!iqueue.pop(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_void)
|
||||
{
|
||||
etl::queue_spsc_atomic<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
|
||||
queue.push(2);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
|
||||
queue.push(3);
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
|
||||
queue.push(4);
|
||||
CHECK_EQUAL(4U, queue.size());
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push(5));
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(3U, queue.size());
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(1U, queue.size());
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(!queue.pop());
|
||||
CHECK(!queue.pop());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_clear)
|
||||
{
|
||||
etl::queue_spsc_atomic<int, 4> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.clear();
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
// Do it again to check that clear() didn't screw up the internals.
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
CHECK_EQUAL(2U, queue.size());
|
||||
queue.clear();
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_empty)
|
||||
{
|
||||
etl::queue_spsc_atomic<int, 4> queue;
|
||||
CHECK(queue.empty());
|
||||
|
||||
queue.push(1);
|
||||
CHECK(!queue.empty());
|
||||
|
||||
queue.clear();
|
||||
CHECK(queue.empty());
|
||||
|
||||
queue.push(1);
|
||||
CHECK(!queue.empty());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_full)
|
||||
{
|
||||
etl::queue_spsc_atomic<int, 4> queue;
|
||||
CHECK(!queue.full());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
CHECK(queue.full());
|
||||
|
||||
queue.clear();
|
||||
CHECK(!queue.full());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
CHECK(queue.full());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
#if REALTIME_TEST && defined(ETL_COMPILER_MICROSOFT)
|
||||
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
|
||||
#define FIX_PROCESSOR_AFFINITY1 SetThreadAffinityMask(GetCurrentThread(), 1);
|
||||
#define FIX_PROCESSOR_AFFINITY2 SetThreadAffinityMask(GetCurrentThread(), 2);
|
||||
#else
|
||||
#error No thread priority modifier defined
|
||||
#endif
|
||||
|
||||
size_t ticks = 0;
|
||||
|
||||
etl::queue_spsc_atomic<int, 10> queue;
|
||||
|
||||
const size_t LENGTH = 1000000;
|
||||
|
||||
void timer_event()
|
||||
{
|
||||
FIX_PROCESSOR_AFFINITY1;
|
||||
|
||||
const size_t TICK = 1;
|
||||
size_t tick = TICK;
|
||||
ticks = 1;
|
||||
|
||||
while (ticks <= LENGTH)
|
||||
{
|
||||
if (queue.push(ticks))
|
||||
{
|
||||
++ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(queue_threads)
|
||||
{
|
||||
FIX_PROCESSOR_AFFINITY2;
|
||||
|
||||
std::vector<int> tick_list;
|
||||
tick_list.reserve(LENGTH);
|
||||
|
||||
std::thread t1(timer_event);
|
||||
|
||||
while (tick_list.size() < LENGTH)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (queue.pop(i))
|
||||
{
|
||||
tick_list.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Join the thread with the main thread
|
||||
t1.join();
|
||||
|
||||
CHECK_EQUAL(LENGTH, tick_list.size());
|
||||
|
||||
for (size_t i = 0; i < LENGTH; ++i)
|
||||
{
|
||||
CHECK_EQUAL(i + 1, tick_list[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
569
test/test_queue_spsc_isr.cpp
Normal file
569
test/test_queue_spsc_isr.cpp
Normal file
@ -0,0 +1,569 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
http://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 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++.h"
|
||||
|
||||
#include "queue_spsc_isr.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#if defined(ETL_COMPILER_MICROSOFT)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#define REALTIME_TEST 0
|
||||
|
||||
namespace
|
||||
{
|
||||
class Access
|
||||
{
|
||||
public:
|
||||
|
||||
static void clear()
|
||||
{
|
||||
called_lock = false;
|
||||
called_unlock = false;
|
||||
}
|
||||
|
||||
static void lock()
|
||||
{
|
||||
called_lock = true;
|
||||
}
|
||||
|
||||
static void unlock()
|
||||
{
|
||||
called_unlock = true;
|
||||
}
|
||||
|
||||
static bool called_lock;
|
||||
static bool called_unlock;
|
||||
};
|
||||
|
||||
bool Access::called_lock;
|
||||
bool Access::called_unlock;
|
||||
|
||||
SUITE(test_queue_isr)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_constructor)
|
||||
{
|
||||
Access::clear();
|
||||
|
||||
etl::queue_spsc_isr<int, 4, Access> queue;
|
||||
|
||||
CHECK_EQUAL(4U, queue.max_size());
|
||||
CHECK_EQUAL(4U, queue.capacity());
|
||||
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop)
|
||||
{
|
||||
Access::clear();
|
||||
|
||||
etl::queue_spsc_isr<int, 4, Access> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size_from_isr());
|
||||
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK_EQUAL(4U, queue.available_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK_EQUAL(4U, queue.available());
|
||||
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push_from_isr(1);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_isr());
|
||||
CHECK_EQUAL(3U, queue.available_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push(2);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_isr());
|
||||
CHECK_EQUAL(2U, queue.available_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push(3);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_isr());
|
||||
CHECK_EQUAL(1U, queue.available_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push(4);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(4U, queue.size_from_isr());
|
||||
CHECK_EQUAL(0U, queue.available_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push_from_isr(5));
|
||||
|
||||
Access::clear();
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.pop_from_isr(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.pop_from_isr(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.pop_from_isr(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!queue.pop(i));
|
||||
CHECK(!queue.pop_from_isr(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_iqueue)
|
||||
{
|
||||
Access::clear();
|
||||
|
||||
etl::queue_spsc_isr<int, 4, Access> queue;
|
||||
|
||||
etl::iqueue_spsc_isr<int, Access>& iqueue = queue;
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size_from_isr());
|
||||
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size());
|
||||
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
iqueue.push_from_isr(1);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(1U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
iqueue.push(2);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(2U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
iqueue.push(3);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(3U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
iqueue.push(4);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(4U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!iqueue.push(5));
|
||||
CHECK(!iqueue.push_from_isr(5));
|
||||
|
||||
Access::clear();
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(3U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(iqueue.pop_from_isr(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(2U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(iqueue.pop_from_isr(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(1U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(iqueue.pop_from_isr(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(0U, iqueue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!iqueue.pop(i));
|
||||
CHECK(!iqueue.pop_from_isr(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_void)
|
||||
{
|
||||
Access::clear();
|
||||
|
||||
etl::queue_spsc_isr<int, 4, Access> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size_from_isr());
|
||||
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push_from_isr(1);
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push(2);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push(3);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
queue.push(4);
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(4U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push_from_isr(5));
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.pop_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.pop_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.pop_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size_from_isr());
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!queue.pop());
|
||||
CHECK(!queue.pop_from_isr());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_clear)
|
||||
{
|
||||
Access::clear();
|
||||
|
||||
etl::queue_spsc_isr<int, 4, Access> queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.clear();
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
Access::clear();
|
||||
|
||||
// Do it again to check that clear() didn't screw up the internals.
|
||||
queue.push_from_isr(1);
|
||||
queue.push_from_isr(2);
|
||||
CHECK_EQUAL(2U, queue.size_from_isr());
|
||||
queue.clear_from_isr();
|
||||
CHECK_EQUAL(0U, queue.size_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_empty)
|
||||
{
|
||||
Access::clear();
|
||||
|
||||
etl::queue_spsc_isr<int, 4, Access> queue;
|
||||
|
||||
CHECK(queue.empty());
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!queue.empty());
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
queue.clear();
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.empty_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(!queue.empty_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_full)
|
||||
{
|
||||
Access::clear();
|
||||
|
||||
etl::queue_spsc_isr<int, 4, Access> queue;
|
||||
|
||||
CHECK(!queue.full());
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.full());
|
||||
CHECK(Access::called_lock);
|
||||
CHECK(Access::called_unlock);
|
||||
|
||||
queue.clear();
|
||||
Access::clear();
|
||||
|
||||
CHECK(!queue.full_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
|
||||
Access::clear();
|
||||
|
||||
CHECK(queue.full_from_isr());
|
||||
CHECK(!Access::called_lock);
|
||||
CHECK(!Access::called_unlock);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
#if REALTIME_TEST && defined(ETL_COMPILER_MICROSOFT)
|
||||
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
|
||||
#define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
|
||||
#define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1);
|
||||
#else
|
||||
#error No thread priority modifier defined
|
||||
#endif
|
||||
|
||||
size_t ticks = 0;
|
||||
|
||||
struct ThreadLock
|
||||
{
|
||||
static void lock()
|
||||
{
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
static void unlock()
|
||||
{
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
static std::mutex mutex;
|
||||
};
|
||||
|
||||
std::mutex ThreadLock::mutex;
|
||||
|
||||
etl::queue_spsc_isr<int, 10, ThreadLock> queue;
|
||||
|
||||
const size_t LENGTH = 1000;
|
||||
|
||||
void timer_thread()
|
||||
{
|
||||
RAISE_THREAD_PRIORITY;
|
||||
FIX_PROCESSOR_AFFINITY;
|
||||
|
||||
const size_t TICK = 1;
|
||||
size_t tick = TICK;
|
||||
ticks = 1;
|
||||
|
||||
while (ticks <= LENGTH)
|
||||
{
|
||||
if (ThreadLock::mutex.try_lock())
|
||||
{
|
||||
if (queue.push_from_isr(ticks))
|
||||
{
|
||||
++ticks;
|
||||
}
|
||||
|
||||
ThreadLock::mutex.unlock();
|
||||
}
|
||||
|
||||
Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(queue_threads)
|
||||
{
|
||||
FIX_PROCESSOR_AFFINITY;
|
||||
|
||||
std::vector<int> tick_list;
|
||||
tick_list.reserve(LENGTH);
|
||||
|
||||
std::thread t1(timer_thread);
|
||||
|
||||
while (tick_list.size() < LENGTH)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (queue.pop(i))
|
||||
{
|
||||
tick_list.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Join the thread with the main thread
|
||||
t1.join();
|
||||
|
||||
CHECK_EQUAL(LENGTH, tick_list.size());
|
||||
|
||||
for (size_t i = 0; i < LENGTH; ++i)
|
||||
{
|
||||
CHECK_EQUAL(i + 1, tick_list[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
@ -327,8 +327,10 @@
|
||||
<ClInclude Include="..\..\include\etl\array_wrapper.h" />
|
||||
<ClInclude Include="..\..\include\etl\atomic.h" />
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_arm.h" />
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_gcc.h" />
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_gcc_sync.h" />
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_std.h" />
|
||||
<ClInclude Include="..\..\include\etl\callback_timer.h" />
|
||||
<ClInclude Include="..\..\include\etl\combinations.h" />
|
||||
<ClInclude Include="..\..\include\etl\compare.h" />
|
||||
<ClInclude Include="..\..\include\etl\constant.h" />
|
||||
<ClInclude Include="..\..\include\etl\c\ecl_timer.h" />
|
||||
@ -341,7 +343,12 @@
|
||||
<ClInclude Include="..\..\include\etl\message_types.h" />
|
||||
<ClInclude Include="..\..\include\etl\message_router.h" />
|
||||
<ClInclude Include="..\..\include\etl\message_router_generator.h" />
|
||||
<ClInclude Include="..\..\include\etl\mutex.h" />
|
||||
<ClInclude Include="..\..\include\etl\mutex\mutex_arm.h" />
|
||||
<ClInclude Include="..\..\include\etl\mutex\mutex_gcc_sync.h" />
|
||||
<ClInclude Include="..\..\include\etl\mutex\mutex_std.h" />
|
||||
<ClInclude Include="..\..\include\etl\packet.h" />
|
||||
<ClInclude Include="..\..\include\etl\permutations.h" />
|
||||
<ClInclude Include="..\..\include\etl\profiles\arduino_arm.h" />
|
||||
<ClInclude Include="..\..\include\etl\profiles\armv5.h" />
|
||||
<ClInclude Include="..\..\include\etl\profiles\armv6.h" />
|
||||
@ -355,6 +362,9 @@
|
||||
<ClInclude Include="..\..\include\etl\profiles\ticc.h" />
|
||||
<ClInclude Include="..\..\include\etl\scheduler.h" />
|
||||
<ClInclude Include="..\..\include\etl\smallest_generator.h" />
|
||||
<ClInclude Include="..\..\include\etl\queue_spsc_atomic.h" />
|
||||
<ClInclude Include="..\..\include\etl\queue_spsc_isr.h" />
|
||||
<ClInclude Include="..\..\include\etl\queue_mpmc_mutex.h" />
|
||||
<ClInclude Include="..\..\include\etl\sqrt.h" />
|
||||
<ClInclude Include="..\..\include\etl\string_view.h" />
|
||||
<ClInclude Include="..\..\include\etl\task.h" />
|
||||
@ -539,6 +549,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_array_view.cpp" />
|
||||
<ClCompile Include="..\test_array_wrapper.cpp" />
|
||||
<ClCompile Include="..\test_atomic_std.cpp" />
|
||||
<ClCompile Include="..\test_binary.cpp" />
|
||||
<ClCompile Include="..\test_bitset.cpp" />
|
||||
<ClCompile Include="..\test_bloom_filter.cpp" />
|
||||
@ -666,6 +677,9 @@
|
||||
<ClCompile Include="..\test_pool.cpp" />
|
||||
<ClCompile Include="..\test_priority_queue.cpp" />
|
||||
<ClCompile Include="..\test_queue.cpp" />
|
||||
<ClCompile Include="..\test_queue_mpmc_mutex.cpp" />
|
||||
<ClCompile Include="..\test_queue_spsc_atomic.cpp" />
|
||||
<ClCompile Include="..\test_queue_spsc_isr.cpp" />
|
||||
<ClCompile Include="..\test_random.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
|
||||
@ -70,6 +70,9 @@
|
||||
<Filter Include="Resource Files\Images">
|
||||
<UniqueIdentifier>{4d08353c-b393-47c7-a9eb-c9f2f8c25887}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ETL\Utilities\Mutex">
|
||||
<UniqueIdentifier>{0bcdf7f9-8e2b-4f70-932b-bde56404f421}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\etl\doxygen.h">
|
||||
@ -561,9 +564,6 @@
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_arm.h">
|
||||
<Filter>ETL\Utilities\Atomic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_gcc.h">
|
||||
<Filter>ETL\Utilities\Atomic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ecl_user.h">
|
||||
<Filter>Source Files\ECL</Filter>
|
||||
</ClInclude>
|
||||
@ -588,6 +588,39 @@
|
||||
<ClInclude Include="..\..\include\etl\c\ecl_timer.h">
|
||||
<Filter>ECL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_std.h">
|
||||
<Filter>ETL\Utilities\Atomic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\atomic\atomic_gcc_sync.h">
|
||||
<Filter>ETL\Utilities\Atomic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\queue_mpmc_mutex.h">
|
||||
<Filter>ETL\Containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\queue_spsc_isr.h">
|
||||
<Filter>ETL\Containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\queue_spsc_atomic.h">
|
||||
<Filter>ETL\Containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\mutex\mutex_gcc_sync.h">
|
||||
<Filter>ETL\Utilities\Mutex</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\mutex\mutex_std.h">
|
||||
<Filter>ETL\Utilities\Mutex</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\mutex\mutex_arm.h">
|
||||
<Filter>ETL\Utilities\Mutex</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\mutex.h">
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\combinations.h">
|
||||
<Filter>ETL\Maths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\permutations.h">
|
||||
<Filter>ETL\Maths</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\main.cpp">
|
||||
@ -974,6 +1007,18 @@
|
||||
<ClCompile Include="..\test_c_timer_framework.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_atomic_std.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_queue_mpmc_mutex.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_queue_spsc_atomic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_queue_spsc_isr.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\Doxyfile">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user