From 879fb1f6265271bfd31ab1a906b8a33a42eab30b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 5 Feb 2018 21:16:43 +0000 Subject: [PATCH] Improvements to message and callback timer frameworks. Reduced disable/enable time dur function calls. Added the option to use either atomic semaphores or interrupt enables to control access. --- library.properties | 2 +- src/c/ecl_timer.c | 28 +- src/callback_timer.h | 78 ++- src/message_timer.h | 75 ++- support/Release notes.txt | 6 + test/codeblocks/ETL.layout | 1051 +++++++++++++++---------------- test/ecl_user.h | 16 +- test/etl_profile.h | 3 + test/test_c_timer_framework.cpp | 2 + 9 files changed, 645 insertions(+), 616 deletions(-) diff --git a/library.properties b/library.properties index b0890a1f..bfa833f7 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Embedded Template Library -version=10.17.0 +version=10.18.0 author= John Wellbelove maintainer=John Wellbelove sentence=A C++ template library tailored for embedded systems. diff --git a/src/c/ecl_timer.c b/src/c/ecl_timer.c index 2b6e3e77..3fb41b74 100644 --- a/src/c/ecl_timer.c +++ b/src/c/ecl_timer.c @@ -261,7 +261,6 @@ struct ecl_time_config struct ecl_timer_config* ptimers; uint_least8_t max_timers; volatile ecl_timer_enable_t enabled; - ECL_TIMER_TIMER_SEMAPHORE process_semaphore; volatile uint_least8_t registered_timers; }; @@ -274,7 +273,6 @@ void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_ ecl.ptimers = ptimers_; ecl.max_timers = max_timers_; ecl.enabled = 0; - ecl.process_semaphore = 0; ecl.registered_timers = 0; int i; @@ -298,7 +296,7 @@ ecl_timer_id_t ecl_timer_register(void (*pcallback_)(), ecl_timer_id_t id = ECL_TIMER_NO_TIMER; - ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + ECL_TIMER_DISABLE_PROCESSING; int is_space = (ecl.registered_timers < ecl.max_timers); @@ -321,7 +319,7 @@ ecl_timer_id_t ecl_timer_register(void (*pcallback_)(), } } - ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); + ECL_TIMER_ENABLE_PROCESSING; return id; } @@ -337,7 +335,7 @@ ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_) if (id_ != ECL_TIMER_NO_TIMER) { - ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + ECL_TIMER_DISABLE_PROCESSING; struct ecl_timer_config* ptimer = &ecl.ptimers[id_]; @@ -355,7 +353,7 @@ ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_) } } - ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); + ECL_TIMER_ENABLE_PROCESSING; } return result; @@ -385,7 +383,7 @@ ecl_timer_result_t ecl_timer_is_running() //******************************************* void ecl_timer_clear() { - ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + ECL_TIMER_DISABLE_PROCESSING; ecl_timer_list_clear(); @@ -397,7 +395,7 @@ void ecl_timer_clear() ecl.registered_timers = 0; - ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); + ECL_TIMER_ENABLE_PROCESSING; } //******************************************* @@ -411,7 +409,7 @@ ecl_timer_result_t ecl_timer_tick(uint32_t count) if (ecl.enabled) { - if (ECL_TIMER_PROCESSING_ENABLED(ecl.process_semaphore)) + if (ECL_TIMER_PROCESSING_ENABLED) { // We have something to do? int has_active = !ecl_timer_list_empty(); @@ -463,8 +461,6 @@ ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immedia { assert(ecl.ptimers != 0); - ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); - ecl_timer_result_t result = ECL_TIMER_FAIL; // Valid timer id? @@ -478,6 +474,7 @@ ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immedia // Has a valid period. if (ptimer->period != ECL_TIMER_INACTIVE) { + ECL_TIMER_DISABLE_PROCESSING; if (ecl_timer_is_active(ptimer)) { ecl_timer_list_remove(ptimer->id, 0); @@ -485,14 +482,13 @@ ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immedia ptimer->delta = immediate_ ? 0 : ptimer->period; ecl_timer_list_insert(ptimer->id); + ECL_TIMER_ENABLE_PROCESSING; result = ECL_TIMER_PASS; } } } - ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); - return result; } @@ -503,8 +499,6 @@ ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_) { assert(ecl.ptimers != 0); - ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); - ecl_timer_result_t result = ECL_TIMER_FAIL; // Valid timer id? @@ -517,14 +511,14 @@ ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_) { if (ecl_timer_is_active(ptimer)) { + ECL_TIMER_DISABLE_PROCESSING; ecl_timer_list_remove(ptimer->id, 0); + ECL_TIMER_ENABLE_PROCESSING; result = ECL_TIMER_PASS; } } } - ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); - return result; } diff --git a/src/callback_timer.h b/src/callback_timer.h index d8e5124c..8ed39417 100644 --- a/src/callback_timer.h +++ b/src/callback_timer.h @@ -42,6 +42,30 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "42" +#if !defined(ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK) && !defined(ETL_CALLBACK_TIMER_USE_INTERRUPT_LOCK) + #error ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK or ETL_CALLBACK_TIMER_USE_INTERRUPT_LOCK not defined +#endif + +#if defined(ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK) && defined(ETL_CALLBACK_TIMER_USE_INTERRUPT_LOCK) + #error Only define one of ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK or ETL_CALLBACK_TIMER_USE_INTERRUPT_LOCK +#endif + +#if defined(ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK) + #define ETL_DISABLE_TIMER_UPDATES (++process_semaphore) + #define ETL_ENABLE_TIMER_UPDATES (--process_semaphore) + #define ETL_TIMER_UPDATES_ENABLED (process_semaphore.load() == 0) +#endif + +#if defined(ETL_CALLBACK_TIMER_USE_INTERRUPT_LOCK) + #if !defined(ETL_CALLBACK_TIMER_DISABLE_INTERRUPTS) || !defined(ETL_CALLBACK_TIMER_ENABLE_INTERRUPTS) + #error ETL_CALLBACK_TIMER_DISABLE_INTERRUPTS and/or ETL_CALLBACK_TIMER_ENABLE_INTERRUPTS not defined + #endif + + #define ETL_DISABLE_TIMER_UPDATES (ETL_CALLBACK_TIMER_DISABLE_INTERRUPTS) + #define ETL_ENABLE_TIMER_UPDATES (ETL_CALLBACK_TIMER_ENABLE_INTERRUPTS) + #define ETL_TIMER_UPDATES_ENABLED true +#endif + namespace etl { //************************************************************************* @@ -326,7 +350,7 @@ namespace etl { etl::timer::id::type id = etl::timer::id::NO_TIMER; - disable_timer_updates(); + ETL_DISABLE_TIMER_UPDATES; bool is_space = (registered_timers < MAX_TIMERS); @@ -348,7 +372,7 @@ namespace etl } } - enable_timer_updates(); + ETL_ENABLE_TIMER_UPDATES; return id; } @@ -362,7 +386,7 @@ namespace etl { etl::timer::id::type id = etl::timer::id::NO_TIMER; - disable_timer_updates(); + ETL_DISABLE_TIMER_UPDATES; bool is_space = (registered_timers < MAX_TIMERS); @@ -384,7 +408,7 @@ namespace etl } } - enable_timer_updates(); + ETL_ENABLE_TIMER_UPDATES; return id; } @@ -398,7 +422,7 @@ namespace etl if (id_ != etl::timer::id::NO_TIMER) { - disable_timer_updates(); + ETL_DISABLE_TIMER_UPDATES; etl::callback_timer_data& timer = timer_array[id_]; @@ -416,7 +440,7 @@ namespace etl } } - enable_timer_updates(); + ETL_ENABLE_TIMER_UPDATES; } return result; @@ -443,7 +467,7 @@ namespace etl //******************************************* void clear() { - disable_timer_updates(); + ETL_DISABLE_TIMER_UPDATES; active_list.clear(); @@ -454,7 +478,7 @@ namespace etl registered_timers = 0; - enable_timer_updates(); + ETL_ENABLE_TIMER_UPDATES; } //******************************************* @@ -467,7 +491,7 @@ namespace etl { if (enabled) { - if (process_semaphore.load() == 0) + if (ETL_TIMER_UPDATES_ENABLED) { // We have something to do? bool has_active = !active_list.empty(); @@ -525,8 +549,6 @@ namespace etl //******************************************* bool start(etl::timer::id::type id_, bool immediate_ = false) { - disable_timer_updates(); - bool result = false; // Valid timer id? @@ -540,6 +562,7 @@ namespace etl // Has a valid period. if (timer.period != etl::timer::state::INACTIVE) { + ETL_DISABLE_TIMER_UPDATES; if (timer.is_active()) { active_list.remove(timer.id, false); @@ -547,14 +570,13 @@ namespace etl timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + ETL_ENABLE_TIMER_UPDATES; result = true; } } } - enable_timer_updates(); - return result; } @@ -563,8 +585,6 @@ namespace etl //******************************************* bool stop(etl::timer::id::type id_) { - disable_timer_updates(); - bool result = false; // Valid timer id? @@ -577,14 +597,14 @@ namespace etl { if (timer.is_active()) { + ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + ETL_ENABLE_TIMER_UPDATES; result = true; } } } - enable_timer_updates(); - return result; } @@ -625,7 +645,9 @@ namespace etl : timer_array(timer_array_), active_list(timer_array_), enabled(false), +#if defined(ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK) process_semaphore(0), +#endif registered_timers(0), MAX_TIMERS(MAX_TIMERS_) { @@ -633,22 +655,6 @@ namespace etl private: - //******************************************* - /// Enable timer callback events. - //******************************************* - void enable_timer_updates() - { - --process_semaphore; - } - - //******************************************* - /// Disable timer callback events. - //******************************************* - void disable_timer_updates() - { - ++process_semaphore; - } - // The array of timer data structures. callback_timer_data* const timer_array; @@ -656,7 +662,9 @@ namespace etl __private_callback_timer__::list active_list; volatile bool enabled; +#if defined(ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK) volatile etl::timer_semaphore_t process_semaphore; +#endif volatile uint_least8_t registered_timers; public: @@ -688,6 +696,10 @@ namespace etl }; } +#undef ETL_DISABLE_TIMER_UPDATES +#undef ETL_ENABLE_TIMER_UPDATES +#undef ETL_TIMER_UPDATES_ENABLED + #undef ETL_FILE #endif diff --git a/src/message_timer.h b/src/message_timer.h index 03a6a19c..d76bb94d 100644 --- a/src/message_timer.h +++ b/src/message_timer.h @@ -45,6 +45,30 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "41" +#if !defined(ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK) && !defined(ETL_MESSAGE_TIMER_USE_INTERRUPT_LOCK) + #error ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK or ETL_MESSAGE_TIMER_USE_INTERRUPT_LOCK not defined +#endif + +#if defined(ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK) && defined(ETL_MESSAGE_TIMER_USE_INTERRUPT_LOCK) + #error Only define one of ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK or ETL_MESSAGE_TIMER_USE_INTERRUPT_LOCK +#endif + +#if defined(ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK) + #define ETL_DISABLE_TIMER_UPDATES (++process_semaphore) + #define ETL_ENABLE_TIMER_UPDATES (--process_semaphore) + #define ETL_TIMER_UPDATES_ENABLED (process_semaphore.load() == 0) +#endif + +#if defined(ETL_MESSAGE_TIMER_USE_INTERRUPT_LOCK) + #if !defined(ETL_MESSAGE_TIMER_DISABLE_INTERRUPTS) || !defined(ETL_MESSAGE_TIMER_ENABLE_INTERRUPTS) + #error ETL_MESSAGE_TIMER_DISABLE_INTERRUPTS and/or ETL_MESSAGE_TIMER_ENABLE_INTERRUPTS not defined + #endif + + #define ETL_DISABLE_TIMER_UPDATES (ETL_MESSAGE_TIMER_DISABLE_INTERRUPTS) + #define ETL_ENABLE_TIMER_UPDATES (ETL_MESSAGE_TIMER_ENABLE_INTERRUPTS) + #define ETL_TIMER_UPDATES_ENABLED true +#endif + namespace etl { //************************************************************************* @@ -323,7 +347,7 @@ namespace etl { etl::timer::id::type id = etl::timer::id::NO_TIMER; - disable_timer_updates(); + ETL_DISABLE_TIMER_UPDATES; bool is_space = (registered_timers < MAX_TIMERS); @@ -349,7 +373,7 @@ namespace etl } } - enable_timer_updates(); + ETL_ENABLE_TIMER_UPDATES; return id; } @@ -363,7 +387,7 @@ namespace etl if (id_ != etl::timer::id::NO_TIMER) { - disable_timer_updates(); + ETL_DISABLE_TIMER_UPDATES; etl::message_timer_data& timer = timer_array[id_]; @@ -381,7 +405,7 @@ namespace etl } } - enable_timer_updates(); + ETL_ENABLE_TIMER_UPDATES; } return result; @@ -408,7 +432,7 @@ namespace etl //******************************************* void clear() { - disable_timer_updates(); + ETL_DISABLE_TIMER_UPDATES; active_list.clear(); @@ -419,7 +443,7 @@ namespace etl registered_timers = 0; - enable_timer_updates(); + ETL_ENABLE_TIMER_UPDATES; } //******************************************* @@ -432,7 +456,7 @@ namespace etl { if (enabled) { - if (process_semaphore.load() == 0) + if ETL_IF_CONSTEXPR(ETL_TIMER_UPDATES_ENABLED) { // We have something to do? bool has_active = !active_list.empty(); @@ -492,8 +516,6 @@ namespace etl { bool result = false; - disable_timer_updates(); - // Valid timer id? if (id_ != etl::timer::id::NO_TIMER) { @@ -505,6 +527,7 @@ namespace etl // Has a valid period. if (timer.period != etl::timer::state::INACTIVE) { + ETL_DISABLE_TIMER_UPDATES; if (timer.is_active()) { active_list.remove(timer.id, false); @@ -512,14 +535,13 @@ namespace etl timer.delta = immediate_ ? 0 : timer.period; active_list.insert(timer.id); + ETL_ENABLE_TIMER_UPDATES; result = true; } } } - enable_timer_updates(); - return result; } @@ -530,8 +552,6 @@ namespace etl { bool result = false; - disable_timer_updates(); - // Valid timer id? if (id_ != etl::timer::id::NO_TIMER) { @@ -542,14 +562,14 @@ namespace etl { if (timer.is_active()) { + ETL_DISABLE_TIMER_UPDATES; active_list.remove(timer.id, false); + ETL_ENABLE_TIMER_UPDATES; result = true; } } } - enable_timer_updates(); - return result; } @@ -590,7 +610,9 @@ namespace etl : timer_array(timer_array_), active_list(timer_array_), enabled(false), +#if defined(ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK) process_semaphore(0), +#endif registered_timers(0), MAX_TIMERS(MAX_TIMERS_) { @@ -605,22 +627,6 @@ namespace etl private: - //******************************************* - /// Enable timer callback events. - //******************************************* - void enable_timer_updates() - { - --process_semaphore; - } - - //******************************************* - /// Disable timer callback events. - //******************************************* - void disable_timer_updates() - { - ++process_semaphore; - } - // The array of timer data structures. message_timer_data* const timer_array; @@ -628,7 +634,10 @@ namespace etl __private_message_timer__::list active_list; volatile bool enabled; + +#if defined(ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK) volatile etl::timer_semaphore_t process_semaphore; +#endif volatile uint_least8_t registered_timers; public: @@ -660,6 +669,10 @@ namespace etl }; } +#undef ETL_DISABLE_TIMER_UPDATES +#undef ETL_ENABLE_TIMER_UPDATES +#undef ETL_TIMER_UPDATES_ENABLED + #undef ETL_FILE #endif diff --git a/support/Release notes.txt b/support/Release notes.txt index a02a8180..11310d97 100644 --- a/support/Release notes.txt +++ b/support/Release notes.txt @@ -1,3 +1,9 @@ +=============================================================================== +10.18.0 +Improvements to message and callback timer frameworks. +Reduced disable/enable time dur function calls. +Added the option to use either atomic semaphores or interrupt enables to control access. + =============================================================================== 10.17.0 Added emplace functions to etl::variant. diff --git a/test/codeblocks/ETL.layout b/test/codeblocks/ETL.layout index 7fb40ace..1306d367 100644 --- a/test/codeblocks/ETL.layout +++ b/test/codeblocks/ETL.layout @@ -1,585 +1,584 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/ecl_user.h b/test/ecl_user.h index 26eb1ab4..418bdee9 100644 --- a/test/ecl_user.h +++ b/test/ecl_user.h @@ -31,18 +31,18 @@ SOFTWARE. #include +extern uint32_t timer_semaphore; + #if defined(_MSC_VER) #include - #define ECL_TIMER_TIMER_SEMAPHORE uint32_t - #define ECL_TIMER_DISABLE_PROCESSING(x) InterlockedIncrement((volatile long*)&x) - #define ECL_TIMER_ENABLE_PROCESSING(x) InterlockedDecrement((volatile long*)&x) - #define ECL_TIMER_PROCESSING_ENABLED(x) (InterlockedAdd((volatile long*)&x, 0) == 0) + #define ECL_TIMER_DISABLE_PROCESSING InterlockedIncrement((volatile long*)&timer_semaphore) + #define ECL_TIMER_ENABLE_PROCESSING InterlockedDecrement((volatile long*)&timer_semaphore) + #define ECL_TIMER_PROCESSING_ENABLED (InterlockedAdd((volatile long*)&timer_semaphore, 0) == 0) #else - #define ECL_TIMER_TIMER_SEMAPHORE uint32_t - #define ECL_TIMER_DISABLE_PROCESSING(x) __sync_fetch_and_add(&x, 1) - #define ECL_TIMER_ENABLE_PROCESSING(x) __sync_fetch_and_sub(&x, 1) - #define ECL_TIMER_PROCESSING_ENABLED(x) (__sync_fetch_and_add(&x, 0) == 0) + #define ECL_TIMER_DISABLE_PROCESSING __sync_fetch_and_add(&timer_semaphore, 1) + #define ECL_TIMER_ENABLE_PROCESSING __sync_fetch_and_sub(&timer_semaphore, 1) + #define ECL_TIMER_PROCESSING_ENABLED (__sync_fetch_and_add(&timer_semaphore, 0) == 0) #endif #endif diff --git a/test/etl_profile.h b/test/etl_profile.h index ab9df17e..d2f02616 100644 --- a/test/etl_profile.h +++ b/test/etl_profile.h @@ -39,6 +39,9 @@ SOFTWARE. #define ETL_IDEQUE_REPAIR_ENABLE #define ETL_IN_UNIT_TEST +#define ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK +#define ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK + #define ETL_POLYMORPHIC_BITSET #define ETL_POLYMORPHIC_DEQUE #define ETL_POLYMORPHIC_FLAT_MAP diff --git a/test/test_c_timer_framework.cpp b/test/test_c_timer_framework.cpp index c96a712b..3868fcc3 100644 --- a/test/test_c_timer_framework.cpp +++ b/test/test_c_timer_framework.cpp @@ -33,6 +33,8 @@ SOFTWARE. extern "C" { + uint32_t timer_semaphore; + #include "ecl_timer.h" }