From 3e192acb0a5c9cb9f5d7bf16d0d2854a9f8826f6 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 28 May 2019 09:52:41 +0200 Subject: [PATCH 1/5] scheduled functioin: calls from yield are now optional --- cores/esp8266/Schedule.cpp | 24 ++++++++++++++---------- cores/esp8266/Schedule.h | 11 ++++++++--- cores/esp8266/core_esp8266_main.cpp | 4 +++- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 4e6a0780e0..6bafeb1f1b 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -12,6 +12,7 @@ struct scheduled_fn_t scheduled_fn_t* mNext = nullptr; mFuncT mFunc; esp8266::polledTimeout::periodicFastUs callNow; + schedule_e policy; scheduled_fn_t() : callNow(esp8266::polledTimeout::periodicFastUs::alwaysExpired) { } }; @@ -52,7 +53,7 @@ static void recycle_fn_unsafe(scheduled_fn_t* fn) } IRAM_ATTR // (not only) called from ISR -bool schedule_function_us(std::function&& fn, uint32_t repeat_us) +bool schedule_function_us(std::function&& fn, uint32_t repeat_us, schedule_e policy) { assert(repeat_us < decltype(scheduled_fn_t::callNow)::neverExpires); //~26800000us (26.8s) @@ -64,8 +65,9 @@ bool schedule_function_us(std::function&& fn, uint32_t repeat_us) if (repeat_us) item->callNow.reset(repeat_us); - + item->policy = policy; item->mFunc = fn; + if (sFirst) sLast->mNext = item; else @@ -76,24 +78,24 @@ bool schedule_function_us(std::function&& fn, uint32_t repeat_us) } IRAM_ATTR // (not only) called from ISR -bool schedule_function_us(const std::function& fn, uint32_t repeat_us) +bool schedule_function_us(const std::function& fn, uint32_t repeat_us, schedule_e policy) { - return schedule_function_us(std::function(fn), repeat_us); + return schedule_function_us(std::function(fn), repeat_us, policy); } IRAM_ATTR // called from ISR -bool schedule_function(std::function&& fn) +bool schedule_function(std::function&& fn, schedule_e policy) { - return schedule_function_us([fn]() { fn(); return false; }, 0); + return schedule_function_us([fn]() { fn(); return false; }, 0, policy); } IRAM_ATTR // called from ISR -bool schedule_function(const std::function& fn) +bool schedule_function(const std::function& fn, schedule_e policy) { - return schedule_function(std::function(fn)); + return schedule_function(std::function(fn), policy); } -void run_scheduled_functions() +void run_scheduled_functions(schedule_e policy) { // Note to the reader: // There is no exposed API to remove a scheduled function: @@ -116,10 +118,12 @@ void run_scheduled_functions() { scheduled_fn_t* toCall = nextCall; nextCall = nextCall->mNext; - if (toCall->callNow) + if ((toCall->policy == SCHEDULE_OFTEN_NO_YIELDELAYCALL || policy == SCHEDULE_CAN_USE_DELAY) + && toCall->callNow) { if (toCall->mFunc()) { +Serial.printf("(%d/%d)",policy, toCall->policy); // function stays in list lastRecurring = toCall; } diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index 089205edc8..00ffd810ac 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -26,9 +26,12 @@ #define SCHEDULED_FN_MAX_COUNT 32 +enum schedule_e { SCHEDULE_CAN_USE_DELAY, SCHEDULE_OFTEN_NO_YIELDELAYCALL }; + // * Run the lambda only once next time //bool schedule_function(std::function&& fn); -bool schedule_function(const std::function& fn); +bool schedule_function(const std::function& fn, + schedule_e policy = SCHEDULE_CAN_USE_DELAY); // * Run the lambda periodically about every microseconds until // it returns false. @@ -36,11 +39,13 @@ bool schedule_function(const std::function& fn); // `yield` is not called frequently, and therefore should not be used for // timing critical operations. //bool schedule_function_us(std::function&& fn, uint32_t repeat_us); -bool schedule_function_us(const std::function& fn, uint32_t repeat_us); +bool schedule_function_us(const std::function& fn, + uint32_t repeat_us, + schedule_e policy = SCHEDULE_CAN_USE_DELAY); // Run all scheduled functions. // Use this function if your are not using `loop`, or `loop` does not return // on a regular basis. -void run_scheduled_functions(); +void run_scheduled_functions(schedule_e policy = SCHEDULE_CAN_USE_DELAY); #endif //ESP_SCHEDULE_H diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 7ab1e56bf7..9e0b5925e2 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -87,12 +87,12 @@ void preloop_update_frequency() { extern "C" void esp_yield() { if (cont_can_yield(g_pcont)) { cont_yield(g_pcont); + run_scheduled_functions(SCHEDULE_OFTEN_NO_YIELDELAYCALL); } } extern "C" void esp_schedule() { // always on CONT stack here - run_scheduled_functions(); ets_post(LOOP_TASK_PRIORITY, 0, 0); } @@ -100,6 +100,7 @@ extern "C" void __yield() { if (cont_can_yield(g_pcont)) { esp_schedule(); cont_yield(g_pcont); //esp_yield(); + run_scheduled_functions(SCHEDULE_OFTEN_NO_YIELDELAYCALL); } else { panic(); @@ -124,6 +125,7 @@ static void loop_wrapper() { setup_done = true; } loop(); + run_scheduled_functions(SCHEDULE_CAN_USE_DELAY); esp_schedule(); } From 66e6c32123af565bfb71fa5c650dfadbb010c637 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 28 May 2019 10:50:30 +0200 Subject: [PATCH 2/5] comments, prints removed, enum renamed --- cores/esp8266/Schedule.cpp | 12 ++++++++---- cores/esp8266/Schedule.h | 19 +++++++++++++------ cores/esp8266/core_esp8266_main.cpp | 14 +++++++++----- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 6bafeb1f1b..c586f431a3 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -19,9 +19,7 @@ struct scheduled_fn_t static scheduled_fn_t* sFirst = nullptr; static scheduled_fn_t* sLast = nullptr; - static scheduled_fn_t* sUnused = nullptr; - static int sCount = 0; IRAM_ATTR // called from ISR @@ -118,12 +116,18 @@ void run_scheduled_functions(schedule_e policy) { scheduled_fn_t* toCall = nextCall; nextCall = nextCall->mNext; - if ((toCall->policy == SCHEDULE_OFTEN_NO_YIELDELAYCALL || policy == SCHEDULE_CAN_USE_DELAY) + + // run scheduled function: + // - when its schedule policy allows it anytime + // - or if we are called at loop() time + // and + // - its time policy allows it + if ( ( toCall->policy == SCHEDULED_FUNCTION_WITHOUT_YIELDELAYCALLS + || policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP) && toCall->callNow) { if (toCall->mFunc()) { -Serial.printf("(%d/%d)",policy, toCall->policy); // function stays in list lastRecurring = toCall; } diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index 00ffd810ac..c4877d3d77 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -26,26 +26,33 @@ #define SCHEDULED_FN_MAX_COUNT 32 -enum schedule_e { SCHEDULE_CAN_USE_DELAY, SCHEDULE_OFTEN_NO_YIELDELAYCALL }; +enum schedule_e +{ + SCHEDULED_FUNCTION_ONCE_PER_LOOP, + SCHEDULED_FUNCTION_WITHOUT_YIELDELAYCALLS +}; // * Run the lambda only once next time -//bool schedule_function(std::function&& fn); +//bool schedule_function(const std::function&& fn, +// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); bool schedule_function(const std::function& fn, - schedule_e policy = SCHEDULE_CAN_USE_DELAY); + schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); // * Run the lambda periodically about every microseconds until // it returns false. // * Note that it may be more than microseconds between calls if // `yield` is not called frequently, and therefore should not be used for // timing critical operations. -//bool schedule_function_us(std::function&& fn, uint32_t repeat_us); +//bool schedule_function_us(const std::function&& fn, +// uint32_t repeat_us, +// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); bool schedule_function_us(const std::function& fn, uint32_t repeat_us, - schedule_e policy = SCHEDULE_CAN_USE_DELAY); + schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); // Run all scheduled functions. // Use this function if your are not using `loop`, or `loop` does not return // on a regular basis. -void run_scheduled_functions(schedule_e policy = SCHEDULE_CAN_USE_DELAY); +void run_scheduled_functions(schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); #endif //ESP_SCHEDULE_H diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 9e0b5925e2..795507686a 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -84,10 +84,15 @@ void preloop_update_frequency() { } +static inline void esp_yield_within_cont() __attribute__((always_inline)); +static void esp_yield_within_cont() { + cont_yield(g_pcont); + run_scheduled_functions(SCHEDULED_FUNCTION_WITHOUT_YIELDELAYCALLS); +} + extern "C" void esp_yield() { if (cont_can_yield(g_pcont)) { - cont_yield(g_pcont); - run_scheduled_functions(SCHEDULE_OFTEN_NO_YIELDELAYCALL); + esp_yield_within_cont(); } } @@ -99,8 +104,7 @@ extern "C" void esp_schedule() { extern "C" void __yield() { if (cont_can_yield(g_pcont)) { esp_schedule(); - cont_yield(g_pcont); //esp_yield(); - run_scheduled_functions(SCHEDULE_OFTEN_NO_YIELDELAYCALL); + esp_yield_within_cont(); } else { panic(); @@ -125,7 +129,7 @@ static void loop_wrapper() { setup_done = true; } loop(); - run_scheduled_functions(SCHEDULE_CAN_USE_DELAY); + run_scheduled_functions(SCHEDULED_FUNCTION_ONCE_PER_LOOP); esp_schedule(); } From e67fa53c60e9c85601544ae786feaced61c1701c Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 28 May 2019 12:49:52 +0200 Subject: [PATCH 3/5] use move constructors (remove const ref signatures) --- cores/esp8266/Schedule.cpp | 20 ++++++++++---------- cores/esp8266/Schedule.h | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index c586f431a3..39c57df1bd 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -75,11 +75,11 @@ bool schedule_function_us(std::function&& fn, uint32_t repeat_us, sc return true; } -IRAM_ATTR // (not only) called from ISR -bool schedule_function_us(const std::function& fn, uint32_t repeat_us, schedule_e policy) -{ - return schedule_function_us(std::function(fn), repeat_us, policy); -} +//IRAM_ATTR // (not only) called from ISR +//bool schedule_function_us(const std::function& fn, uint32_t repeat_us, schedule_e policy) +//{ +// return schedule_function_us(std::function(fn), repeat_us, policy); +//} IRAM_ATTR // called from ISR bool schedule_function(std::function&& fn, schedule_e policy) @@ -87,11 +87,11 @@ bool schedule_function(std::function&& fn, schedule_e policy) return schedule_function_us([fn]() { fn(); return false; }, 0, policy); } -IRAM_ATTR // called from ISR -bool schedule_function(const std::function& fn, schedule_e policy) -{ - return schedule_function(std::function(fn), policy); -} +//IRAM_ATTR // called from ISR +//bool schedule_function(const std::function& fn, schedule_e policy) +//{ +// return schedule_function(std::function(fn), policy); +//} void run_scheduled_functions(schedule_e policy) { diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index c4877d3d77..3d2841dcc0 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -33,22 +33,22 @@ enum schedule_e }; // * Run the lambda only once next time -//bool schedule_function(const std::function&& fn, -// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); -bool schedule_function(const std::function& fn, +bool schedule_function(std::function&& fn, schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); +//bool schedule_function(const std::function& fn, +// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); // * Run the lambda periodically about every microseconds until // it returns false. // * Note that it may be more than microseconds between calls if // `yield` is not called frequently, and therefore should not be used for // timing critical operations. -//bool schedule_function_us(const std::function&& fn, -// uint32_t repeat_us, -// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); -bool schedule_function_us(const std::function& fn, +bool schedule_function_us(std::function&& fn, uint32_t repeat_us, schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); +//bool schedule_function_us(const std::function& fn, +// uint32_t repeat_us, +// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); // Run all scheduled functions. // Use this function if your are not using `loop`, or `loop` does not return From 5e9aa61702991334a8c19a287fbe6ed120810eaa Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Tue, 28 May 2019 15:00:27 +0200 Subject: [PATCH 4/5] restore constref api (Ticker needs update, not all at once) --- cores/esp8266/Schedule.cpp | 20 ++++++++++---------- cores/esp8266/Schedule.h | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 39c57df1bd..c586f431a3 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -75,11 +75,11 @@ bool schedule_function_us(std::function&& fn, uint32_t repeat_us, sc return true; } -//IRAM_ATTR // (not only) called from ISR -//bool schedule_function_us(const std::function& fn, uint32_t repeat_us, schedule_e policy) -//{ -// return schedule_function_us(std::function(fn), repeat_us, policy); -//} +IRAM_ATTR // (not only) called from ISR +bool schedule_function_us(const std::function& fn, uint32_t repeat_us, schedule_e policy) +{ + return schedule_function_us(std::function(fn), repeat_us, policy); +} IRAM_ATTR // called from ISR bool schedule_function(std::function&& fn, schedule_e policy) @@ -87,11 +87,11 @@ bool schedule_function(std::function&& fn, schedule_e policy) return schedule_function_us([fn]() { fn(); return false; }, 0, policy); } -//IRAM_ATTR // called from ISR -//bool schedule_function(const std::function& fn, schedule_e policy) -//{ -// return schedule_function(std::function(fn), policy); -//} +IRAM_ATTR // called from ISR +bool schedule_function(const std::function& fn, schedule_e policy) +{ + return schedule_function(std::function(fn), policy); +} void run_scheduled_functions(schedule_e policy) { diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index 3d2841dcc0..6c5fca7ea5 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -35,8 +35,8 @@ enum schedule_e // * Run the lambda only once next time bool schedule_function(std::function&& fn, schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); -//bool schedule_function(const std::function& fn, -// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); +bool schedule_function(const std::function& fn, + schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); // * Run the lambda periodically about every microseconds until // it returns false. @@ -46,9 +46,9 @@ bool schedule_function(std::function&& fn, bool schedule_function_us(std::function&& fn, uint32_t repeat_us, schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); -//bool schedule_function_us(const std::function& fn, -// uint32_t repeat_us, -// schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); +bool schedule_function_us(const std::function& fn, + uint32_t repeat_us, + schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP); // Run all scheduled functions. // Use this function if your are not using `loop`, or `loop` does not return From a45353eed3b4464611b9e9a6c1189dd84af21228 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Wed, 29 May 2019 00:39:40 +0200 Subject: [PATCH 5/5] scheduled functions: yield every 100ms --- cores/esp8266/Schedule.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index c586f431a3..495caafd27 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -4,6 +4,7 @@ #include "Schedule.h" #include "PolledTimeout.h" #include "interrupts.h" +#include "coredecls.h" typedef std::function mFuncT; @@ -110,6 +111,7 @@ void run_scheduled_functions(schedule_e policy) fence = true; } + esp8266::polledTimeout::periodicFastMs yieldNow(100); // yield every 100ms scheduled_fn_t* lastRecurring = nullptr; scheduled_fn_t* nextCall = sFirst; while (nextCall) @@ -150,6 +152,13 @@ void run_scheduled_functions(schedule_e policy) else // function stays in list lastRecurring = toCall; + + if (policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP && yieldNow) + { + // this is yield() in cont stack: + esp_schedule(); + cont_yield(g_pcont); + } } fence = false;