Modified ISR queue to take references to etl::ifunction instances at runtime rather than static class at compile time.

This commit is contained in:
John Wellbelove 2019-02-25 08:45:53 +01:00
parent 0db4f32522
commit 4aab7c0173
3 changed files with 382 additions and 371 deletions

View File

@ -39,6 +39,7 @@ SOFTWARE.
#include "parameter_type.h"
#include "memory_model.h"
#include "integral_limits.h"
#include "function.h"
#undef ETL_FILE
#define ETL_FILE "46"
@ -390,14 +391,10 @@ namespace etl
///\ingroup queue_spsc
///\brief This is the base for all queue_spsc_isrs that contain a particular type.
///\details Normally a reference to this type will be taken from a derived queue_spsc_isr.
///\code
/// etl::queue_spsc_isr_isr<int, 10> myQueue;
/// etl::iqueue_isr<int>& iQueue = myQueue;
///\endcode
/// This queue supports concurrent access by one producer and one consumer.
/// \tparam T The type of value that the queue_spsc_isr holds.
//***************************************************************************
template <typename T, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class iqueue_spsc_isr : public queue_spsc_isr_base<T, MEMORY_MODEL>
{
private:
@ -417,11 +414,11 @@ namespace etl
//*************************************************************************
bool push(parameter_t value)
{
TAccess::lock();
lock();
bool result = this->push_implementation(value);
TAccess::unlock();
unlock();
return result;
}
@ -434,11 +431,11 @@ namespace etl
template <typename ... Args>
bool emplace(Args&&... args)
{
TAccess::lock();
lock();
bool result = this->emplace_implementation(std::forward<Args>(args)...);
TAccess::unlock();
unlock();
return result;
}
@ -450,11 +447,11 @@ namespace etl
template <typename T1>
bool emplace(const T1& value1)
{
TAccess::lock();
lock();
bool result = this->emplace_implementation(value1);
TAccess::unlock();
unlock();
return result;
}
@ -466,11 +463,11 @@ namespace etl
template <typename T1, typename T2>
bool emplace(const T1& value1, const T2& value2)
{
TAccess::lock();
lock();
bool result = this->emplace_implementation(value1, value2);
TAccess::unlock();
unlock();
return result;
}
@ -482,11 +479,11 @@ namespace etl
template <typename T1, typename T2, typename T3>
bool emplace(const T1& value1, const T2& value2, const T3& value3)
{
TAccess::lock();
lock();
bool result = this->emplace_implementation(value1, value2, value3);
TAccess::unlock();
unlock();
return result;
}
@ -498,11 +495,11 @@ namespace etl
template <typename T1, typename T2, typename T3, typename T4>
bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
{
TAccess::lock();
lock();
bool result = this->emplace_implementation(value1, value2, value3, value4);
TAccess::unlock();
unlock();
return result;
}
@ -513,11 +510,11 @@ namespace etl
//*************************************************************************
bool pop(reference value)
{
TAccess::lock();
lock();
bool result = this->pop_implementation(value);
TAccess::unlock();
unlock();
return result;
}
@ -527,11 +524,11 @@ namespace etl
//*************************************************************************
bool pop()
{
TAccess::lock();
lock();
bool result = this->pop_implementation();
TAccess::unlock();
unlock();
return result;
}
@ -541,14 +538,14 @@ namespace etl
//*************************************************************************
void clear()
{
TAccess::lock();
lock();
while (this->pop_implementation())
{
// Do nothing.
}
TAccess::unlock();
unlock();
}
//*************************************************************************
@ -556,11 +553,11 @@ namespace etl
//*************************************************************************
bool empty() const
{
TAccess::lock();
lock();
size_type result = (this->current_size == 0);
TAccess::unlock();
unlock();
return result;
}
@ -570,11 +567,11 @@ namespace etl
//*************************************************************************
bool full() const
{
TAccess::lock();
lock();
size_type result = (this->current_size == this->MAX_SIZE);
TAccess::unlock();
unlock();
return result;
}
@ -584,11 +581,11 @@ namespace etl
//*************************************************************************
size_type size() const
{
TAccess::lock();
lock();
size_type result = this->current_size;
TAccess::unlock();
unlock();
return result;
}
@ -598,11 +595,11 @@ namespace etl
//*************************************************************************
size_type available() const
{
TAccess::lock();
lock();
size_type result = this->MAX_SIZE - this->current_size;
TAccess::unlock();
unlock();
return result;
}
@ -612,8 +609,10 @@ namespace etl
//*************************************************************************
/// The constructor that is called from derived classes.
//*************************************************************************
iqueue_spsc_isr(T* p_buffer_, size_type max_size_)
iqueue_spsc_isr(T* p_buffer_, size_type max_size_, etl::ifunction<void>& lock_, etl::ifunction<void>& unlock_)
: base_t(p_buffer_, max_size_)
, lock(lock_)
, unlock(unlock_)
{
}
@ -623,7 +622,8 @@ namespace etl
iqueue_spsc_isr(const iqueue_spsc_isr&);
iqueue_spsc_isr& operator =(const iqueue_spsc_isr&);
TAccess access; ///< The object that locks/unlocks interrupts.
etl::ifunction<void>& lock; ///< The callback that locks interrupts.
etl::ifunction<void>& unlock; ///< The callback that unlocks interrupts.
};
//***************************************************************************
@ -632,15 +632,14 @@ namespace etl
/// 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 MEMORY_MODEL The memory model for the queue. Determines the type of the internal counter variables.
//***************************************************************************
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>
template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
class queue_spsc_isr : public etl::iqueue_spsc_isr<T, MEMORY_MODEL>
{
private:
typedef etl::iqueue_spsc_isr<T, TAccess, MEMORY_MODEL> base_t;
typedef etl::iqueue_spsc_isr<T, MEMORY_MODEL> base_t;
public:
@ -653,8 +652,9 @@ namespace etl
//*************************************************************************
/// Default constructor.
//*************************************************************************
queue_spsc_isr()
: base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
queue_spsc_isr(etl::ifunction<void>& lock,
etl::ifunction<void>& unlock)
: base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, lock, unlock)
{
}

