Merge remote-tracking branch 'origin/feature/memory_models' into development

# Conflicts:
#	include/etl/version.h
#	support/Release notes.txt
This commit is contained in:
John Wellbelove 2018-07-29 12:55:14 +01:00
parent bd008350a2
commit 0e38e6959a
16 changed files with 2261 additions and 156 deletions

View File

@ -32,14 +32,44 @@ SOFTWARE.
#define ETL_MEMORY_MODEL_INCLUDED
#include "user_type.h"
#include <stdint.h>
#include "type_lookup.h"
namespace etl
{
ETL_DECLARE_USER_TYPE(memory_model, int)
ETL_USER_TYPE(MM_SMALL, 0)
ETL_USER_TYPE(MM_MEDIUM, 1)
ETL_USER_TYPE(MM_LARGE, 2)
ETL_USER_TYPE(MEMORY_MODEL_SMALL, 0)
ETL_USER_TYPE(MEMORY_MODEL_MEDIUM, 1)
ETL_USER_TYPE(MEMORY_MODEL_LARGE, 2)
ETL_USER_TYPE(MEMORY_MODEL_HUGE, 3)
ETL_END_USER_TYPE(memory_model)
template <const size_t MEMORY_MODEL>
struct size_type_lookup;
template <>
struct size_type_lookup<etl::memory_model::MEMORY_MODEL_SMALL>
{
typedef uint_least8_t type;
};
template <>
struct size_type_lookup<etl::memory_model::MEMORY_MODEL_MEDIUM>
{
typedef uint_least16_t type;
};
template <>
struct size_type_lookup<etl::memory_model::MEMORY_MODEL_LARGE>
{
typedef uint_least32_t type;
};
template <>
struct size_type_lookup<etl::memory_model::MEMORY_MODEL_HUGE>
{
typedef uint_least64_t type;
};
}
#endif

View File

