From 4aab7c017302b446f87037e25430167a80d9b749 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 25 Feb 2019 08:45:53 +0100 Subject: [PATCH 1/4] Modified ISR queue to take references to etl::ifunction instances at runtime rather than static class at compile time. --- include/etl/queue_spsc_isr.h | 78 +++---- test/test_queue_spsc_isr.cpp | 336 ++++++++++++++-------------- test/test_queue_spsc_isr_small.cpp | 339 +++++++++++++++-------------- 3 files changed, 382 insertions(+), 371 deletions(-) diff --git a/include/etl/queue_spsc_isr.h b/include/etl/queue_spsc_isr.h index e4918ad7..838e356f 100644 --- a/include/etl/queue_spsc_isr.h +++ b/include/etl/queue_spsc_isr.h @@ -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 myQueue; - /// etl::iqueue_isr& 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 + template class iqueue_spsc_isr : public queue_spsc_isr_base { 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 bool emplace(Args&&... args) { - TAccess::lock(); + lock(); bool result = this->emplace_implementation(std::forward(args)...); - TAccess::unlock(); + unlock(); return result; } @@ -450,11 +447,11 @@ namespace etl template 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 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 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 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& lock_, etl::ifunction& 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& lock; ///< The callback that locks interrupts. + etl::ifunction& 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 - class queue_spsc_isr : public etl::iqueue_spsc_isr + template + class queue_spsc_isr : public etl::iqueue_spsc_isr { private: - typedef etl::iqueue_spsc_isr base_t; + typedef etl::iqueue_spsc_isr base_t; public: @@ -653,8 +652,9 @@ namespace etl //************************************************************************* /// Default constructor. //************************************************************************* - queue_spsc_isr() - : base_t(reinterpret_cast(&buffer[0]), MAX_SIZE) + queue_spsc_isr(etl::ifunction& lock, + etl::ifunction& unlock) + : base_t(reinterpret_cast(&buffer[0]), MAX_SIZE, lock, unlock) { } diff --git a/test/test_queue_spsc_isr.cpp b/test/test_queue_spsc_isr.cpp index 56516beb..ed465660 100644 --- a/test/test_queue_spsc_isr.cpp +++ b/test/test_queue_spsc_isr.cpp @@ -29,6 +29,7 @@ SOFTWARE. #include "UnitTest++.h" #include "etl/queue_spsc_isr.h" +#include "etl/function.h" #include #include @@ -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 lock; + etl::function_imv 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 queue; + etl::queue_spsc_isr 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 queue; + etl::queue_spsc_isr 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 queue; + etl::queue_spsc_isr queue(lock, unlock); - etl::iqueue_spsc_isr& iqueue = queue; + etl::iqueue_spsc_isr& 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 queue; + etl::queue_spsc_isr 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 queue; + etl::queue_spsc_isr 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 queue; + etl::queue_spsc_isr 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 queue; + etl::queue_spsc_isr 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 queue; + etl::queue_spsc_isr 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 queue; + etl::function_imv lock; + etl::function_imv unlock; + + etl::queue_spsc_isr 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); diff --git a/test/test_queue_spsc_isr_small.cpp b/test/test_queue_spsc_isr_small.cpp index ca5f4f22..643970a6 100644 --- a/test/test_queue_spsc_isr_small.cpp +++ b/test/test_queue_spsc_isr_small.cpp @@ -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 lock; + etl::function_imv 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 QueueInt; - typedef etl::iqueue_spsc_isr IQueueInt; + typedef etl::queue_spsc_isr QueueInt; + typedef etl::iqueue_spsc_isr IQueueInt; - typedef etl::queue_spsc_isr QueueInt255; + typedef etl::queue_spsc_isr 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 queue; + etl::queue_spsc_isr 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 queue; + etl::function_imv lock; + etl::function_imv unlock; + + etl::queue_spsc_isr 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); From ab91c7af33e30ee4cfabba022edc8d9d6707fe71 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 25 Feb 2019 09:02:12 +0100 Subject: [PATCH 2/4] Revert "Modified ISR queue to take references to etl::ifunction instances at runtime rather than static class at compile time." This reverts commit 4aab7c017302b446f87037e25430167a80d9b749. --- include/etl/queue_spsc_isr.h | 78 +++---- test/test_queue_spsc_isr.cpp | 336 ++++++++++++++-------------- test/test_queue_spsc_isr_small.cpp | 339 ++++++++++++++--------------- 3 files changed, 371 insertions(+), 382 deletions(-) diff --git a/include/etl/queue_spsc_isr.h b/include/etl/queue_spsc_isr.h index 838e356f..e4918ad7 100644 --- a/include/etl/queue_spsc_isr.h +++ b/include/etl/queue_spsc_isr.h @@ -39,7 +39,6 @@ SOFTWARE. #include "parameter_type.h" #include "memory_model.h" #include "integral_limits.h" -#include "function.h" #undef ETL_FILE #define ETL_FILE "46" @@ -391,10 +390,14 @@ 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 myQueue; + /// etl::iqueue_isr& 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 + template class iqueue_spsc_isr : public queue_spsc_isr_base { private: @@ -414,11 +417,11 @@ namespace etl //************************************************************************* bool push(parameter_t value) { - lock(); + TAccess::lock(); bool result = this->push_implementation(value); - unlock(); + TAccess::unlock(); return result; } @@ -431,11 +434,11 @@ namespace etl template bool emplace(Args&&... args) { - lock(); + TAccess::lock(); bool result = this->emplace_implementation(std::forward(args)...); - unlock(); + TAccess::unlock(); return result; } @@ -447,11 +450,11 @@ namespace etl template bool emplace(const T1& value1) { - lock(); + TAccess::lock(); bool result = this->emplace_implementation(value1); - unlock(); + TAccess::unlock(); return result; } @@ -463,11 +466,11 @@ namespace etl template bool emplace(const T1& value1, const T2& value2) { - lock(); + TAccess::lock(); bool result = this->emplace_implementation(value1, value2); - unlock(); + TAccess::unlock(); return result; } @@ -479,11 +482,11 @@ namespace etl template bool emplace(const T1& value1, const T2& value2, const T3& value3) { - lock(); + TAccess::lock(); bool result = this->emplace_implementation(value1, value2, value3); - unlock(); + TAccess::unlock(); return result; } @@ -495,11 +498,11 @@ namespace etl template bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) { - lock(); + TAccess::lock(); bool result = this->emplace_implementation(value1, value2, value3, value4); - unlock(); + TAccess::unlock(); return result; } @@ -510,11 +513,11 @@ namespace etl //************************************************************************* bool pop(reference value) { - lock(); + TAccess::lock(); bool result = this->pop_implementation(value); - unlock(); + TAccess::unlock(); return result; } @@ -524,11 +527,11 @@ namespace etl //************************************************************************* bool pop() { - lock(); + TAccess::lock(); bool result = this->pop_implementation(); - unlock(); + TAccess::unlock(); return result; } @@ -538,14 +541,14 @@ namespace etl //************************************************************************* void clear() { - lock(); + TAccess::lock(); while (this->pop_implementation()) { // Do nothing. } - unlock(); + TAccess::unlock(); } //************************************************************************* @@ -553,11 +556,11 @@ namespace etl //************************************************************************* bool empty() const { - lock(); + TAccess::lock(); size_type result = (this->current_size == 0); - unlock(); + TAccess::unlock(); return result; } @@ -567,11 +570,11 @@ namespace etl //************************************************************************* bool full() const { - lock(); + TAccess::lock(); size_type result = (this->current_size == this->MAX_SIZE); - unlock(); + TAccess::unlock(); return result; } @@ -581,11 +584,11 @@ namespace etl //************************************************************************* size_type size() const { - lock(); + TAccess::lock(); size_type result = this->current_size; - unlock(); + TAccess::unlock(); return result; } @@ -595,11 +598,11 @@ namespace etl //************************************************************************* size_type available() const { - lock(); + TAccess::lock(); size_type result = this->MAX_SIZE - this->current_size; - unlock(); + TAccess::unlock(); return result; } @@ -609,10 +612,8 @@ namespace etl //************************************************************************* /// The constructor that is called from derived classes. //************************************************************************* - iqueue_spsc_isr(T* p_buffer_, size_type max_size_, etl::ifunction& lock_, etl::ifunction& unlock_) + iqueue_spsc_isr(T* p_buffer_, size_type max_size_) : base_t(p_buffer_, max_size_) - , lock(lock_) - , unlock(unlock_) { } @@ -622,8 +623,7 @@ namespace etl iqueue_spsc_isr(const iqueue_spsc_isr&); iqueue_spsc_isr& operator =(const iqueue_spsc_isr&); - etl::ifunction& lock; ///< The callback that locks interrupts. - etl::ifunction& unlock; ///< The callback that unlocks interrupts. + TAccess access; ///< The object that locks/unlocks interrupts. }; //*************************************************************************** @@ -632,14 +632,15 @@ 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 - class queue_spsc_isr : public etl::iqueue_spsc_isr + template + class queue_spsc_isr : public etl::iqueue_spsc_isr { private: - typedef etl::iqueue_spsc_isr base_t; + typedef etl::iqueue_spsc_isr base_t; public: @@ -652,9 +653,8 @@ namespace etl //************************************************************************* /// Default constructor. //************************************************************************* - queue_spsc_isr(etl::ifunction& lock, - etl::ifunction& unlock) - : base_t(reinterpret_cast(&buffer[0]), MAX_SIZE, lock, unlock) + queue_spsc_isr() + : base_t(reinterpret_cast(&buffer[0]), MAX_SIZE) { } diff --git a/test/test_queue_spsc_isr.cpp b/test/test_queue_spsc_isr.cpp index ed465660..56516beb 100644 --- a/test/test_queue_spsc_isr.cpp +++ b/test/test_queue_spsc_isr.cpp @@ -29,7 +29,6 @@ SOFTWARE. #include "UnitTest++.h" #include "etl/queue_spsc_isr.h" -#include "etl/function.h" #include #include @@ -47,46 +46,44 @@ namespace { public: - void clear() + static void clear() { - called_lock = false; + called_lock = false; called_unlock = false; } - void lock() + static void lock() { called_lock = true; } - void unlock() + static void unlock() { called_unlock = true; } - bool called_lock; - bool called_unlock; + static bool called_lock; + static bool called_unlock; }; - Access access; - - etl::function_imv lock; - etl::function_imv unlock; + bool Access::called_lock; + bool Access::called_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) { } @@ -106,121 +103,121 @@ namespace //************************************************************************* TEST(test_constructor) { - access.clear(); + Access::clear(); - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; 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 queue(lock, unlock); + etl::queue_spsc_isr queue; 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)); @@ -229,92 +226,92 @@ namespace //************************************************************************* TEST(test_size_push_pop_iqueue) { - access.clear(); + Access::clear(); - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; - etl::iqueue_spsc_isr& iqueue = queue; + etl::iqueue_spsc_isr& 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)); @@ -323,84 +320,84 @@ namespace //************************************************************************* TEST(test_size_push_pop_void) { - access.clear(); + Access::clear(); - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; 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()); @@ -409,7 +406,7 @@ namespace //************************************************************************* TEST(test_multiple_emplace) { - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; queue.emplace(1); queue.emplace(1, 2); @@ -433,20 +430,20 @@ namespace //************************************************************************* TEST(test_clear) { - access.clear(); + Access::clear(); - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; 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); @@ -454,84 +451,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 queue(lock, unlock); + etl::queue_spsc_isr queue; 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 queue(lock, unlock); + etl::queue_spsc_isr queue; 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); } //========================================================================= @@ -547,25 +544,22 @@ namespace struct ThreadLock { - void lock() + static void lock() { mutex.lock(); } - void unlock() + static void unlock() { mutex.unlock(); } - std::mutex mutex; + static std::mutex mutex; }; - ThreadLock threadLock; + std::mutex ThreadLock::mutex; - etl::function_imv lock; - etl::function_imv unlock; - - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; const size_t LENGTH = 1000; @@ -580,14 +574,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); diff --git a/test/test_queue_spsc_isr_small.cpp b/test/test_queue_spsc_isr_small.cpp index 643970a6..ca5f4f22 100644 --- a/test/test_queue_spsc_isr_small.cpp +++ b/test/test_queue_spsc_isr_small.cpp @@ -46,46 +46,44 @@ namespace { public: - void clear() + static void clear() { called_lock = false; called_unlock = false; } - void lock() + static void lock() { called_lock = true; } - void unlock() + static void unlock() { called_unlock = true; } - bool called_lock; - bool called_unlock; + static bool called_lock; + static bool called_unlock; }; - Access access; - - etl::function_imv lock; - etl::function_imv unlock; + bool Access::called_lock; + bool Access::called_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) { } @@ -100,131 +98,131 @@ namespace return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); } - typedef etl::queue_spsc_isr QueueInt; - typedef etl::iqueue_spsc_isr IQueueInt; + typedef etl::queue_spsc_isr QueueInt; + typedef etl::iqueue_spsc_isr IQueueInt; - typedef etl::queue_spsc_isr QueueInt255; + typedef etl::queue_spsc_isr QueueInt255; SUITE(test_queue_isr) { //************************************************************************* TEST(test_constructor) { - access.clear(); + Access::clear(); - QueueInt queue(lock, unlock); + QueueInt queue; 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(lock, unlock); + QueueInt queue; 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)); @@ -233,92 +231,92 @@ namespace //************************************************************************* TEST(test_size_push_pop_iqueue) { - access.clear(); + Access::clear(); - QueueInt queue(lock, unlock); + QueueInt queue; 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)); @@ -327,84 +325,84 @@ namespace //************************************************************************* TEST(test_size_push_pop_void) { - access.clear(); + Access::clear(); - QueueInt queue(lock, unlock); + QueueInt queue; 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()); @@ -413,7 +411,7 @@ namespace //************************************************************************* TEST(test_push_255) { - QueueInt255 queue(lock, unlock); + QueueInt255 queue; for (int i = 0; i < 255; ++i) { @@ -426,7 +424,7 @@ namespace //************************************************************************* TEST(test_multiple_emplace) { - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; queue.emplace(1); queue.emplace(1, 2); @@ -450,20 +448,20 @@ namespace //************************************************************************* TEST(test_clear) { - access.clear(); + Access::clear(); - QueueInt queue(lock, unlock); + QueueInt queue; 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); @@ -471,84 +469,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(lock, unlock); + QueueInt queue; 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(lock, unlock); + QueueInt queue; 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); } //========================================================================= @@ -564,25 +562,22 @@ namespace struct ThreadLock { - void lock() + static void lock() { mutex.lock(); } - void unlock() + static void unlock() { mutex.unlock(); } - std::mutex mutex; + static std::mutex mutex; }; - ThreadLock threadLock; + std::mutex ThreadLock::mutex; - etl::function_imv lock; - etl::function_imv unlock; - - etl::queue_spsc_isr queue(lock, unlock); + etl::queue_spsc_isr queue; const size_t LENGTH = 1000; @@ -597,14 +592,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); From 8cfb3fce23d8026c227daf084e41d5c4e1dda022 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 25 Feb 2019 09:42:51 +0100 Subject: [PATCH 3/4] Added queue_spsc_locked with injected lock and unlock functionality. --- include/etl/queue_spsc_isr.h | 6 +- include/etl/queue_spsc_locked.h | 681 ++++++++++++++++++++++++++ include/etl/version.h | 2 +- support/Release notes.txt | 4 + test/etl_profile.h | 1 + test/test_queue_spsc_locked.cpp | 628 ++++++++++++++++++++++++ test/test_queue_spsc_locked_small.cpp | 645 ++++++++++++++++++++++++ test/vs2017/etl.vcxproj | 3 + test/vs2017/etl.vcxproj.filters | 9 + 9 files changed, 1975 insertions(+), 4 deletions(-) create mode 100644 include/etl/queue_spsc_locked.h create mode 100644 test/test_queue_spsc_locked.cpp create mode 100644 test/test_queue_spsc_locked_small.cpp diff --git a/include/etl/queue_spsc_isr.h b/include/etl/queue_spsc_isr.h index e4918ad7..c9f7c5fb 100644 --- a/include/etl/queue_spsc_isr.h +++ b/include/etl/queue_spsc_isr.h @@ -74,7 +74,7 @@ namespace etl /// 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 && !defined(ETL_STLPORT) && !ETL_QUEUE_ISR_FORCE_CPP03 +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_QUEUE_ISR_FORCE_CPP03) template bool emplace_from_isr(Args&&... args) { @@ -192,7 +192,7 @@ namespace etl return false; } -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !ETL_QUEUE_ISR_FORCE_CPP03 +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_QUEUE_ISR_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. @@ -430,7 +430,7 @@ namespace etl /// 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 && !defined(ETL_STLPORT) && !ETL_QUEUE_ISR_FORCE_CPP03 +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_QUEUE_ISR_FORCE_CPP03) template bool emplace(Args&&... args) { diff --git a/include/etl/queue_spsc_locked.h b/include/etl/queue_spsc_locked.h new file mode 100644 index 00000000..d2c3a2c2 --- /dev/null +++ b/include/etl/queue_spsc_locked.h @@ -0,0 +1,681 @@ +///\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_SPSC_QUEUE_LOCKED_INCLUDED +#define ETL_SPSC_QUEUE_LOCKED_INCLUDED + +#include +#include + +#include "platform.h" +#include "alignment.h" +#include "parameter_type.h" +#include "memory_model.h" +#include "integral_limits.h" +#include "function.h" + +#undef ETL_FILE +#define ETL_FILE "46" + +namespace etl +{ + template + class queue_spsc_isr_base + { + protected: + + typedef typename etl::parameter_type::type parameter_t; + + public: + + /// The type used for determining the size of queue. + typedef typename etl::size_type_lookup::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. + + //************************************************************************* + /// Push a value to the queue from an ISR. + //************************************************************************* + bool push_from_unlocked(parameter_t value) + { + return push_implementation(value); + } + + //************************************************************************* + /// 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 && !defined(ETL_STLPORT) && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03) + template + bool emplace_from_unlocked(Args&&... args) + { + return emplace_implementation(std::forward(args)...); + } +#endif + + //************************************************************************* + /// Pop a value from the queue from an ISR + //************************************************************************* + bool pop_from_unlocked(reference value) + { + return pop_implementation(value); + } + + //************************************************************************* + /// 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: + + queue_spsc_isr_base(T* p_buffer_, size_type max_size_) + : p_buffer(p_buffer_), + write_index(0), + read_index(0), + current_size(0), + MAX_SIZE(max_size_) + { + } + + //************************************************************************* + /// Push a value to the queue. + //************************************************************************* + bool push_implementation(parameter_t value) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(value); + + write_index = get_next_index(write_index, MAX_SIZE); + + ++current_size; + + return true; + } + + // Queue is full. + return false; + } + +#if ETL_CPP11_SUPPORTED && !defined(ETL_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 + bool emplace_implementation(Args&&... args) + { + if (current_size != MAX_SIZE) + { + ::new (&p_buffer[write_index]) T(std::forward(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 + 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 + 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 + 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 + 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; + } + + //************************************************************************* + /// 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. + + private: + + //************************************************************************* + /// Destructor. + //************************************************************************* +#if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ISR) || defined(ETL_POLYMORPHIC_CONTAINERS) + public: + virtual ~queue_spsc_isr_base() + { + } +#else + protected: + ~queue_spsc_isr_base() + { + } +#endif + }; + + //*************************************************************************** + ///\ingroup queue_spsc + ///\brief This is the base for all queue_spsc_isrs that contain a particular type. + ///\details Normally a reference to this type will be taken from a derived queue_spsc_locked. + /// This queue supports concurrent access by one producer and one consumer. + /// \tparam T The type of value that the queue_spsc_locked holds. + //*************************************************************************** + template + class iqueue_spsc_locked : public queue_spsc_isr_base + { + private: + + typedef queue_spsc_isr_base base_t; + typedef typename base_t::parameter_t parameter_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. + 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(parameter_t value) + { + lock(); + + bool result = this->push_implementation(value); + + 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. + //************************************************************************* +#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03) + template + bool emplace(Args&&... args) + { + lock(); + + bool result = this->emplace_implementation(std::forward(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 + 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 + 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 + 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 + 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; + } + + //************************************************************************* + /// 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_spsc_locked(T* p_buffer_, size_type max_size_, etl::ifunction& lock_, etl::ifunction& unlock_) + : base_t(p_buffer_, max_size_) + , lock(lock_) + , unlock(unlock_) + { + } + + private: + + // Disable copy construction and assignment. + iqueue_spsc_locked(const iqueue_spsc_locked&); + iqueue_spsc_locked& operator =(const iqueue_spsc_locked&); + + etl::ifunction& lock; ///< The callback that locks interrupts. + etl::ifunction& unlock; ///< The callback that unlocks interrupts. + }; + + //*************************************************************************** + ///\ingroup queue_spsc + /// A fixed capacity spsc queue. + /// This queue supports concurrent access by one producer and one consumer. + /// \tparam T The type this queue should support. + /// \tparam SIZE The maximum capacity of the queue. + /// \tparam MEMORY_MODEL The memory model for the queue. Determines the type of the internal counter variables. + //*************************************************************************** + template + class queue_spsc_locked : public etl::iqueue_spsc_locked + { + private: + + typedef etl::iqueue_spsc_locked base_t; + + public: + + typedef typename base_t::size_type size_type; + + ETL_STATIC_ASSERT((SIZE <= etl::integral_limits::max), "Size too large for memory model"); + + static const size_type MAX_SIZE = size_type(SIZE); + + //************************************************************************* + /// Default constructor. + //************************************************************************* + queue_spsc_locked(etl::ifunction& lock, + etl::ifunction& unlock) + : base_t(reinterpret_cast(&buffer[0]), MAX_SIZE, lock, unlock) + { + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~queue_spsc_locked() + { + base_t::clear(); + } + + private: + + queue_spsc_locked(const queue_spsc_locked&); + queue_spsc_locked& operator = (const queue_spsc_locked&); + + /// The uninitialised buffer of T used in the queue_spsc_locked. + typename etl::aligned_storage::value>::type buffer[MAX_SIZE]; + }; +} + +#undef ETL_FILE + +#endif diff --git a/include/etl/version.h b/include/etl/version.h index d717855e..5e46f2bc 100644 --- a/include/etl/version.h +++ b/include/etl/version.h @@ -38,7 +38,7 @@ SOFTWARE. ///\ingroup utilities #define ETL_VERSION_MAJOR 14 -#define ETL_VERSION_MINOR 12 +#define ETL_VERSION_MINOR 13 #define ETL_VERSION_PATCH 0 #define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) ETL_STRINGIFY(ETL_VERSION_MINOR) ETL_STRINGIFY(ETL_VERSION_PATCH) diff --git a/support/Release notes.txt b/support/Release notes.txt index e21a933b..a678831c 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,7 @@ +=============================================================================== +14.13.0 +Changed API for etl::queue_spsc_isr + =============================================================================== 14.12.0 Enabled emplace functions for C++03. diff --git a/test/etl_profile.h b/test/etl_profile.h index 02e0861a..95880884 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -84,6 +84,7 @@ SOFTWARE. //#define ETL_QUEUE_FORCE_CPP03 //#define ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03 //#define ETL_QUEUE_ISR_FORCE_CPP03 +//#define ETL_QUEUE_LOCKED_FORCE_CPP03 #ifdef _MSC_VER #include "etl/profiles/msvc_x86.h" diff --git a/test/test_queue_spsc_locked.cpp b/test/test_queue_spsc_locked.cpp new file mode 100644 index 00000000..60f4a31e --- /dev/null +++ b/test/test_queue_spsc_locked.cpp @@ -0,0 +1,628 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://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. +******************************************************************************/ + +#include "UnitTest++.h" + +#include "etl/queue_spsc_locked.h" +#include "etl/function.h" + +#include +#include +#include + +#if defined(ETL_COMPILER_MICROSOFT) +#include +#endif + +#define REALTIME_TEST 0 + +namespace +{ + class Access + { + public: + + void clear() + { + called_lock = false; + called_unlock = false; + } + + void lock() + { + called_lock = true; + } + + void unlock() + { + called_unlock = true; + } + + bool called_lock; + bool called_unlock; + }; + + Access access; + + etl::function_imv lock; + etl::function_imv unlock; + + 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); + } + + SUITE(test_queue_locked) + { + //************************************************************************* + TEST(test_constructor) + { + access.clear(); + + etl::queue_spsc_locked queue(lock, unlock); + + CHECK_EQUAL(4U, queue.max_size()); + CHECK_EQUAL(4U, queue.capacity()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + } + + //************************************************************************* + TEST(test_size_push_pop) + { + access.clear(); + + etl::queue_spsc_locked queue(lock, unlock); + + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(4U, queue.available_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(0U, queue.size()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + CHECK_EQUAL(4U, queue.available()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + queue.push_from_unlocked(1); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + CHECK_EQUAL(3U, queue.available_from_unlocked()); + + access.clear(); + + queue.push(2); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + CHECK_EQUAL(2U, queue.available_from_unlocked()); + + access.clear(); + + queue.push(3); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + CHECK_EQUAL(1U, queue.available_from_unlocked()); + + access.clear(); + + queue.push(4); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(4U, queue.size_from_unlocked()); + CHECK_EQUAL(0U, queue.available_from_unlocked()); + + access.clear(); + + CHECK(!queue.push(5)); + CHECK(!queue.push_from_unlocked(5)); + + access.clear(); + + int i; + + CHECK(queue.pop(i)); + CHECK_EQUAL(1, i); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked(i)); + CHECK_EQUAL(2, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked(i)); + CHECK_EQUAL(3, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked(i)); + CHECK_EQUAL(4, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(!queue.pop(i)); + CHECK(!queue.pop_from_unlocked(i)); + } + + //************************************************************************* + TEST(test_size_push_pop_iqueue) + { + access.clear(); + + etl::queue_spsc_locked queue(lock, unlock); + + etl::iqueue_spsc_locked& iqueue = queue; + + CHECK_EQUAL(0U, iqueue.size_from_unlocked()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(0U, iqueue.size()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + iqueue.push_from_unlocked(1); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, iqueue.size_from_unlocked()); + + access.clear(); + + iqueue.push(2); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(2U, iqueue.size_from_unlocked()); + + access.clear(); + + iqueue.push(3); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, iqueue.size_from_unlocked()); + + access.clear(); + + iqueue.push(4); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(4U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(!iqueue.push(5)); + CHECK(!iqueue.push_from_unlocked(5)); + + access.clear(); + + int i; + + CHECK(iqueue.pop(i)); + CHECK_EQUAL(1, i); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(iqueue.pop_from_unlocked(i)); + CHECK_EQUAL(2, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(2U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(iqueue.pop_from_unlocked(i)); + CHECK_EQUAL(3, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(iqueue.pop_from_unlocked(i)); + CHECK_EQUAL(4, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(0U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(!iqueue.pop(i)); + CHECK(!iqueue.pop_from_unlocked(i)); + } + + //************************************************************************* + TEST(test_size_push_pop_void) + { + access.clear(); + + etl::queue_spsc_locked queue(lock, unlock); + + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(0U, queue.size()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + queue.push_from_unlocked(1); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + + access.clear(); + + queue.push(2); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + + access.clear(); + + queue.push(3); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + + access.clear(); + + queue.push(4); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(4U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(!queue.push(5)); + CHECK(!queue.push_from_unlocked(5)); + + access.clear(); + + CHECK(queue.pop()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(!queue.pop()); + CHECK(!queue.pop_from_unlocked()); + } + + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_spsc_locked queue(lock, unlock); + + 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) + { + access.clear(); + + etl::queue_spsc_locked 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_EQUAL(0U, queue.size()); + + access.clear(); + + // 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(!access.called_lock); + CHECK(!access.called_unlock); + } + + //************************************************************************* + TEST(test_empty) + { + access.clear(); + + etl::queue_spsc_locked queue(lock, unlock); + + CHECK(queue.empty()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.push(1); + + access.clear(); + + CHECK(!queue.empty()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.clear(); + access.clear(); + + CHECK(queue.empty_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + queue.push(1); + + access.clear(); + + CHECK(!queue.empty_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + } + + //************************************************************************* + TEST(test_full) + { + access.clear(); + + etl::queue_spsc_locked queue(lock, unlock); + + CHECK(!queue.full()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.push(1); + queue.push(2); + queue.push(3); + queue.push(4); + + access.clear(); + + CHECK(queue.full()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.clear(); + access.clear(); + + CHECK(!queue.full_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + queue.push(1); + queue.push(2); + queue.push(3); + queue.push(4); + + access.clear(); + + CHECK(queue.full_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + } + + //========================================================================= +#if REALTIME_TEST && defined(ETL_COMPILER_MICROSOFT) + #if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported + #define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) + #define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1); + #else + #error No thread priority modifier defined + #endif + + size_t ticks = 0; + + struct ThreadLock + { + void lock() + { + mutex.lock(); + } + + void unlock() + { + mutex.unlock(); + } + + std::mutex mutex; + }; + + ThreadLock threadLock; + + etl::function_imv lock; + etl::function_imv unlock; + + etl::queue_spsc_locked queue(lock, unlock); + + const size_t LENGTH = 1000; + + void timer_thread() + { + RAISE_THREAD_PRIORITY; + FIX_PROCESSOR_AFFINITY; + + const size_t TICK = 1; + size_t tick = TICK; + ticks = 1; + + while (ticks <= LENGTH) + { + if (threadLock.mutex.try_lock()) + { + if (queue.push_from_unlocked(ticks)) + { + ++ticks; + } + + threadLock.mutex.unlock(); + } + + Sleep(0); + } + } + + TEST(queue_threads) + { + FIX_PROCESSOR_AFFINITY; + + std::vector 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 + }; +} diff --git a/test/test_queue_spsc_locked_small.cpp b/test/test_queue_spsc_locked_small.cpp new file mode 100644 index 00000000..30bedefb --- /dev/null +++ b/test/test_queue_spsc_locked_small.cpp @@ -0,0 +1,645 @@ +/****************************************************************************** +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. +******************************************************************************/ + +#include "UnitTest++.h" + +#include "etl/queue_spsc_locked.h" + +#include +#include +#include + +#if defined(ETL_COMPILER_MICROSOFT) +#include +#endif + +#define REALTIME_TEST 0 + +namespace +{ + class Access + { + public: + + void clear() + { + called_lock = false; + called_unlock = false; + } + + void lock() + { + called_lock = true; + } + + void unlock() + { + called_unlock = true; + } + + bool called_lock; + bool called_unlock; + }; + + Access access; + + etl::function_imv lock; + etl::function_imv unlock; + + 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); + } + + typedef etl::queue_spsc_locked QueueInt; + typedef etl::iqueue_spsc_locked IQueueInt; + + typedef etl::queue_spsc_locked QueueInt255; + + SUITE(test_queue_locked) + { + //************************************************************************* + TEST(test_constructor) + { + access.clear(); + + QueueInt queue(lock, unlock); + + CHECK_EQUAL(4U, queue.max_size()); + CHECK_EQUAL(4U, queue.capacity()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + } + + //************************************************************************* + TEST(test_size_push_pop) + { + access.clear(); + + QueueInt queue(lock, unlock); + + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(4U, queue.available_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(0U, queue.size()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + CHECK_EQUAL(4U, queue.available()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + queue.push_from_unlocked(1); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + CHECK_EQUAL(3U, queue.available_from_unlocked()); + + access.clear(); + + queue.push(2); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + CHECK_EQUAL(2U, queue.available_from_unlocked()); + + access.clear(); + + queue.push(3); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + CHECK_EQUAL(1U, queue.available_from_unlocked()); + + access.clear(); + + queue.push(4); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(4U, queue.size_from_unlocked()); + CHECK_EQUAL(0U, queue.available_from_unlocked()); + + access.clear(); + + CHECK(!queue.push(5)); + CHECK(!queue.push_from_unlocked(5)); + + access.clear(); + + int i; + + CHECK(queue.pop(i)); + CHECK_EQUAL(1, i); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked(i)); + CHECK_EQUAL(2, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked(i)); + CHECK_EQUAL(3, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked(i)); + CHECK_EQUAL(4, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(!queue.pop(i)); + CHECK(!queue.pop_from_unlocked(i)); + } + + //************************************************************************* + TEST(test_size_push_pop_iqueue) + { + access.clear(); + + QueueInt queue(lock, unlock); + + IQueueInt& iqueue = queue; + + CHECK_EQUAL(0U, iqueue.size_from_unlocked()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(0U, iqueue.size()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + iqueue.push_from_unlocked(1); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, iqueue.size_from_unlocked()); + + access.clear(); + + iqueue.push(2); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(2U, iqueue.size_from_unlocked()); + + access.clear(); + + iqueue.push(3); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, iqueue.size_from_unlocked()); + + access.clear(); + + iqueue.push(4); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(4U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(!iqueue.push(5)); + CHECK(!iqueue.push_from_unlocked(5)); + + access.clear(); + + int i; + + CHECK(iqueue.pop(i)); + CHECK_EQUAL(1, i); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(iqueue.pop_from_unlocked(i)); + CHECK_EQUAL(2, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(2U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(iqueue.pop_from_unlocked(i)); + CHECK_EQUAL(3, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(iqueue.pop_from_unlocked(i)); + CHECK_EQUAL(4, i); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(0U, iqueue.size_from_unlocked()); + + access.clear(); + + CHECK(!iqueue.pop(i)); + CHECK(!iqueue.pop_from_unlocked(i)); + } + + //************************************************************************* + TEST(test_size_push_pop_void) + { + access.clear(); + + QueueInt queue(lock, unlock); + + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + access.clear(); + + CHECK_EQUAL(0U, queue.size()); + + CHECK(access.called_lock); + CHECK(access.called_unlock); + + access.clear(); + + queue.push_from_unlocked(1); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + + access.clear(); + + queue.push(2); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + + access.clear(); + + queue.push(3); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + + access.clear(); + + queue.push(4); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(4U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(!queue.push(5)); + CHECK(!queue.push_from_unlocked(5)); + + access.clear(); + + CHECK(queue.pop()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + CHECK_EQUAL(3U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(2U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(1U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(queue.pop_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + CHECK_EQUAL(0U, queue.size_from_unlocked()); + + access.clear(); + + CHECK(!queue.pop()); + CHECK(!queue.pop_from_unlocked()); + } + + //************************************************************************* + TEST(test_push_255) + { + QueueInt255 queue(lock, unlock); + + for (int i = 0; i < 255; ++i) + { + queue.push(i); + } + + CHECK_EQUAL(255U, queue.size()); + } + + //************************************************************************* + TEST(test_multiple_emplace) + { + etl::queue_spsc_locked queue(lock, unlock); + + 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) + { + access.clear(); + + 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_EQUAL(0U, queue.size()); + + access.clear(); + + // 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(!access.called_lock); + CHECK(!access.called_unlock); + } + + //************************************************************************* + TEST(test_empty) + { + access.clear(); + + QueueInt queue(lock, unlock); + + CHECK(queue.empty()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.push(1); + + access.clear(); + + CHECK(!queue.empty()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.clear(); + access.clear(); + + CHECK(queue.empty_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + queue.push(1); + + access.clear(); + + CHECK(!queue.empty_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + } + + //************************************************************************* + TEST(test_full) + { + access.clear(); + + QueueInt queue(lock, unlock); + + CHECK(!queue.full()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.push(1); + queue.push(2); + queue.push(3); + queue.push(4); + + access.clear(); + + CHECK(queue.full()); + CHECK(access.called_lock); + CHECK(access.called_unlock); + + queue.clear(); + access.clear(); + + CHECK(!queue.full_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + + queue.push(1); + queue.push(2); + queue.push(3); + queue.push(4); + + access.clear(); + + CHECK(queue.full_from_unlocked()); + CHECK(!access.called_lock); + CHECK(!access.called_unlock); + } + + //========================================================================= +#if REALTIME_TEST && defined(ETL_COMPILER_MICROSOFT) + #if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported + #define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) + #define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1); + #else + #error No thread priority modifier defined + #endif + + size_t ticks = 0; + + struct ThreadLock + { + void lock() + { + mutex.lock(); + } + + void unlock() + { + mutex.unlock(); + } + + std::mutex mutex; + }; + + ThreadLock threadLock; + + etl::function_imv lock; + etl::function_imv unlock; + + etl::queue_spsc_locked queue(lock, unlock); + + const size_t LENGTH = 1000; + + void timer_thread() + { + RAISE_THREAD_PRIORITY; + FIX_PROCESSOR_AFFINITY; + + const size_t TICK = 1; + size_t tick = TICK; + ticks = 1; + + while (ticks <= LENGTH) + { + if (threadLock.mutex.try_lock()) + { + if (queue.push_from_unlocked(ticks)) + { + ++ticks; + } + + threadLock.mutex.unlock(); + } + + Sleep(0); + } + } + + TEST(queue_threads) + { + FIX_PROCESSOR_AFFINITY; + + std::vector 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 + }; +} diff --git a/test/vs2017/etl.vcxproj b/test/vs2017/etl.vcxproj index 113befae..d01f21d8 100644 --- a/test/vs2017/etl.vcxproj +++ b/test/vs2017/etl.vcxproj @@ -377,6 +377,7 @@ + @@ -720,6 +721,8 @@ + + true true diff --git a/test/vs2017/etl.vcxproj.filters b/test/vs2017/etl.vcxproj.filters index 170e9085..bb822b22 100644 --- a/test/vs2017/etl.vcxproj.filters +++ b/test/vs2017/etl.vcxproj.filters @@ -729,6 +729,9 @@ ETL\Maths + + ETL\Containers + @@ -1154,6 +1157,12 @@ Source Files + + Source Files + + + Source Files + From 752191e8198d22dbe5f6bf8bd080388ca4052833 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 26 Feb 2019 10:00:21 +0100 Subject: [PATCH 4/4] Updated profiles for C++17 --- include/etl/profiles/gcc_generic.h | 2 +- include/etl/profiles/gcc_linux_x86.h | 2 +- include/etl/profiles/gcc_windows_x86.h | 2 +- include/etl/profiles/segger_gcc_stlport.h | 2 +- support/Release notes.txt | 4 ++-- test/codeblocks/ETL.cbp | 2 ++ 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/etl/profiles/gcc_generic.h b/include/etl/profiles/gcc_generic.h index 39826014..74fba031 100644 --- a/include/etl/profiles/gcc_generic.h +++ b/include/etl/profiles/gcc_generic.h @@ -41,7 +41,7 @@ SOFTWARE. #ifdef __cplusplus #define ETL_CPP11_SUPPORTED (__cplusplus >= 201103L) #define ETL_CPP14_SUPPORTED (__cplusplus >= 201402L) - #define ETL_CPP17_SUPPORTED 0 + #define ETL_CPP17_SUPPORTED (__cplusplus >= 201703L) #else #define ETL_CPP11_SUPPORTED 0 #define ETL_CPP14_SUPPORTED 0 diff --git a/include/etl/profiles/gcc_linux_x86.h b/include/etl/profiles/gcc_linux_x86.h index c9a3c9cc..24ab6c68 100644 --- a/include/etl/profiles/gcc_linux_x86.h +++ b/include/etl/profiles/gcc_linux_x86.h @@ -41,7 +41,7 @@ SOFTWARE. #ifdef __cplusplus #define ETL_CPP11_SUPPORTED (__cplusplus >= 201103L) #define ETL_CPP14_SUPPORTED (__cplusplus >= 201402L) - #define ETL_CPP17_SUPPORTED 0 + #define ETL_CPP17_SUPPORTED (__cplusplus >= 201703L) #else #define ETL_CPP11_SUPPORTED 0 #define ETL_CPP14_SUPPORTED 0 diff --git a/include/etl/profiles/gcc_windows_x86.h b/include/etl/profiles/gcc_windows_x86.h index a5a83349..c04151d9 100644 --- a/include/etl/profiles/gcc_windows_x86.h +++ b/include/etl/profiles/gcc_windows_x86.h @@ -41,7 +41,7 @@ SOFTWARE. #ifdef __cplusplus #define ETL_CPP11_SUPPORTED (__cplusplus >= 201103L) #define ETL_CPP14_SUPPORTED (__cplusplus >= 201402L) - #define ETL_CPP17_SUPPORTED 0 + #define ETL_CPP17_SUPPORTED (__cplusplus >= 201703L) #else #define ETL_CPP11_SUPPORTED 0 #define ETL_CPP14_SUPPORTED 0 diff --git a/include/etl/profiles/segger_gcc_stlport.h b/include/etl/profiles/segger_gcc_stlport.h index c626bb29..45a0d844 100644 --- a/include/etl/profiles/segger_gcc_stlport.h +++ b/include/etl/profiles/segger_gcc_stlport.h @@ -41,7 +41,7 @@ SOFTWARE. #ifdef __cplusplus #define ETL_CPP11_SUPPORTED (__cplusplus >= 201103L) #define ETL_CPP14_SUPPORTED (__cplusplus >= 201402L) - #define ETL_CPP17_SUPPORTED 0 + #define ETL_CPP17_SUPPORTED (__cplusplus >= 201703L) #else #define ETL_CPP11_SUPPORTED 0 #define ETL_CPP14_SUPPORTED 0 diff --git a/support/Release notes.txt b/support/Release notes.txt index a678831c..5a6d8671 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,10 +1,10 @@ =============================================================================== 14.13.0 -Changed API for etl::queue_spsc_isr +Added etl::queue_spsc_locked with injected locking functions. =============================================================================== 14.12.0 -Enabled emplace functions for C++03. +Enabled emplace functions for 'No STL'. =============================================================================== 14.11.3 diff --git a/test/codeblocks/ETL.cbp b/test/codeblocks/ETL.cbp index c573df20..17829a76 100644 --- a/test/codeblocks/ETL.cbp +++ b/test/codeblocks/ETL.cbp @@ -410,6 +410,8 @@ + +