1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-06 05:21:22 +03:00

scheduled functions: calls from yield are now optional (#6158)

* scheduled functions: calls from yield are now optional
* add move constructors
* yield every 100ms
This commit is contained in:
david gauchard 2019-05-29 11:10:30 +02:00 committed by GitHub
parent dddc8d2495
commit 455583b40f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 20 deletions

View File

@ -4,6 +4,7 @@
#include "Schedule.h"
#include "PolledTimeout.h"
#include "interrupts.h"
#include "coredecls.h"
typedef std::function<bool(void)> mFuncT;
@ -12,15 +13,14 @@ 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) { }
};
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
@ -52,7 +52,7 @@ static void recycle_fn_unsafe(scheduled_fn_t* fn)
}
IRAM_ATTR // (not only) called from ISR
bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us)
bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us, schedule_e policy)
{
assert(repeat_us < decltype(scheduled_fn_t::callNow)::neverExpires); //~26800000us (26.8s)
@ -64,8 +64,9 @@ bool schedule_function_us(std::function<bool(void)>&& 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 +77,24 @@ bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us)
}
IRAM_ATTR // (not only) called from ISR
bool schedule_function_us(const std::function<bool(void)>& fn, uint32_t repeat_us)
bool schedule_function_us(const std::function<bool(void)>& fn, uint32_t repeat_us, schedule_e policy)
{
return schedule_function_us(std::function<bool(void)>(fn), repeat_us);
return schedule_function_us(std::function<bool(void)>(fn), repeat_us, policy);
}
IRAM_ATTR // called from ISR
bool schedule_function(std::function<void(void)>&& fn)
bool schedule_function(std::function<void(void)>&& 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<void(void)>& fn)
bool schedule_function(const std::function<void(void)>& fn, schedule_e policy)
{
return schedule_function(std::function<void(void)>(fn));
return schedule_function(std::function<void(void)>(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:
@ -110,13 +111,22 @@ void run_scheduled_functions()
fence = true;
}
esp8266::polledTimeout::periodicFastMs yieldNow(100); // yield every 100ms
scheduled_fn_t* lastRecurring = nullptr;
scheduled_fn_t* nextCall = sFirst;
while (nextCall)
{
scheduled_fn_t* toCall = nextCall;
nextCall = nextCall->mNext;
if (toCall->callNow)
// 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())
{
@ -142,6 +152,13 @@ void run_scheduled_functions()
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;

View File

@ -26,21 +26,33 @@
#define SCHEDULED_FN_MAX_COUNT 32
enum schedule_e
{
SCHEDULED_FUNCTION_ONCE_PER_LOOP,
SCHEDULED_FUNCTION_WITHOUT_YIELDELAYCALLS
};
// * Run the lambda only once next time
//bool schedule_function(std::function<void(void)>&& fn);
bool schedule_function(const std::function<void(void)>& fn);
bool schedule_function(std::function<void(void)>&& fn,
schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP);
bool schedule_function(const std::function<void(void)>& fn,
schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP);
// * Run the lambda periodically about every <repeat_us> microseconds until
// it returns false.
// * Note that it may be more than <repeat_us> 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<bool(void)>&& fn, uint32_t repeat_us);
bool schedule_function_us(const std::function<bool(void)>& fn, uint32_t repeat_us);
bool schedule_function_us(std::function<bool(void)>&& fn,
uint32_t repeat_us,
schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP);
bool schedule_function_us(const std::function<bool(void)>& 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
// on a regular basis.
void run_scheduled_functions();
void run_scheduled_functions(schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP);
#endif //ESP_SCHEDULE_H

View File

@ -84,22 +84,27 @@ 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);
esp_yield_within_cont();
}
}
extern "C" void esp_schedule() {
// always on CONT stack here
run_scheduled_functions();
ets_post(LOOP_TASK_PRIORITY, 0, 0);
}
extern "C" void __yield() {
if (cont_can_yield(g_pcont)) {
esp_schedule();
cont_yield(g_pcont); //esp_yield();
esp_yield_within_cont();
}
else {
panic();
@ -124,6 +129,7 @@ static void loop_wrapper() {
setup_done = true;
}
loop();
run_scheduled_functions(SCHEDULED_FUNCTION_ONCE_PER_LOOP);
esp_schedule();
}