@ -319,7 +319,7 @@ namespace etl
/// Returns the remaining capacity.
///\return The remaining capacity.
//*************************************************************************
size_t available() const
size_type available() const
{
return container.max_size() - container.size();
}
@ -372,7 +372,9 @@ namespace etl
{
public:
static const size_t MAX_SIZE = SIZE;
typedef typename TContainer::size_type size_type;
static const size_type MAX_SIZE = size_type(SIZE);
//*************************************************************************
/// Default constructor.

View File

@ -43,6 +43,8 @@ SOFTWARE.
#include "debug_count.h"
#include "type_traits.h"
#include "parameter_type.h"
#include "memory_model.h"
#include "integral_limits.h"
#undef ETL_FILE
#define ETL_FILE "13"
@ -102,11 +104,13 @@ namespace etl
/// The base class for all queues.
///\ingroup queue
//***************************************************************************
template <const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_base
{
public:
typedef size_t size_type; ///< The type used for determining the size of queue.
/// The type used for determining the size of queue.
typedef typename etl::size_type_lookup<MEMORY_MODEL>::type size_type;
//*************************************************************************
/// Returns the current number of items in the queue.
@ -154,7 +158,7 @@ namespace etl
/// Returns the remaining capacity.
///\return The remaining capacity.
//*************************************************************************
size_t available() const
size_type available() const
{
return max_size() - size();
}
@ -217,8 +221,8 @@ namespace etl
ETL_RESET_DEBUG_COUNT;
}
size_type in; ///< Where to input new data.
size_type out; ///< Where to get the oldest data.
size_type in; ///< Where to input new data.
size_type out; ///< Where to get the oldest data.
size_type current_size; ///< The number of items in the queue.
const size_type CAPACITY; ///< The maximum number of items in the queue.
ETL_DECLARE_DEBUG_COUNT; ///< For internal debugging purposes.
@ -236,25 +240,32 @@ namespace etl
/// \warning This queue cannot be used for concurrent access from multiple threads.
/// \tparam T The type of value that the queue holds.
//***************************************************************************
template <typename T>
class iqueue : public etl::queue_base
template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class iqueue : public etl::queue_base<MEMORY_MODEL>
{
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 T* pointer; ///< A pointer to the type used in the queue.
typedef const T* const_pointer; ///< A const pointer to the type used in the queue.
typedef queue_base::size_type size_type; ///< The type used for determining the size of the queue.
private:
typedef typename etl::parameter_type<T>::type parameter_t;
typedef typename etl::queue_base base_t;
typedef typename etl::parameter_type<T>::type parameter_t;
typedef typename etl::queue_base<MEMORY_MODEL> base_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 T* pointer; ///< A pointer to the type used in the queue.
typedef const T* const_pointer; ///< A const pointer to the type used in the queue.
typedef typename base_t::size_type size_type; ///< The type used for determining the size of the queue.
using base_t::in;
using base_t::out;
using base_t::CAPACITY;
using base_t::current_size;
using base_t::full;
using base_t::empty;
using base_t::add_in;
using base_t::del_out;
//*************************************************************************
/// Gets a reference to the value at the front of the queue.<br>
/// \return A reference to the value at the front of the queue.
@ -302,7 +313,7 @@ namespace etl
ETL_ASSERT(!full(), ETL_ERROR(queue_full));
#endif
::new (&p_buffer[in]) T(value);
base_t::add_in();
add_in();
}
//*************************************************************************
@ -319,7 +330,7 @@ namespace etl
#if defined(ETL_CHECK_PUSH_POP)
ETL_ASSERT(!full(), ETL_ERROR(queue_full));
#endif
base_t::add_in();
add_in();
return p_buffer[next];
}
@ -336,7 +347,7 @@ namespace etl
ETL_ASSERT(!full(), ETL_ERROR(queue_full));
#endif
::new (&p_buffer[in]) T(value1);
base_t::add_in();
add_in();
}
//*************************************************************************
@ -351,7 +362,7 @@ namespace etl
ETL_ASSERT(!full(), ETL_ERROR(queue_full));
#endif
::new (&p_buffer[in]) T(value1, value2);
base_t::add_in();
add_in();
}
//*************************************************************************
@ -366,7 +377,7 @@ namespace etl
ETL_ASSERT(!full(), ETL_ERROR(queue_full));
#endif
::new (&p_buffer[in]) T(value1, value2, value3);
base_t::add_in();
add_in();
}
//*************************************************************************
@ -381,7 +392,7 @@ namespace etl
ETL_ASSERT(!full(), ETL_ERROR(queue_full));
#endif
::new (&p_buffer[in]) T(value1, value2, value3, value4);
base_t::add_in();
add_in();
}
//*************************************************************************
@ -398,7 +409,7 @@ namespace etl
while (current_size > 0)
{
p_buffer[out].~T();
base_t::del_out();
del_out();
}
in = 0;
@ -417,7 +428,7 @@ namespace etl
ETL_ASSERT(!empty(), ETL_ERROR(queue_empty));
#endif
p_buffer[out].~T();
base_t::del_out();
del_out();
}
//*************************************************************************
@ -466,9 +477,9 @@ namespace etl
{
clear();
size_t index = other.out;
size_type index = other.out;
for (size_t i = 0; i < other.size(); ++i)
for (size_type i = 0; i < other.size(); ++i)
{
push(other.p_buffer[index]);
index = (index == (CAPACITY - 1)) ? 0 : index + 1;
@ -479,7 +490,7 @@ namespace etl
/// The constructor that is called from derived classes.
//*************************************************************************
iqueue(T* p_buffer_, size_type max_size_)
: queue_base(max_size_),
: base_t(max_size_),
p_buffer(p_buffer_)
{
}
@ -511,21 +522,30 @@ namespace etl
///\ingroup queue
/// A fixed capacity queue.
/// This queue does not support concurrent access by different threads.
/// \tparam T The type this queue should support.
/// \tparam SIZE The maximum capacity of the queue.
/// \tparam T The type this queue should support.
/// \tparam SIZE The maximum capacity of the queue.
/// \tparam MEMORY_MODEL The memory model for the queue. Determines the type of the internal counter variables.
//***************************************************************************
template <typename T, const size_t SIZE>
class queue : public etl::iqueue<T>
template <typename T, const size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue : public etl::iqueue<T, MEMORY_MODEL>
{
private:
typedef etl::iqueue<T, MEMORY_MODEL> base_t;
public:
static const size_t MAX_SIZE = SIZE;
typedef typename base_t::size_type size_type;
ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
static const size_type MAX_SIZE = size_type(SIZE);
//*************************************************************************
/// Default constructor.
//*************************************************************************
queue()
: etl::iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
: base_t(reinterpret_cast<T*>(&buffer[0]), SIZE)
{
}
@ -533,9 +553,9 @@ namespace etl
/// Copy constructor
//*************************************************************************
queue(const queue& rhs)
: etl::iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE)
: base_t(reinterpret_cast<T*>(&buffer[0]), SIZE)
{
etl::iqueue<T>::clone(rhs);
base_t::clone(rhs);
}
//*************************************************************************
@ -543,7 +563,7 @@ namespace etl
//*************************************************************************
~queue()
{
etl::iqueue<T>::clear();
base_t::clear();
}
//*************************************************************************
@ -553,7 +573,7 @@ namespace etl
{
if (&rhs != this)
{
etl::iqueue<T>::clone(rhs);
base_t::clone(rhs);
}
return *this;

View File

@ -38,20 +38,26 @@ SOFTWARE.
#include "alignment.h"
#include "parameter_type.h"
#include "mutex.h"
#include "memory_model.h"
#include "integral_limits.h"
#undef ETL_FILE
#define ETL_FILE "48"
namespace etl
{
template <const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_mpmc_mutex_base
{
public:
/// The type used for determining the size of queue.
typedef typename etl::size_type_lookup<MEMORY_MODEL>::type size_type;
//*************************************************************************
/// How many items can the queue hold.
//*************************************************************************
size_t capacity() const
size_type capacity() const
{
return MAX_SIZE;
}
@ -59,14 +65,14 @@ namespace etl
//*************************************************************************
/// How many items can the queue hold.
//*************************************************************************
size_t max_size() const
size_type max_size() const
{
return MAX_SIZE;
}
protected:
queue_mpmc_mutex_base(size_t max_size_)
queue_mpmc_mutex_base(size_type max_size_)
: write_index(0),
read_index(0),
current_size(0),
@ -77,7 +83,7 @@ namespace etl
//*************************************************************************
/// Calculate the next index.
//*************************************************************************
static size_t get_next_index(size_t index, size_t maximum)
static size_type get_next_index(size_type index, size_type maximum)
{
++index;
@ -89,10 +95,10 @@ namespace etl
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.
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.
//*************************************************************************
/// Destructor.
@ -121,19 +127,26 @@ namespace etl
/// 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
template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class iqueue_mpmc_mutex : public queue_mpmc_mutex_base<MEMORY_MODEL>
{
protected:
private:
typedef typename etl::parameter_type<T>::type parameter_t;
typedef typename etl::parameter_type<T>::type parameter_t;
typedef etl::queue_mpmc_mutex_base<MEMORY_MODEL> base_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.
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 typename base_t::size_type size_type; ///< The type used for determining the size of the queue.
using base_t::write_index;
using base_t::read_index;
using base_t::current_size;
using base_t::MAX_SIZE;
using base_t::get_next_index;
//*************************************************************************
/// Push a value to the queue.
@ -199,7 +212,7 @@ namespace etl
{
access.lock();
size_t result = (current_size == 0);
size_type result = (current_size == 0);
access.unlock();
@ -213,7 +226,7 @@ namespace etl
{
access.lock();
size_t result = (current_size == MAX_SIZE);
size_type result = (current_size == MAX_SIZE);
access.unlock();
@ -223,11 +236,11 @@ namespace etl
//*************************************************************************
/// How many items in the queue?
//*************************************************************************
size_t size() const
size_type size() const
{
access.lock();
size_t result = current_size;
size_type result = current_size;
access.unlock();
@ -237,11 +250,11 @@ namespace etl
//*************************************************************************
/// How much free space available in the queue.
//*************************************************************************
size_t available() const
size_type available() const
{
access.lock();
size_t result = MAX_SIZE - current_size;
size_type result = MAX_SIZE - current_size;
access.unlock();
@ -254,7 +267,7 @@ namespace etl
/// The constructor that is called from derived classes.
//*************************************************************************
iqueue_mpmc_mutex(T* p_buffer_, size_type max_size_)
: queue_mpmc_mutex_base(max_size_),
: base_t(max_size_),
p_buffer(p_buffer_)
{
}
@ -335,17 +348,24 @@ namespace etl
///\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.
/// \tparam T The type this queue should support.
/// \tparam SIZE The maximum capacity of the queue.
/// \tparam MEMORY_MODEL The memory model for the queue. Determines the type of the internal counter variables.
//***************************************************************************
template <typename T, size_t SIZE>
class queue_mpmc_mutex : public etl::iqueue_mpmc_mutex<T>
template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_mpmc_mutex : public etl::iqueue_mpmc_mutex<T, MEMORY_MODEL>
{
typedef etl::iqueue_mpmc_mutex<T> base_t;
private:
typedef etl::iqueue_mpmc_mutex<T, MEMORY_MODEL> base_t;
public:
static const size_t MAX_SIZE = SIZE;
typedef typename base_t::size_type size_type;
ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
static const size_type MAX_SIZE = size_type(SIZE);
//*************************************************************************
/// Default constructor.

View File

@ -38,16 +38,22 @@ SOFTWARE.
#include "alignment.h"
#include "parameter_type.h"
#include "atomic.h"
#include "memory_model.h"
#include "integral_limits.h"
#undef ETL_FILE
#define ETL_FILE "47"
namespace etl
{
template <const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_spsc_atomic_base
{
public:
/// The type used for determining the size of queue.
typedef typename etl::size_type_lookup<MEMORY_MODEL>::type size_type;
//*************************************************************************
/// Is the queue empty?
/// Accurate from the 'pop' thread.
@ -65,7 +71,7 @@ namespace etl
//*************************************************************************
bool full() const
{
size_t next_index = get_next_index(write.load(etl::memory_order_acquire), RESERVED);
size_type next_index = get_next_index(write.load(etl::memory_order_acquire), RESERVED);
return (next_index == read.load(etl::memory_order_acquire));
}
@ -74,12 +80,12 @@ namespace etl
/// How many items in the queue?
/// Due to concurrency, this is a guess.
//*************************************************************************
size_t size() const
size_type size() const
{
size_t write_index = write.load(etl::memory_order_acquire);
size_t read_index = read.load(etl::memory_order_acquire);
size_type write_index = write.load(etl::memory_order_acquire);
size_type read_index = read.load(etl::memory_order_acquire);
size_t n;
size_type n;
if (write_index >= read_index)
{
@ -97,7 +103,7 @@ namespace etl
/// How much free space available in the queue.
/// Due to concurrency, this is a guess.
//*************************************************************************
size_t available() const
size_type available() const
{
return RESERVED - size() - 1;
}
@ -105,7 +111,7 @@ namespace etl
//*************************************************************************
/// How many items can the queue hold.
//*************************************************************************
size_t capacity() const
size_type capacity() const
{
return RESERVED - 1;
}
@ -113,14 +119,14 @@ namespace etl
//*************************************************************************
/// How many items can the queue hold.
//*************************************************************************
size_t max_size() const
size_type max_size() const
{
return RESERVED - 1;
}
protected:
queue_spsc_atomic_base(size_t reserved_)
queue_spsc_atomic_base(size_type reserved_)
: write(0),
read(0),
RESERVED(reserved_)
@ -130,7 +136,7 @@ namespace etl
//*************************************************************************
/// Calculate the next index.
//*************************************************************************
static size_t get_next_index(size_t index, size_t maximum)
static size_type get_next_index(size_type index, size_type maximum)
{
++index;
@ -142,9 +148,9 @@ namespace etl
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.
etl::atomic<size_type> write; ///< Where to input new data.
etl::atomic<size_type> read; ///< Where to get the oldest data.
const size_type RESERVED; ///< The maximum number of items in the queue.
private:
@ -163,7 +169,7 @@ namespace etl
}
#endif
};
//***************************************************************************
///\ingroup queue_spsc_atomic
///\brief This is the base for all queue_spscs that contain a particular type.
@ -175,27 +181,33 @@ namespace etl
/// 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
template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class iqueue_spsc_atomic : public queue_spsc_atomic_base<MEMORY_MODEL>
{
private:
typedef typename etl::parameter_type<T>::type parameter_t;
typedef typename etl::parameter_type<T>::type parameter_t;
typedef typename etl::queue_spsc_atomic_base<MEMORY_MODEL> base_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.
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 typename base_t::size_type size_type; ///< The type used for determining the size of the queue.
using base_t::write;
using base_t::read;
using base_t::RESERVED;
using base_t::get_next_index;
//*************************************************************************
/// 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);
size_type write_index = write.load(etl::memory_order_relaxed);
size_type next_index = get_next_index(write_index, RESERVED);
if (next_index != read.load(etl::memory_order_acquire))
{
@ -205,7 +217,7 @@ namespace etl
return true;
}
// Queue is full.
return false;
}
@ -214,16 +226,16 @@ namespace etl
/// 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))
{
size_type 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);
size_type next_index = get_next_index(read_index, RESERVED);
value = p_buffer[read_index];
p_buffer[read_index].~T();
@ -238,7 +250,7 @@ namespace etl
//*************************************************************************
bool pop()
{
size_t read_index = read.load(etl::memory_order_relaxed);
size_type read_index = read.load(etl::memory_order_relaxed);
if (read_index == write.load(etl::memory_order_acquire))
{
@ -246,7 +258,7 @@ namespace etl
return false;
}
size_t next_index = get_next_index(read_index, RESERVED);
size_type next_index = get_next_index(read_index, RESERVED);
p_buffer[read_index].~T();
@ -274,7 +286,7 @@ namespace etl
/// The constructor that is called from derived classes.
//*************************************************************************
iqueue_spsc_atomic(T* p_buffer_, size_type reserved_)
: queue_spsc_atomic_base(reserved_),
: base_t(reserved_),
p_buffer(p_buffer_)
{
}
@ -292,19 +304,30 @@ namespace etl
///\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 T The type this queue should support.
/// \tparam SIZE The maximum capacity of the queue.
/// \tparam MEMORY_MODEL The memory model for the queue. Determines the type of the internal counter variables.
//***************************************************************************
template <typename T, size_t SIZE>
class queue_spsc_atomic : public iqueue_spsc_atomic<T>
template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_spsc_atomic : public iqueue_spsc_atomic<T, MEMORY_MODEL>
{
typedef etl::iqueue_spsc_atomic<T> base_t;
private:
static const size_t RESERVED_SIZE = SIZE + 1;
typedef typename etl::iqueue_spsc_atomic<T, MEMORY_MODEL> base_t;
public:
static const size_t MAX_SIZE = SIZE;
typedef typename base_t::size_type size_type;
private:
static const size_type RESERVED_SIZE = size_type(SIZE + 1);
public:
ETL_STATIC_ASSERT((SIZE <= (etl::integral_limits<size_type>::max - 1)), "Size too large for memory model");
static const size_type MAX_SIZE = size_type(SIZE);
//*************************************************************************
/// Default constructor.
@ -329,4 +352,4 @@ namespace etl
};
};
#endif
#endif

View File

@ -37,13 +37,15 @@ SOFTWARE.
#include "platform.h"
#include "alignment.h"
#include "parameter_type.h"
#include "memory_model.h"
#include "integral_limits.h"
#undef ETL_FILE
#define ETL_FILE "46"
namespace etl
{
template <typename T>
template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_spsc_isr_base
{
protected:
@ -52,10 +54,12 @@ namespace etl
public:
/// The type used for determining the size of queue.
typedef typename etl::size_type_lookup<MEMORY_MODEL>::type size_type;
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.
@ -85,7 +89,7 @@ namespace etl
/// How much free space available in the queue.
/// Called from ISR.
//*************************************************************************
size_t available_from_isr() const
size_type available_from_isr() const
{
return MAX_SIZE - current_size;
}
@ -123,7 +127,7 @@ namespace etl
/// How many items in the queue?
/// Called from ISR.
//*************************************************************************
size_t size_from_isr() const
size_type size_from_isr() const
{
return current_size;
}
@ -131,7 +135,7 @@ namespace etl
//*************************************************************************
/// How many items can the queue hold.
//*************************************************************************
size_t capacity() const
size_type capacity() const
{
return MAX_SIZE;
}
@ -139,7 +143,7 @@ namespace etl
//*************************************************************************
/// How many items can the queue hold.
//*************************************************************************
size_t max_size() const
size_type max_size() const
{
return MAX_SIZE;
}
@ -219,7 +223,7 @@ namespace etl
//*************************************************************************
/// Calculate the next index.
//*************************************************************************
static size_t get_next_index(size_t index, size_t maximum)
static size_type get_next_index(size_type index, size_type maximum)
{
++index;
@ -266,19 +270,20 @@ namespace etl
/// 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>
template <typename T, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class iqueue_spsc_isr : public queue_spsc_isr_base<T, MEMORY_MODEL>
{
private:
typedef typename queue_spsc_isr_base<T>::parameter_t parameter_t;
typedef queue_spsc_isr_base<T, MEMORY_MODEL> base_t;
typedef typename 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.
typedef typename base_t::value_type value_type; ///< The type stored in the queue.
typedef typename base_t::reference reference; ///< A reference to the type used in the queue.
typedef typename base_t::const_reference const_reference; ///< A const reference to the type used in the queue.
typedef typename base_t::size_type size_type; ///< The type used for determining the size of the queue.
//*************************************************************************
/// Push a value to the queue.
@ -344,7 +349,7 @@ namespace etl
{
TAccess::lock();
size_t result = (this->current_size == 0);
size_type result = (this->current_size == 0);
TAccess::unlock();
@ -358,7 +363,7 @@ namespace etl
{
TAccess::lock();
size_t result = (this->current_size == this->MAX_SIZE);
size_type result = (this->current_size == this->MAX_SIZE);
TAccess::unlock();
@ -368,11 +373,11 @@ namespace etl
//*************************************************************************
/// How many items in the queue?
//*************************************************************************
size_t size() const
size_type size() const
{
TAccess::lock();
size_t result = this->current_size;
size_type result = this->current_size;
TAccess::unlock();
@ -382,11 +387,11 @@ namespace etl
//*************************************************************************
/// How much free space available in the queue.
//*************************************************************************
size_t available() const
size_type available() const
{
TAccess::lock();
size_t result = this->MAX_SIZE - this->current_size;
size_type result = this->MAX_SIZE - this->current_size;
TAccess::unlock();
@ -399,7 +404,7 @@ namespace etl
/// 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_)
: base_t(p_buffer_, max_size_)
{
}
@ -416,18 +421,25 @@ namespace etl
///\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.
/// \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.
/// \tparam MEMORY_MODEL The memory model for the queue. Determines the type of the internal counter variables.
//***************************************************************************
template <typename T, size_t SIZE, typename TAccess>
class queue_spsc_isr : public etl::iqueue_spsc_isr<T, TAccess>
template <typename T, size_t SIZE, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_spsc_isr : public etl::iqueue_spsc_isr<T, TAccess, MEMORY_MODEL>
{
typedef etl::iqueue_spsc_isr<T, TAccess> base_t;
private:
typedef etl::iqueue_spsc_isr<T, TAccess, MEMORY_MODEL> base_t;
public:
static const size_t MAX_SIZE = SIZE;
typedef typename base_t::size_type size_type;
ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
static const size_type MAX_SIZE = size_type(SIZE);
//*************************************************************************
/// Default constructor.

View File

@ -37,13 +37,13 @@ SOFTWARE.
/// Definitions of the ETL version
///\ingroup utilities
#define ETL_VERSION "11.14.3"
#define ETL_VERSION_W L"11.14.3"
#define ETL_VERSION_U16 u"11.14.3"
#define ETL_VERSION_U32 U"11.14.3"
#define ETL_VERSION "11.15.0"
#define ETL_VERSION_W L"11.15.0"
#define ETL_VERSION_U16 u"11.15.0"
#define ETL_VERSION_U32 U"11.15.0"
#define ETL_VERSION_MAJOR 11
#define ETL_VERSION_MINOR 14
#define ETL_VERSION_PATCH 3
#define ETL_VERSION_MINOR 15
#define ETL_VERSION_PATCH 0
#define ETL_VERSION_VALUE ((ETL_VERSION_MAJOR * 10000) + (ETL_VERSION_MINOR * 100) + ETL_VERSION_PATCH)
#endif

View File

@ -1,3 +1,15 @@
===============================================================================
11.15.0
Added 'memory model' selection for queues to allow more efficient implementations.
Maximum queue sizes:
MEMORY_MODEL_SMALL 255 (254 for queue_spsc_atomic)
MEMORY_MODEL_MEDIUM 65535
MEMORY_MODEL_LARGE 2147483647
MEMORY_MODEL_HUGE 9223372036854775807
Fixed syntax errors highlighted by GCC v8
===============================================================================
11.14.2
Removed reference_flat_set & reference_flat_map reliance on equality.

View File

@ -406,9 +406,13 @@
<Unit filename="../test_pool.cpp" />
<Unit filename="../test_priority_queue.cpp" />
<Unit filename="../test_queue.cpp" />
<Unit filename="../test_queue_memory_model_small.cpp" />
<Unit filename="../test_queue_mpmc_mutex.cpp" />
<Unit filename="../test_queue_mpmc_mutex_small.cpp" />
<Unit filename="../test_queue_spsc_atomic.cpp" />
<Unit filename="../test_queue_spsc_atomic_small.cpp" />
<Unit filename="../test_queue_spsc_isr.cpp" />
<Unit filename="../test_queue_spsc_isr_small.cpp" />
<Unit filename="../test_random.cpp" />
<Unit filename="../test_reference_flat_map.cpp" />
<Unit filename="../test_reference_flat_multimap.cpp" />

View File

@ -0,0 +1,589 @@
/******************************************************************************
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.
******************************************************************************/
#include "UnitTest++.h"
#include <queue>
#include "etl/queue.h"
namespace
{
struct Item
{
Item(char c_, int i_, double d_)
: c(c_),
i(i_),
d(d_)
{
}
char c;
int i;
double d;
};
bool operator == (const Item& lhs, const Item& rhs)
{
return (lhs.c == rhs.c) && (lhs.i == rhs.i) && (lhs.d == rhs.d);
}
struct ItemNTD
{
ItemNTD()
{
p = new char;
}
ItemNTD(const ItemNTD&)
: p(new char)
{
}
~ItemNTD()
{
delete p;
}
char* p;
};
typedef etl::queue<int, 4, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt;
typedef etl::iqueue<int, etl::memory_model::MEMORY_MODEL_SMALL> IQueueInt;
typedef etl::queue<ItemNTD, 4, etl::memory_model::MEMORY_MODEL_SMALL> QueueItemNTD;
typedef etl::iqueue<ItemNTD, etl::memory_model::MEMORY_MODEL_SMALL> IQueueItemNTD;
typedef etl::queue<int, 255, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt255;
SUITE(test_queue)
{
//*************************************************************************
TEST(test_copy_constructor)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
QueueInt queue2(queue);
CHECK(queue.size() == queue2.size());
while (!queue.empty())
{
CHECK_EQUAL(queue.front(), queue2.front());
queue.pop();
queue2.pop();
}
}
//*************************************************************************
TEST(test_delete_via_iqueue)
{
QueueInt* pqueue = new QueueInt;
IQueueInt* piqueue = pqueue;
piqueue->push(1);
piqueue->push(2);
piqueue->push(3);
piqueue->push(4);
delete piqueue;
}
//*************************************************************************
TEST(test_size)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.push(3);
CHECK_EQUAL(3U, queue.size());
}
//*************************************************************************
TEST(test_clear)
{
QueueInt queue;
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_clear_non_pod)
{
QueueItemNTD queue;
queue.push(ItemNTD());
queue.push(ItemNTD());
queue.clear();
CHECK_EQUAL(0U, queue.size());
// Do it again to check that clear() didn't screw up the internals.
queue.push(ItemNTD());
queue.push(ItemNTD());
CHECK_EQUAL(2U, queue.size());
queue.clear();
CHECK_EQUAL(0U, queue.size());
}
//*************************************************************************
TEST(test_empty)
{
QueueInt queue;
CHECK(queue.empty());
queue.push(1);
CHECK(!queue.empty());
}
//*************************************************************************
TEST(test_full)
{
QueueInt queue;
CHECK(!queue.full());
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
CHECK(queue.full());
}
//*************************************************************************
TEST(test_front)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.push(3);
CHECK_EQUAL(1, queue.front());
queue.pop();
CHECK_EQUAL(2, queue.front());
queue.pop();
CHECK_EQUAL(3, queue.front());
}
//*************************************************************************
TEST(test_front_const)
{
QueueInt queue;
const QueueInt& constQueue = queue;
queue.push(1);
queue.push(2);
queue.push(3);
CHECK_EQUAL(1, constQueue.front());
queue.pop();
CHECK_EQUAL(2, constQueue.front());
queue.pop();
CHECK_EQUAL(3, constQueue.front());
}
//*************************************************************************
TEST(test_back)
{
QueueInt queue;
queue.push(1);
CHECK_EQUAL(1, queue.back());
queue.push(2);
CHECK_EQUAL(2, queue.back());
queue.push(3);
CHECK_EQUAL(3, queue.back());
}
//*************************************************************************
TEST(test_back_const)
{
QueueInt queue;
const QueueInt& constQueue = queue;
queue.push(1);
CHECK_EQUAL(1, constQueue.back());
queue.push(2);
CHECK_EQUAL(2, constQueue.back());
queue.push(3);
CHECK_EQUAL(3, constQueue.back());
}
//*************************************************************************
TEST(test_push)
{
QueueInt queue;
queue.push(1);
CHECK_EQUAL(1U, queue.size());
queue.push(2);
CHECK_EQUAL(2U, queue.size());
CHECK_EQUAL(1, queue.front());
queue.pop();
CHECK_EQUAL(2, queue.front());
}
//*************************************************************************
TEST(test_push_255)
{
QueueInt255 queue;
for (int i = 0; i < 255; ++i)
{
queue.push(i);
}
CHECK_EQUAL(255U, queue.size());
}
//*************************************************************************
TEST(test_push_void)
{
QueueInt queue;
queue.push() = 1;
CHECK_EQUAL(1U, queue.size());
queue.push() = 2;
CHECK_EQUAL(2U, queue.size());
CHECK_EQUAL(1, queue.front());
queue.pop();
CHECK_EQUAL(2, queue.front());
}
//*************************************************************************
TEST(test_push_excess)
{
QueueInt queue;
for (size_t i = 0; i < queue.max_size(); ++i)
{
queue.push(1);
}
CHECK_THROW(queue.push(1), etl::queue_full);
}
//*************************************************************************
TEST(test_multiple_push)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.push(3);
bool pass = true;
if (queue.front() != 1)
{
pass = false;
}
queue.pop();
if (queue.front() != 2)
{
pass = false;
}
queue.pop();
if (queue.front() != 3)
{
pass = false;
}
CHECK(pass);
}
//*************************************************************************
TEST(test_multiple_emplace)
{
etl::queue<Item, 4> queue;
queue.emplace('a', 1, 1.2);
queue.emplace('b', 2, 3.4);
queue.emplace('c', 3, 5.6);
queue.emplace('d', 4, 7.8);
CHECK(queue.front() == Item('a', 1, 1.2));
queue.pop();
CHECK(queue.front() == Item('b', 2, 3.4));
queue.pop();
CHECK(queue.front() == Item('c', 3, 5.6));
queue.pop();
CHECK(queue.front() == Item('d', 4, 7.8));
queue.pop();
}
//*************************************************************************
TEST(test_multiple_push_void)
{
QueueInt queue;
queue.push() = 1;
queue.push() = 2;
queue.push() = 3;
bool pass = true;
if (queue.front() != 1)
{
pass = false;
}
queue.pop();
if (queue.front() != 2)
{
pass = false;
}
queue.pop();
if (queue.front() != 3)
{
pass = false;
}
CHECK(pass);
}
//*************************************************************************
TEST(test_pop)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.pop();
CHECK_EQUAL(1U, queue.size());
}
//*************************************************************************
TEST(test_pop_into)
{
QueueInt queue;
int i;
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
queue.pop_into(i);
CHECK_EQUAL(1, i);
CHECK_EQUAL(3U, queue.size());
queue.pop_into(i);
CHECK_EQUAL(2, i);
CHECK_EQUAL(2U, queue.size());
queue.pop_into(i);
CHECK_EQUAL(3, i);
CHECK_EQUAL(1U, queue.size());
queue.pop_into(i);
CHECK_EQUAL(4, i);
CHECK_EQUAL(0U, queue.size());
}
//*************************************************************************
TEST(test_pop_into_queue)
{
QueueInt queue1;
QueueInt queue2;
queue1.push(1);
queue1.push(2);
queue1.push(3);
queue1.push(4);
queue1.pop_into(queue2);
CHECK_EQUAL(1U, queue2.size());
CHECK_EQUAL(1, queue2.front());
CHECK_EQUAL(1, queue2.back());
queue1.pop_into(queue2);
CHECK_EQUAL(2U, queue2.size());
CHECK_EQUAL(1, queue2.front());
CHECK_EQUAL(2, queue2.back());
queue1.pop_into(queue2);
CHECK_EQUAL(3U, queue2.size());
CHECK_EQUAL(1, queue2.front());
CHECK_EQUAL(3, queue2.back());
queue1.pop_into(queue2);
CHECK_EQUAL(4U, queue2.size());
CHECK_EQUAL(1, queue2.front());
CHECK_EQUAL(4, queue2.back());
int i;
queue2.pop_into(i);
CHECK_EQUAL(1, i);
queue2.pop_into(i);
CHECK_EQUAL(2, i);
queue2.pop_into(i);
CHECK_EQUAL(3, i);
queue2.pop_into(i);
CHECK_EQUAL(4, i);
}
//*************************************************************************
TEST(test_pop_exception)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.pop();
queue.pop();
CHECK_THROW(queue.pop(), etl::queue_empty);
}
//*************************************************************************
TEST(test_assignment)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
QueueInt queue2;
queue2 = queue;
CHECK(queue.size() == queue2.size());
while (!queue.empty())
{
CHECK_EQUAL(queue.front(), queue2.front());
queue.pop();
queue2.pop();
}
}
//*************************************************************************
TEST(test_assignment_interface)
{
QueueInt queue1;
queue1.push(1);
queue1.push(2);
queue1.push(3);
queue1.push(4);
QueueInt queue2;
IQueueInt& iqueue1 = queue1;
IQueueInt& iqueue2 = queue2;
iqueue2 = iqueue1;
CHECK(queue1.size() == queue2.size());
while (!queue1.empty())
{
CHECK_EQUAL(queue1.front(), queue2.front());
queue1.pop();
queue2.pop();
}
}
//*************************************************************************
TEST(test_self_assignment)
{
QueueInt queue;
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
queue = queue;
CHECK(queue.max_size() == queue.size());
CHECK_EQUAL(1, queue.front());
queue.pop();
CHECK_EQUAL(2, queue.front());
queue.pop();
CHECK_EQUAL(3, queue.front());
queue.pop();
CHECK_EQUAL(4, queue.front());
queue.pop();
}
};
}

View File

@ -69,17 +69,17 @@ namespace
int d;
};
bool operator ==(const Data& lhs, const Data& rhs)
{
return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d);
}
// bool operator ==(const Data& lhs, const Data& rhs)
// {
// return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d);
// }
std::ostream& operator <<(std::ostream& os, const Data& data)
{
os << data.a << " " << data.b << " " << data.c << " " << data.d;
return os;
}
// std::ostream& operator <<(std::ostream& os, const Data& data)
// {
// os << data.a << " " << data.b << " " << data.c << " " << data.d;
//
// return os;
// }
SUITE(test_queue_mpmc_mutex)
{

View File

@ -0,0 +1,460 @@
/******************************************************************************
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.
******************************************************************************/
#include "UnitTest++.h"
#include <thread>
#include <chrono>
#include <vector>
#include <mutex>
#include <atomic>
#include <algorithm>
#include "etl/queue_mpmc_mutex.h"
#if defined(ETL_COMPILER_MICROSOFT)
#include <Windows.h>
#endif
#define REALTIME_TEST 1
namespace
{
struct Data
{
Data(int a_, int b_ = 2, int c_ = 3, int d_ = 4)
: a(a_),
b(b_),
c(c_),
d(d_)
{
}
Data()
: a(0),
b(0),
c(0),
d(0)
{
}
int a;
int b;
int c;
int d;
};
typedef etl::queue_mpmc_mutex<int, 4, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt;
typedef etl::iqueue_mpmc_mutex<int, etl::memory_model::MEMORY_MODEL_SMALL> IQueueInt;
typedef etl::queue_mpmc_mutex<int, 255, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt255;
// bool operator ==(const Data& lhs, const Data& rhs)
// {
// return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d);
// }
// std::ostream& operator <<(std::ostream& os, const Data& data)
// {
// os << data.a << " " << data.b << " " << data.c << " " << data.d;
//
// return os;
// }
SUITE(test_queue_mpmc_mutex)
{
//*************************************************************************
TEST(test_constructor)
{
QueueInt queue;
CHECK_EQUAL(4U, queue.max_size());
CHECK_EQUAL(4U, queue.capacity());
}
//*************************************************************************
TEST(test_size_push_pop)
{
QueueInt 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)
{
QueueInt queue;
IQueueInt& 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)
{
QueueInt 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_push_255)
{
QueueInt255 queue;
for (int i = 0; i < 255; ++i)
{
queue.push(i);
}
CHECK_EQUAL(255U, queue.size());
}
//*************************************************************************
TEST(test_clear)
{
QueueInt 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)
{
QueueInt queue;
CHECK(queue.empty());
queue.push(1);
CHECK(!queue.empty());
queue.clear();
CHECK(queue.empty());
queue.push(1);
CHECK(!queue.empty());
}
//*************************************************************************
TEST(test_full)
{
QueueInt 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
};
}

View File

@ -0,0 +1,330 @@
/******************************************************************************
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.
******************************************************************************/
#include "UnitTest++.h"
#include <thread>
#include <chrono>
#include <vector>
#include "etl/queue_spsc_atomic.h"
#if defined(ETL_COMPILER_MICROSOFT)
#include <Windows.h>
#endif
#define REALTIME_TEST 0
namespace
{
typedef etl::queue_spsc_atomic<int, 4, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt;
typedef etl::iqueue_spsc_atomic<int, etl::memory_model::MEMORY_MODEL_SMALL> IQueueInt;
typedef etl::queue_spsc_atomic<int, 254, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt254;
SUITE(test_queue_atomic)
{
//*************************************************************************
TEST(test_constructor)
{
QueueInt queue;
CHECK_EQUAL(4U, queue.max_size());
CHECK_EQUAL(4U, queue.capacity());
}
//*************************************************************************
TEST(test_size_push_pop)
{
QueueInt 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)
{
QueueInt queue;
IQueueInt& 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)
{
QueueInt 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_push_254)
{
QueueInt254 queue;
for (int i = 0; i < 254; ++i)
{
queue.push(i);
}
CHECK_EQUAL(254U, queue.size());
}
//*************************************************************************
TEST(test_clear)
{
QueueInt 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)
{
QueueInt queue;
CHECK(queue.empty());
queue.push(1);
CHECK(!queue.empty());
queue.clear();
CHECK(queue.empty());
queue.push(1);
CHECK(!queue.empty());
}
//*************************************************************************
TEST(test_full)
{
QueueInt 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
};
}

View File

@ -0,0 +1,587 @@
/******************************************************************************
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.
******************************************************************************/
#include "UnitTest++.h"
#include "etl/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;
typedef etl::queue_spsc_isr<int, 4, Access, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt;
typedef etl::iqueue_spsc_isr<int, Access, etl::memory_model::MEMORY_MODEL_SMALL> IQueueInt;
typedef etl::queue_spsc_isr<int, 255, Access, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt255;
SUITE(test_queue_isr)
{
//*************************************************************************
TEST(test_constructor)
{
Access::clear();
QueueInt 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();
QueueInt 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();
QueueInt queue;
IQueueInt& 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();
QueueInt 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_push_255)
{
QueueInt255 queue;
for (int i = 0; i < 255; ++i)
{
queue.push(i);
}
CHECK_EQUAL(255U, queue.size());
}
//*************************************************************************
TEST(test_clear)
{
Access::clear();
QueueInt 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();
QueueInt 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();
QueueInt 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
};
}

View File

@ -704,9 +704,13 @@
<ClCompile Include="..\test_pool.cpp" />
<ClCompile Include="..\test_priority_queue.cpp" />
<ClCompile Include="..\test_queue.cpp" />
<ClCompile Include="..\test_queue_memory_model_small.cpp" />
<ClCompile Include="..\test_queue_mpmc_mutex.cpp" />
<ClCompile Include="..\test_queue_mpmc_mutex_small.cpp" />
<ClCompile Include="..\test_queue_spsc_atomic.cpp" />
<ClCompile Include="..\test_queue_spsc_atomic_small.cpp" />
<ClCompile Include="..\test_queue_spsc_isr.cpp" />
<ClCompile Include="..\test_queue_spsc_isr_small.cpp" />
<ClCompile Include="..\test_random.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>

View File

@ -1109,6 +1109,18 @@
<ClCompile Include="..\test_no_stl_limits.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_queue_memory_model_small.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_queue_mpmc_mutex_small.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_queue_spsc_atomic_small.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_queue_spsc_isr_small.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">