View File

@ -29,6 +29,7 @@ SOFTWARE.
#include "UnitTest++.h"
#include "etl/queue_spsc_isr.h"
#include "etl/function.h"
#include <thread>
#include <mutex>
@ -46,44 +47,46 @@ namespace
{
public:
static void clear()
void clear()
{
called_lock = false;
called_lock = false;
called_unlock = false;
}
static void lock()
void lock()
{
called_lock = true;
}
static void unlock()
void unlock()
{
called_unlock = true;
}
static bool called_lock;
static bool called_unlock;
bool called_lock;
bool called_unlock;
};
bool Access::called_lock;
bool Access::called_unlock;
Access access;
etl::function_imv<Access, access, &Access::lock> lock;
etl::function_imv<Access, access, &Access::unlock> unlock;
struct Data
{
Data(int a_, int b_ = 2, int c_ = 3, int d_ = 4)
: a(a_),
b(b_),
c(c_),
d(d_)
b(b_),
c(c_),
d(d_)
{
}
Data()
: a(0),
b(0),
c(0),
d(0)
b(0),
c(0),
d(0)
{
}
@ -103,121 +106,121 @@ namespace
//*************************************************************************
TEST(test_constructor)
{
Access::clear();
access.clear();
etl::queue_spsc_isr<int, 4, Access> queue;
etl::queue_spsc_isr<int, 4> queue(lock, unlock);
CHECK_EQUAL(4U, queue.max_size());
CHECK_EQUAL(4U, queue.capacity());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//*************************************************************************
TEST(test_size_push_pop)
{
Access::clear();
access.clear();
etl::queue_spsc_isr<int, 4, Access> queue;
etl::queue_spsc_isr<int, 4> queue(lock, unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(4U, queue.available_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(0U, queue.size());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(4U, queue.available());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
queue.push_from_isr(1);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
CHECK_EQUAL(3U, queue.available_from_isr());
Access::clear();
access.clear();
queue.push(2);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
CHECK_EQUAL(2U, queue.available_from_isr());
Access::clear();
access.clear();
queue.push(3);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
CHECK_EQUAL(1U, queue.available_from_isr());
Access::clear();
access.clear();
queue.push(4);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(4U, queue.size_from_isr());
CHECK_EQUAL(0U, queue.available_from_isr());
Access::clear();
access.clear();
CHECK(!queue.push(5));
CHECK(!queue.push_from_isr(5));
Access::clear();
access.clear();
int i;
CHECK(queue.pop(i));
CHECK_EQUAL(1, i);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr(i));
CHECK_EQUAL(2, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr(i));
CHECK_EQUAL(3, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr(i));
CHECK_EQUAL(4, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(!queue.pop(i));
CHECK(!queue.pop_from_isr(i));
@ -226,92 +229,92 @@ namespace
//*************************************************************************
TEST(test_size_push_pop_iqueue)
{
Access::clear();
access.clear();
etl::queue_spsc_isr<int, 4, Access> queue;
etl::queue_spsc_isr<int, 4> queue(lock, unlock);
etl::iqueue_spsc_isr<int, Access>& iqueue = queue;
etl::iqueue_spsc_isr<int>& iqueue = queue;
CHECK_EQUAL(0U, iqueue.size_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(0U, iqueue.size());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
iqueue.push_from_isr(1);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, iqueue.size_from_isr());
Access::clear();
access.clear();
iqueue.push(2);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(2U, iqueue.size_from_isr());
Access::clear();
access.clear();
iqueue.push(3);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, iqueue.size_from_isr());
Access::clear();
access.clear();
iqueue.push(4);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(4U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(!iqueue.push(5));
CHECK(!iqueue.push_from_isr(5));
Access::clear();
access.clear();
int i;
CHECK(iqueue.pop(i));
CHECK_EQUAL(1, i);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(iqueue.pop_from_isr(i));
CHECK_EQUAL(2, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(2U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(iqueue.pop_from_isr(i));
CHECK_EQUAL(3, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(iqueue.pop_from_isr(i));
CHECK_EQUAL(4, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(0U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(!iqueue.pop(i));
CHECK(!iqueue.pop_from_isr(i));
@ -320,84 +323,84 @@ namespace
//*************************************************************************
TEST(test_size_push_pop_void)
{
Access::clear();
access.clear();
etl::queue_spsc_isr<int, 4, Access> queue;
etl::queue_spsc_isr<int, 4> queue(lock, unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(0U, queue.size());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
queue.push_from_isr(1);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
Access::clear();
access.clear();
queue.push(2);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
Access::clear();
access.clear();
queue.push(3);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
Access::clear();
access.clear();
queue.push(4);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(4U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(!queue.push(5));
CHECK(!queue.push_from_isr(5));
Access::clear();
access.clear();
CHECK(queue.pop());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(!queue.pop());
CHECK(!queue.pop_from_isr());
@ -406,7 +409,7 @@ namespace
//*************************************************************************
TEST(test_multiple_emplace)
{
etl::queue_spsc_isr<Data, 4, Access> queue;
etl::queue_spsc_isr<Data, 4> queue(lock, unlock);
queue.emplace(1);
queue.emplace(1, 2);
@ -430,20 +433,20 @@ namespace
//*************************************************************************
TEST(test_clear)
{
Access::clear();
access.clear();
etl::queue_spsc_isr<int, 4, Access> queue;
etl::queue_spsc_isr<int, 4> queue(lock, unlock);
CHECK_EQUAL(0U, queue.size());
queue.push(1);
queue.push(2);
queue.clear();
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(0U, queue.size());
Access::clear();
access.clear();
// Do it again to check that clear() didn't screw up the internals.
queue.push_from_isr(1);
@ -451,84 +454,84 @@ namespace
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);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//*************************************************************************
TEST(test_empty)
{
Access::clear();
access.clear();
etl::queue_spsc_isr<int, 4, Access> queue;
etl::queue_spsc_isr<int, 4> queue(lock, unlock);
CHECK(queue.empty());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.push(1);
Access::clear();
access.clear();
CHECK(!queue.empty());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.clear();
Access::clear();
access.clear();
CHECK(queue.empty_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
queue.push(1);
Access::clear();
access.clear();
CHECK(!queue.empty_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//*************************************************************************
TEST(test_full)
{
Access::clear();
access.clear();
etl::queue_spsc_isr<int, 4, Access> queue;
etl::queue_spsc_isr<int, 4> queue(lock, unlock);
CHECK(!queue.full());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
Access::clear();
access.clear();
CHECK(queue.full());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.clear();
Access::clear();
access.clear();
CHECK(!queue.full_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
Access::clear();
access.clear();
CHECK(queue.full_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//=========================================================================
@ -544,22 +547,25 @@ namespace
struct ThreadLock
{
static void lock()
void lock()
{
mutex.lock();
}
static void unlock()
void unlock()
{
mutex.unlock();
}
static std::mutex mutex;
std::mutex mutex;
};
std::mutex ThreadLock::mutex;
ThreadLock threadLock;
etl::queue_spsc_isr<int, 10, ThreadLock> queue;
etl::function_imv<ThreadLock, threadLock, &ThreadLock::lock> lock;
etl::function_imv<ThreadLock, threadLock, &ThreadLock::unlock> unlock;
etl::queue_spsc_isr<int, 10> queue(lock, unlock);
const size_t LENGTH = 1000;
@ -574,14 +580,14 @@ namespace
while (ticks <= LENGTH)
{
if (ThreadLock::mutex.try_lock())
if (threadLock.mutex.try_lock())
{
if (queue.push_from_isr(ticks))
{
++ticks;
}
ThreadLock::mutex.unlock();
threadLock.mutex.unlock();
}
Sleep(0);

View File

@ -46,44 +46,46 @@ namespace
{
public:
static void clear()
void clear()
{
called_lock = false;
called_unlock = false;
}
static void lock()
void lock()
{
called_lock = true;
}
static void unlock()
void unlock()
{
called_unlock = true;
}
static bool called_lock;
static bool called_unlock;
bool called_lock;
bool called_unlock;
};
bool Access::called_lock;
bool Access::called_unlock;
Access access;
etl::function_imv<Access, access, &Access::lock> lock;
etl::function_imv<Access, access, &Access::unlock> unlock;
struct Data
{
Data(int a_, int b_ = 2, int c_ = 3, int d_ = 4)
: a(a_),
b(b_),
c(c_),
d(d_)
b(b_),
c(c_),
d(d_)
{
}
Data()
: a(0),
b(0),
c(0),
d(0)
b(0),
c(0),
d(0)
{
}
@ -98,131 +100,131 @@ namespace
return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d);
}
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, 4, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt;
typedef etl::iqueue_spsc_isr<int, etl::memory_model::MEMORY_MODEL_SMALL> IQueueInt;
typedef etl::queue_spsc_isr<int, 255, Access, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt255;
typedef etl::queue_spsc_isr<int, 255, etl::memory_model::MEMORY_MODEL_SMALL> QueueInt255;
SUITE(test_queue_isr)
{
//*************************************************************************
TEST(test_constructor)
{
Access::clear();
access.clear();
QueueInt queue;
QueueInt queue(lock, unlock);
CHECK_EQUAL(4U, queue.max_size());
CHECK_EQUAL(4U, queue.capacity());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//*************************************************************************
TEST(test_size_push_pop)
{
Access::clear();
access.clear();
QueueInt queue;
QueueInt queue(lock, unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(4U, queue.available_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(0U, queue.size());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(4U, queue.available());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
queue.push_from_isr(1);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
CHECK_EQUAL(3U, queue.available_from_isr());
Access::clear();
access.clear();
queue.push(2);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
CHECK_EQUAL(2U, queue.available_from_isr());
Access::clear();
access.clear();
queue.push(3);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
CHECK_EQUAL(1U, queue.available_from_isr());
Access::clear();
access.clear();
queue.push(4);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(4U, queue.size_from_isr());
CHECK_EQUAL(0U, queue.available_from_isr());
Access::clear();
access.clear();
CHECK(!queue.push(5));
CHECK(!queue.push_from_isr(5));
Access::clear();
access.clear();
int i;
CHECK(queue.pop(i));
CHECK_EQUAL(1, i);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr(i));
CHECK_EQUAL(2, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr(i));
CHECK_EQUAL(3, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr(i));
CHECK_EQUAL(4, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(!queue.pop(i));
CHECK(!queue.pop_from_isr(i));
@ -231,92 +233,92 @@ namespace
//*************************************************************************
TEST(test_size_push_pop_iqueue)
{
Access::clear();
access.clear();
QueueInt queue;
QueueInt queue(lock, unlock);
IQueueInt& iqueue = queue;
CHECK_EQUAL(0U, iqueue.size_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(0U, iqueue.size());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
iqueue.push_from_isr(1);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, iqueue.size_from_isr());
Access::clear();
access.clear();
iqueue.push(2);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(2U, iqueue.size_from_isr());
Access::clear();
access.clear();
iqueue.push(3);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, iqueue.size_from_isr());
Access::clear();
access.clear();
iqueue.push(4);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(4U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(!iqueue.push(5));
CHECK(!iqueue.push_from_isr(5));
Access::clear();
access.clear();
int i;
CHECK(iqueue.pop(i));
CHECK_EQUAL(1, i);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(iqueue.pop_from_isr(i));
CHECK_EQUAL(2, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(2U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(iqueue.pop_from_isr(i));
CHECK_EQUAL(3, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(iqueue.pop_from_isr(i));
CHECK_EQUAL(4, i);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(0U, iqueue.size_from_isr());
Access::clear();
access.clear();
CHECK(!iqueue.pop(i));
CHECK(!iqueue.pop_from_isr(i));
@ -325,84 +327,84 @@ namespace
//*************************************************************************
TEST(test_size_push_pop_void)
{
Access::clear();
access.clear();
QueueInt queue;
QueueInt queue(lock, unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
Access::clear();
access.clear();
CHECK_EQUAL(0U, queue.size());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
Access::clear();
access.clear();
queue.push_from_isr(1);
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
Access::clear();
access.clear();
queue.push(2);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
Access::clear();
access.clear();
queue.push(3);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
Access::clear();
access.clear();
queue.push(4);
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(4U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(!queue.push(5));
CHECK(!queue.push_from_isr(5));
Access::clear();
access.clear();
CHECK(queue.pop());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(3U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(2U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(1U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(queue.pop_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
CHECK_EQUAL(0U, queue.size_from_isr());
Access::clear();
access.clear();
CHECK(!queue.pop());
CHECK(!queue.pop_from_isr());
@ -411,7 +413,7 @@ namespace
//*************************************************************************
TEST(test_push_255)
{
QueueInt255 queue;
QueueInt255 queue(lock, unlock);
for (int i = 0; i < 255; ++i)
{
@ -424,7 +426,7 @@ namespace
//*************************************************************************
TEST(test_multiple_emplace)
{
etl::queue_spsc_isr<Data, 4, Access, etl::memory_model::MEMORY_MODEL_SMALL> queue;
etl::queue_spsc_isr<Data, 4, etl::memory_model::MEMORY_MODEL_SMALL> queue(lock, unlock);
queue.emplace(1);
queue.emplace(1, 2);
@ -448,20 +450,20 @@ namespace
//*************************************************************************
TEST(test_clear)
{
Access::clear();
access.clear();
QueueInt queue;
QueueInt queue(lock, unlock);
CHECK_EQUAL(0U, queue.size());
queue.push(1);
queue.push(2);
queue.clear();
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
CHECK_EQUAL(0U, queue.size());
Access::clear();
access.clear();
// Do it again to check that clear() didn't screw up the internals.
queue.push_from_isr(1);
@ -469,84 +471,84 @@ namespace
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);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//*************************************************************************
TEST(test_empty)
{
Access::clear();
access.clear();
QueueInt queue;
QueueInt queue(lock, unlock);
CHECK(queue.empty());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.push(1);
Access::clear();
access.clear();
CHECK(!queue.empty());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.clear();
Access::clear();
access.clear();
CHECK(queue.empty_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
queue.push(1);
Access::clear();
access.clear();
CHECK(!queue.empty_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//*************************************************************************
TEST(test_full)
{
Access::clear();
access.clear();
QueueInt queue;
QueueInt queue(lock, unlock);
CHECK(!queue.full());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
Access::clear();
access.clear();
CHECK(queue.full());
CHECK(Access::called_lock);
CHECK(Access::called_unlock);
CHECK(access.called_lock);
CHECK(access.called_unlock);
queue.clear();
Access::clear();
access.clear();
CHECK(!queue.full_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
Access::clear();
access.clear();
CHECK(queue.full_from_isr());
CHECK(!Access::called_lock);
CHECK(!Access::called_unlock);
CHECK(!access.called_lock);
CHECK(!access.called_unlock);
}
//=========================================================================
@ -562,22 +564,25 @@ namespace
struct ThreadLock
{
static void lock()
void lock()
{
mutex.lock();
}
static void unlock()
void unlock()
{
mutex.unlock();
}
static std::mutex mutex;
std::mutex mutex;
};
std::mutex ThreadLock::mutex;
ThreadLock threadLock;
etl::queue_spsc_isr<int, 10, ThreadLock> queue;
etl::function_imv<ThreadLock, threadLock, &ThreadLock::lock> lock;
etl::function_imv<ThreadLock, threadLock, &ThreadLock::unlock> unlock;
etl::queue_spsc_isr<int, 10> queue(lock, unlock);
const size_t LENGTH = 1000;
@ -592,14 +597,14 @@ namespace
while (ticks <= LENGTH)
{
if (ThreadLock::mutex.try_lock())
if (threadLock.mutex.try_lock())
{
if (queue.push_from_isr(ticks))
{
++ticks;
}
ThreadLock::mutex.unlock();
threadLock.mutex.unlock();
}
Sleep(0);