mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Merge remote-tracking branch 'origin/feature/memory_models' into development
# Conflicts: # include/etl/version.h # support/Release notes.txt
This commit is contained in:
parent
bd008350a2
commit
0e38e6959a
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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" />
|
||||
|
||||
589
test/test_queue_memory_model_small.cpp
Normal file
589
test/test_queue_memory_model_small.cpp
Normal 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();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
|
||||
460
test/test_queue_mpmc_mutex_small.cpp
Normal file
460
test/test_queue_mpmc_mutex_small.cpp
Normal 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
|
||||
};
|
||||
}
|
||||
330
test/test_queue_spsc_atomic_small.cpp
Normal file
330
test/test_queue_spsc_atomic_small.cpp
Normal 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
|
||||
};
|
||||
}
|
||||
587
test/test_queue_spsc_isr_small.cpp
Normal file
587
test/test_queue_spsc_isr_small.cpp
Normal 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
|
||||
};
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -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">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user