mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Added ilockable interface & queue_lockable
This commit is contained in:
parent
656e27f3e3
commit
d8ad89c21b
@ -263,7 +263,7 @@ namespace etl
|
||||
struct iterator : public etl::iterator<ETL_OR_STD::random_access_iterator_tag, T>
|
||||
{
|
||||
friend class ideque;
|
||||
friend struct const_iterator;
|
||||
friend struct ideque::const_iterator;
|
||||
|
||||
//***************************************************
|
||||
iterator()
|
||||
|
||||
@ -43,8 +43,8 @@ namespace etl
|
||||
public:
|
||||
|
||||
virtual ~ilockable() {}
|
||||
virtual void lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
virtual void lock() const = 0;
|
||||
virtual void unlock() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ namespace etl
|
||||
/// The pool lock function.
|
||||
/// Override to add thread or interrupt locking to the pool.
|
||||
//***************************************************************************
|
||||
virtual void lock() ETL_OVERRIDE
|
||||
virtual void lock() const ETL_OVERRIDE
|
||||
{
|
||||
// The default implementation does nothing.
|
||||
}
|
||||
@ -61,7 +61,7 @@ namespace etl
|
||||
/// The pool unlock function.
|
||||
/// Override to add thread or interrupt unlocking to the pool.
|
||||
//***************************************************************************
|
||||
virtual void unlock() ETL_OVERRIDE
|
||||
virtual void unlock() const ETL_OVERRIDE
|
||||
{
|
||||
// The default implementation does nothing.
|
||||
}
|
||||
|
||||
780
include/etl/queue_lockable.h
Normal file
780
include/etl/queue_lockable.h
Normal file
@ -0,0 +1,780 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2019 jwellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ETL_QUEUE_LOCKABLE_INCLUDED
|
||||
#define ETL_QUEUE_LOCKABLE_INCLUDED
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "memory.h"
|
||||
#include "parameter_type.h"
|
||||
#include "memory_model.h"
|
||||
#include "integral_limits.h"
|
||||
#include "function.h"
|
||||
#include "utility.h"
|
||||
#include "placement_new.h"
|
||||
#include "ilockable.h"
|
||||
|
||||
#undef ETL_FILE
|
||||
#define ETL_FILE "54"
|
||||
|
||||
namespace etl
|
||||
{
|
||||
template <typename T, const size_t VMemory_Model = etl::memory_model::MEMORY_MODEL_LARGE>
|
||||
class iqueue_lockable_base
|
||||
{
|
||||
public:
|
||||
|
||||
/// The type used for determining the size of queue.
|
||||
typedef typename etl::size_type_lookup<VMemory_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.
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
typedef T&& rvalue_reference;///< An rvalue reference to the type used in the queue.
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
virtual ~iqueue_lockable_base()
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue from an ISR.
|
||||
//*************************************************************************
|
||||
bool push_from_unlocked(const_reference value)
|
||||
{
|
||||
return push_implementation(value);
|
||||
}
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue from an ISR.
|
||||
//*************************************************************************
|
||||
bool push_from_unlocked(rvalue_reference value)
|
||||
{
|
||||
return push_implementation(etl::move(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
///\param value The value to use to construct the item to push to the queue.
|
||||
//*************************************************************************
|
||||
#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03)
|
||||
template <typename ... Args>
|
||||
bool emplace_from_unlocked(Args&&... args)
|
||||
{
|
||||
return emplace_implementation(etl::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue from an ISR
|
||||
//*************************************************************************
|
||||
bool pop_from_unlocked(reference value)
|
||||
{
|
||||
return pop_implementation(value);
|
||||
}
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue from an ISR
|
||||
//*************************************************************************
|
||||
bool pop_from_unlocked(rvalue_reference value)
|
||||
{
|
||||
return pop_implementation(etl::move(value));
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue from an ISR, and discard.
|
||||
//*************************************************************************
|
||||
bool pop_from_unlocked()
|
||||
{
|
||||
return pop_implementation();
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How much free space available in the queue.
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
size_type available_from_unlocked() const
|
||||
{
|
||||
return Max_Size - current_size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Clear the queue from the ISR.
|
||||
//*************************************************************************
|
||||
void clear_from_unlocked()
|
||||
{
|
||||
while (pop_implementation())
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue empty?
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
bool empty_from_unlocked() const
|
||||
{
|
||||
return (current_size == 0);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue full?
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
bool full_from_unlocked() const
|
||||
{
|
||||
return (current_size == Max_Size);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items in the queue?
|
||||
/// Called from ISR.
|
||||
//*************************************************************************
|
||||
size_type size_from_unlocked() const
|
||||
{
|
||||
return current_size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_type capacity() const
|
||||
{
|
||||
return Max_Size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items can the queue hold.
|
||||
//*************************************************************************
|
||||
size_type max_size() const
|
||||
{
|
||||
return Max_Size;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
iqueue_lockable_base(T* p_buffer_, size_type max_size_)
|
||||
: p_buffer(p_buffer_),
|
||||
write_index(0),
|
||||
read_index(0),
|
||||
current_size(0),
|
||||
Max_Size(max_size_)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push_implementation(const_reference value)
|
||||
{
|
||||
if (current_size != Max_Size)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value);
|
||||
|
||||
write_index = get_next_index(write_index, Max_Size);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push_implementation(rvalue_reference value)
|
||||
{
|
||||
if (current_size != Max_Size)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(etl::move(value));
|
||||
|
||||
write_index = get_next_index(write_index, Max_Size);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03)
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
///\param value The value to use to construct the item to push to the queue.
|
||||
//*************************************************************************
|
||||
template <typename ... Args>
|
||||
bool emplace_implementation(Args&&... args)
|
||||
{
|
||||
if (current_size != Max_Size)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
|
||||
|
||||
write_index = get_next_index(write_index, Max_Size);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1>
|
||||
bool emplace_implementation(const T1& value1)
|
||||
{
|
||||
if (current_size != Max_Size)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value1);
|
||||
|
||||
write_index = get_next_index(write_index, Max_Size);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1, typename T2>
|
||||
bool emplace_implementation(const T1& value1, const T2& value2)
|
||||
{
|
||||
if (current_size != Max_Size)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value1, value2);
|
||||
|
||||
write_index = get_next_index(write_index, Max_Size);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1, typename T2, typename T3>
|
||||
bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
|
||||
{
|
||||
if (current_size != Max_Size)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value1, value2, value3);
|
||||
|
||||
write_index = get_next_index(write_index, Max_Size);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
|
||||
{
|
||||
if (current_size != Max_Size)
|
||||
{
|
||||
::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
|
||||
|
||||
write_index = get_next_index(write_index, Max_Size);
|
||||
|
||||
++current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Queue is full.
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop_implementation(reference value)
|
||||
{
|
||||
if (current_size == 0)
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
value = p_buffer[read_index];
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read_index = get_next_index(read_index, Max_Size);
|
||||
|
||||
--current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop_implementation(rvalue_reference value)
|
||||
{
|
||||
if (current_size == 0)
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
value = etl::move(p_buffer[read_index]);
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read_index = get_next_index(read_index, Max_Size);
|
||||
|
||||
--current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue and discard.
|
||||
//*************************************************************************
|
||||
bool pop_implementation()
|
||||
{
|
||||
if (current_size == 0)
|
||||
{
|
||||
// Queue is empty
|
||||
return false;
|
||||
}
|
||||
|
||||
p_buffer[read_index].~T();
|
||||
|
||||
read_index = get_next_index(read_index, Max_Size);
|
||||
|
||||
--current_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Calculate the next index.
|
||||
//*************************************************************************
|
||||
static size_type get_next_index(size_type index, size_type maximum)
|
||||
{
|
||||
++index;
|
||||
|
||||
if (index == maximum)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
T* p_buffer; ///< The internal buffer.
|
||||
size_type write_index; ///< Where to input new data.
|
||||
size_type read_index; ///< Where to get the oldest data.
|
||||
size_type current_size; ///< The current size of the queue.
|
||||
const size_type Max_Size; ///< The maximum number of items in the queue.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\brief This is the base for all queues that contain a particular type.
|
||||
///\details Normally a reference to this type will be taken from a derived queue_lockable.
|
||||
/// This queue supports concurrent access by one producer and one consumer.
|
||||
/// \tparam T The type of value that the queue_lockable holds.
|
||||
//***************************************************************************
|
||||
template <typename T, const size_t VMemory_Model = etl::memory_model::MEMORY_MODEL_LARGE>
|
||||
class iqueue_lockable : public etl::iqueue_lockable_base<T, VMemory_Model>
|
||||
, public etl::ilockable
|
||||
{
|
||||
private:
|
||||
|
||||
typedef iqueue_lockable_base<T, VMemory_Model> base_t;
|
||||
|
||||
public:
|
||||
|
||||
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.
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
typedef typename base_t::rvalue_reference rvalue_reference;///< An rvalue reference to the type used in the queue.
|
||||
#endif
|
||||
typedef typename base_t::size_type size_type; ///< The type used for determining the size of the queue.
|
||||
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push(const_reference value)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->push_implementation(value);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
//*************************************************************************
|
||||
/// Push a value to the queue.
|
||||
//*************************************************************************
|
||||
bool push(rvalue_reference value)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->push_implementation(etl::move(value));
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03)
|
||||
template <typename ... Args>
|
||||
bool emplace(Args&&... args)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->emplace_implementation(etl::forward<Args>(args)...);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1>
|
||||
bool emplace(const T1& value1)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->emplace_implementation(value1);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1, typename T2>
|
||||
bool emplace(const T1& value1, const T2& value2)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->emplace_implementation(value1, value2);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1, typename T2, typename T3>
|
||||
bool emplace(const T1& value1, const T2& value2, const T3& value3)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->emplace_implementation(value1, value2, value3);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Constructs a value in the queue 'in place'.
|
||||
/// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full.
|
||||
//*************************************************************************
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->emplace_implementation(value1, value2, value3, value4);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop(reference value)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->pop_implementation(value);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue.
|
||||
//*************************************************************************
|
||||
bool pop(rvalue_reference value)
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->pop_implementation(etl::move(value));
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Pop a value from the queue and discard.
|
||||
//*************************************************************************
|
||||
bool pop()
|
||||
{
|
||||
lock();
|
||||
|
||||
bool result = this->pop_implementation();
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Clear the queue.
|
||||
//*************************************************************************
|
||||
void clear()
|
||||
{
|
||||
lock();
|
||||
|
||||
while (this->pop_implementation())
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue empty?
|
||||
//*************************************************************************
|
||||
bool empty() const
|
||||
{
|
||||
lock();
|
||||
|
||||
size_type result = (this->current_size == 0);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Is the queue full?
|
||||
//*************************************************************************
|
||||
bool full() const
|
||||
{
|
||||
lock();
|
||||
|
||||
size_type result = (this->current_size == this->Max_Size);
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How many items in the queue?
|
||||
//*************************************************************************
|
||||
size_type size() const
|
||||
{
|
||||
lock();
|
||||
|
||||
size_type result = this->current_size;
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// How much free space available in the queue.
|
||||
//*************************************************************************
|
||||
size_type available() const
|
||||
{
|
||||
lock();
|
||||
|
||||
size_type result = this->Max_Size - this->current_size;
|
||||
|
||||
unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//*************************************************************************
|
||||
/// The constructor that is called from derived classes.
|
||||
//*************************************************************************
|
||||
iqueue_lockable(T* p_buffer_, size_type max_size_)
|
||||
: base_t(p_buffer_, max_size_)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Disable copy construction and assignment.
|
||||
iqueue_lockable(const iqueue_lockable&) ETL_DELETE;
|
||||
iqueue_lockable& operator =(const iqueue_lockable&) ETL_DELETE;
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
iqueue_lockable(iqueue_lockable&&) = delete;
|
||||
iqueue_lockable& operator =(iqueue_lockable&&) = delete;
|
||||
#endif
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// A fixed capacity lockable queue.
|
||||
/// This queue supports concurrent access.
|
||||
/// \tparam T The type this queue should support.
|
||||
/// \tparam VSize The maximum capacity of the queue.
|
||||
/// \tparam VMemory_Model The memory model for the queue. Determines the type of the internal counter variables.
|
||||
//***************************************************************************
|
||||
template <typename T, size_t VSize, size_t VMemory_Model = etl::memory_model::MEMORY_MODEL_LARGE>
|
||||
class queue_lockable : public etl::iqueue_lockable<T, VMemory_Model>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef etl::iqueue_lockable<T, VMemory_Model> base_t;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename base_t::size_type size_type;
|
||||
|
||||
ETL_STATIC_ASSERT((VSize <= etl::integral_limits<size_type>::max), "Size too large for memory model");
|
||||
|
||||
static ETL_CONSTANT size_type Max_Size = size_type(VSize);
|
||||
static ETL_CONSTANT size_type Memory_Model = size_type(VMemory_Model);
|
||||
|
||||
//*************************************************************************
|
||||
/// Default constructor.
|
||||
//*************************************************************************
|
||||
|
||||
queue_lockable()
|
||||
: base_t(reinterpret_cast<T*>(buffer.raw), Max_Size)
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Destructor.
|
||||
//*************************************************************************
|
||||
~queue_lockable()
|
||||
{
|
||||
while (this->pop_implementation())
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
queue_lockable(const queue_lockable&) ETL_DELETE;
|
||||
queue_lockable& operator = (const queue_lockable&) ETL_DELETE;
|
||||
|
||||
#if ETL_CPP11_SUPPORTED
|
||||
queue_lockable(queue_lockable&&) = delete;
|
||||
queue_lockable& operator =(queue_lockable&&) = delete;
|
||||
#endif
|
||||
|
||||
/// The uninitialised buffer of T used in the queue_lockable.
|
||||
etl::uninitialized_buffer_of<T, Max_Size> buffer;
|
||||
};
|
||||
}
|
||||
|
||||
#undef ETL_FILE
|
||||
|
||||
#endif
|
||||
@ -131,7 +131,7 @@ namespace etl
|
||||
public:
|
||||
|
||||
friend class ireference_flat_map;
|
||||
friend class const_iterator;
|
||||
friend class ireference_flat_map::const_iterator;
|
||||
|
||||
iterator()
|
||||
{
|
||||
|
||||
710
test/test_queue_lockable.cpp
Normal file
710
test/test_queue_lockable.cpp
Normal file
@ -0,0 +1,710 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2021 jwellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "UnitTest++/UnitTest++.h"
|
||||
|
||||
#include "etl/queue_lockable.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#if defined(ETL_COMPILER_MICROSOFT)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "data.h"
|
||||
|
||||
#define REALTIME_TEST 0
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
using ItemM = TestDataM<int>;
|
||||
|
||||
//***********************************
|
||||
class QueueInt : public etl::queue_lockable<int, 4>
|
||||
{
|
||||
public:
|
||||
|
||||
QueueInt()
|
||||
: called_lock(false)
|
||||
, called_unlock(false)
|
||||
{
|
||||
}
|
||||
|
||||
void lock() const override
|
||||
{
|
||||
called_lock = true;
|
||||
}
|
||||
|
||||
void unlock() const override
|
||||
{
|
||||
called_unlock = true;
|
||||
}
|
||||
|
||||
void clear_test_flags()
|
||||
{
|
||||
called_lock = false;
|
||||
called_unlock = false;
|
||||
}
|
||||
|
||||
mutable bool called_lock;
|
||||
mutable bool called_unlock;
|
||||
};
|
||||
|
||||
//***********************************
|
||||
class QueueData : public etl::queue_lockable<Data, 4>
|
||||
{
|
||||
public:
|
||||
|
||||
QueueData()
|
||||
: called_lock(false)
|
||||
, called_unlock(false)
|
||||
{
|
||||
}
|
||||
|
||||
void lock() const override
|
||||
{
|
||||
called_lock = true;
|
||||
}
|
||||
|
||||
void unlock() const override
|
||||
{
|
||||
called_unlock = true;
|
||||
}
|
||||
|
||||
void clear_test_flags()
|
||||
{
|
||||
called_lock = false;
|
||||
called_unlock = false;
|
||||
}
|
||||
|
||||
mutable bool called_lock;
|
||||
mutable bool called_unlock;
|
||||
};
|
||||
|
||||
//***********************************
|
||||
class QueueItemM : public etl::queue_lockable<ItemM, 4>
|
||||
{
|
||||
public:
|
||||
|
||||
QueueItemM()
|
||||
: called_lock(false)
|
||||
, called_unlock(false)
|
||||
{
|
||||
}
|
||||
|
||||
void lock() const override
|
||||
{
|
||||
called_lock = true;
|
||||
}
|
||||
|
||||
void unlock() const override
|
||||
{
|
||||
called_unlock = true;
|
||||
}
|
||||
|
||||
void clear_test_flags()
|
||||
{
|
||||
called_lock = false;
|
||||
called_unlock = false;
|
||||
}
|
||||
|
||||
mutable bool called_lock;
|
||||
mutable bool called_unlock;
|
||||
};
|
||||
|
||||
SUITE(test_queue_lockable)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_constructor)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(4U, queue.max_size());
|
||||
CHECK_EQUAL(4U, queue.capacity());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(4U, queue.available_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(4U, queue.available());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push_from_unlocked(1);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(3U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(2);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(2U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(3);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(1U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(4);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(4U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(0U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push_from_unlocked(5));
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.pop(i));
|
||||
CHECK(!queue.pop_from_unlocked(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_move_push_pop)
|
||||
{
|
||||
QueueItemM queue;
|
||||
|
||||
ItemM p1(1);
|
||||
ItemM p2(2);
|
||||
ItemM p3(3);
|
||||
ItemM p4(4);
|
||||
|
||||
queue.push(std::move(p1));
|
||||
queue.push(std::move(p2));
|
||||
queue.push(std::move(p3));
|
||||
queue.push(std::move(p4));
|
||||
|
||||
CHECK(!bool(p1));
|
||||
CHECK(!bool(p2));
|
||||
CHECK(!bool(p3));
|
||||
CHECK(!bool(p4));
|
||||
|
||||
ItemM pr(0);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(1, pr.value);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(2, pr.value);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(3, pr.value);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(4, pr.value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_iqueue)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
etl::iqueue_lockable<int>& iqueue = queue;
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size_from_unlocked());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push_from_unlocked(1);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push(2);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(2U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push(3);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push(4);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(4U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!iqueue.push(5));
|
||||
CHECK(!iqueue.push_from_unlocked(5));
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(iqueue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(2U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(iqueue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(iqueue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(0U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!iqueue.pop(i));
|
||||
CHECK(!iqueue.pop_from_unlocked(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_void)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push_from_unlocked(1);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(2);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(3);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(4);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(4U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push_from_unlocked(5));
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.pop());
|
||||
CHECK(!queue.pop_from_unlocked());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_multiple_emplace)
|
||||
{
|
||||
QueueData queue;
|
||||
|
||||
queue.emplace(1);
|
||||
queue.emplace(1, 2);
|
||||
queue.emplace(1, 2, 3);
|
||||
queue.emplace(1, 2, 3, 4);
|
||||
|
||||
CHECK_EQUAL(4U, queue.size());
|
||||
|
||||
Data popped;
|
||||
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_clear)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.clear();
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
// Do it again to check that clear() didn't screw up the internals.
|
||||
queue.push_from_unlocked(1);
|
||||
queue.push_from_unlocked(2);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
queue.clear_from_unlocked();
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_empty)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK(queue.empty());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.empty());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear();
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.empty_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.empty_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_full)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK(!queue.full());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.full());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear();
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.full_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.full_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
#if REALTIME_TEST
|
||||
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
|
||||
#define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
|
||||
#define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1);
|
||||
#else
|
||||
#define RAISE_THREAD_PRIORITY
|
||||
#define FIX_PROCESSOR_AFFINITY
|
||||
#endif
|
||||
|
||||
size_t ticks = 0;
|
||||
|
||||
class QueueIntMutex : public etl::queue_lockable<int, 10>
|
||||
{
|
||||
public:
|
||||
|
||||
void lock() const override
|
||||
{
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
void unlock() const override
|
||||
{
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
QueueIntMutex 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 (queue.push(ticks))
|
||||
{
|
||||
++ticks;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
710
test/test_queue_lockable_small.cpp
Normal file
710
test/test_queue_lockable_small.cpp
Normal file
@ -0,0 +1,710 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2021 jwellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "UnitTest++/UnitTest++.h"
|
||||
|
||||
#include "etl/queue_lockable.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#if defined(ETL_COMPILER_MICROSOFT)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "data.h"
|
||||
|
||||
#define REALTIME_TEST 0
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
using ItemM = TestDataM<int>;
|
||||
|
||||
//***********************************
|
||||
class QueueInt : public etl::queue_lockable<int, 4, etl::memory_model::MEMORY_MODEL_SMALL>
|
||||
{
|
||||
public:
|
||||
|
||||
QueueInt()
|
||||
: called_lock(false)
|
||||
, called_unlock(false)
|
||||
{
|
||||
}
|
||||
|
||||
void lock() const override
|
||||
{
|
||||
called_lock = true;
|
||||
}
|
||||
|
||||
void unlock() const override
|
||||
{
|
||||
called_unlock = true;
|
||||
}
|
||||
|
||||
void clear_test_flags()
|
||||
{
|
||||
called_lock = false;
|
||||
called_unlock = false;
|
||||
}
|
||||
|
||||
mutable bool called_lock;
|
||||
mutable bool called_unlock;
|
||||
};
|
||||
|
||||
//***********************************
|
||||
class QueueData : public etl::queue_lockable<Data, 4, etl::memory_model::MEMORY_MODEL_SMALL>
|
||||
{
|
||||
public:
|
||||
|
||||
QueueData()
|
||||
: called_lock(false)
|
||||
, called_unlock(false)
|
||||
{
|
||||
}
|
||||
|
||||
void lock() const override
|
||||
{
|
||||
called_lock = true;
|
||||
}
|
||||
|
||||
void unlock() const override
|
||||
{
|
||||
called_unlock = true;
|
||||
}
|
||||
|
||||
void clear_test_flags()
|
||||
{
|
||||
called_lock = false;
|
||||
called_unlock = false;
|
||||
}
|
||||
|
||||
mutable bool called_lock;
|
||||
mutable bool called_unlock;
|
||||
};
|
||||
|
||||
//***********************************
|
||||
class QueueItemM : public etl::queue_lockable<ItemM, 4, etl::memory_model::MEMORY_MODEL_SMALL>
|
||||
{
|
||||
public:
|
||||
|
||||
QueueItemM()
|
||||
: called_lock(false)
|
||||
, called_unlock(false)
|
||||
{
|
||||
}
|
||||
|
||||
void lock() const override
|
||||
{
|
||||
called_lock = true;
|
||||
}
|
||||
|
||||
void unlock() const override
|
||||
{
|
||||
called_unlock = true;
|
||||
}
|
||||
|
||||
void clear_test_flags()
|
||||
{
|
||||
called_lock = false;
|
||||
called_unlock = false;
|
||||
}
|
||||
|
||||
mutable bool called_lock;
|
||||
mutable bool called_unlock;
|
||||
};
|
||||
|
||||
SUITE(test_queue_lockable)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_constructor)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(4U, queue.max_size());
|
||||
CHECK_EQUAL(4U, queue.capacity());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(4U, queue.available_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(4U, queue.available());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push_from_unlocked(1);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(3U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(2);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(2U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(3);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(1U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(4);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(4U, queue.size_from_unlocked());
|
||||
CHECK_EQUAL(0U, queue.available_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push_from_unlocked(5));
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(queue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.pop(i));
|
||||
CHECK(!queue.pop_from_unlocked(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_move_push_pop)
|
||||
{
|
||||
QueueItemM queue;
|
||||
|
||||
ItemM p1(1);
|
||||
ItemM p2(2);
|
||||
ItemM p3(3);
|
||||
ItemM p4(4);
|
||||
|
||||
queue.push(std::move(p1));
|
||||
queue.push(std::move(p2));
|
||||
queue.push(std::move(p3));
|
||||
queue.push(std::move(p4));
|
||||
|
||||
CHECK(!bool(p1));
|
||||
CHECK(!bool(p2));
|
||||
CHECK(!bool(p3));
|
||||
CHECK(!bool(p4));
|
||||
|
||||
ItemM pr(0);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(1, pr.value);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(2, pr.value);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(3, pr.value);
|
||||
|
||||
queue.pop(std::move(pr));
|
||||
CHECK_EQUAL(4, pr.value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_iqueue)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
etl::iqueue_lockable<int, etl::memory_model::MEMORY_MODEL_SMALL>& iqueue = queue;
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size_from_unlocked());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(0U, iqueue.size());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push_from_unlocked(1);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push(2);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(2U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push(3);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
iqueue.push(4);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(4U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!iqueue.push(5));
|
||||
CHECK(!iqueue.push_from_unlocked(5));
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
int i;
|
||||
|
||||
CHECK(iqueue.pop(i));
|
||||
CHECK_EQUAL(1, i);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(iqueue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(2, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(2U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(iqueue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(3, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(iqueue.pop_from_unlocked(i));
|
||||
CHECK_EQUAL(4, i);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(0U, iqueue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!iqueue.pop(i));
|
||||
CHECK(!iqueue.pop_from_unlocked(i));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_size_push_pop_void)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push_from_unlocked(1);
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(2);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(3);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
queue.push(4);
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(4U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.push(5));
|
||||
CHECK(!queue.push_from_unlocked(5));
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(3U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(1U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.pop_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.pop());
|
||||
CHECK(!queue.pop_from_unlocked());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_multiple_emplace)
|
||||
{
|
||||
QueueData queue;
|
||||
|
||||
queue.emplace(1);
|
||||
queue.emplace(1, 2);
|
||||
queue.emplace(1, 2, 3);
|
||||
queue.emplace(1, 2, 3, 4);
|
||||
|
||||
CHECK_EQUAL(4U, queue.size());
|
||||
|
||||
Data popped;
|
||||
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
queue.pop(popped);
|
||||
CHECK(popped == Data(1, 2, 3, 4));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_clear)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.clear();
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
CHECK_EQUAL(0U, queue.size());
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
// Do it again to check that clear() didn't screw up the internals.
|
||||
queue.push_from_unlocked(1);
|
||||
queue.push_from_unlocked(2);
|
||||
CHECK_EQUAL(2U, queue.size_from_unlocked());
|
||||
queue.clear_from_unlocked();
|
||||
CHECK_EQUAL(0U, queue.size_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_empty)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK(queue.empty());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.empty());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear();
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.empty_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.empty_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_full)
|
||||
{
|
||||
QueueInt queue;
|
||||
|
||||
CHECK(!queue.full());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.full());
|
||||
CHECK(queue.called_lock);
|
||||
CHECK(queue.called_unlock);
|
||||
|
||||
queue.clear();
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(!queue.full_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.push(3);
|
||||
queue.push(4);
|
||||
|
||||
queue.clear_test_flags();
|
||||
|
||||
CHECK(queue.full_from_unlocked());
|
||||
CHECK(!queue.called_lock);
|
||||
CHECK(!queue.called_unlock);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
#if REALTIME_TEST
|
||||
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
|
||||
#define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
|
||||
#define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1);
|
||||
#else
|
||||
#define RAISE_THREAD_PRIORITY
|
||||
#define FIX_PROCESSOR_AFFINITY
|
||||
#endif
|
||||
|
||||
size_t ticks = 0;
|
||||
|
||||
class QueueIntMutex : public etl::queue_spsc_locked<int, 10>
|
||||
{
|
||||
public:
|
||||
|
||||
void lock() override
|
||||
{
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
void unlock() override
|
||||
{
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
QueueIntMutex 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 (queue.push(ticks))
|
||||
{
|
||||
++ticks;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
@ -1288,6 +1288,7 @@
|
||||
<ClInclude Include="..\..\include\etl\generators\type_traits_generator.h" />
|
||||
<ClInclude Include="..\..\include\etl\generators\variant_pool_generator.h" />
|
||||
<ClInclude Include="..\..\include\etl\generic_pool.h" />
|
||||
<ClInclude Include="..\..\include\etl\ilockable.h" />
|
||||
<ClInclude Include="..\..\include\etl\indirect_vector.h" />
|
||||
<ClInclude Include="..\..\include\etl\absolute.h" />
|
||||
<ClInclude Include="..\..\include\etl\ipool.h" />
|
||||
@ -1917,6 +1918,8 @@
|
||||
<ClCompile Include="..\test_parity_checksum.cpp" />
|
||||
<ClCompile Include="..\test_pearson.cpp" />
|
||||
<ClCompile Include="..\test_pool.cpp" />
|
||||
<ClCompile Include="..\test_queue_lockable.cpp" />
|
||||
<ClCompile Include="..\test_queue_lockable_small.cpp" />
|
||||
<ClCompile Include="..\test_shared_message.cpp" />
|
||||
<ClCompile Include="..\test_priority_queue.cpp" />
|
||||
<ClCompile Include="..\test_queue.cpp" />
|
||||
|
||||
@ -942,6 +942,9 @@
|
||||
<ClInclude Include="..\..\include\etl\successor.h">
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\ilockable.h">
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\main.cpp">
|
||||
@ -1484,6 +1487,12 @@
|
||||
<ClCompile Include="..\test_fixed_sized_memory_block_allocator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_queue_lockable.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_queue_lockable_small.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\library.properties">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user