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:
parent
dddc8d2495
commit
455583b40f
@ -4,6 +4,7 @@
|
|||||||
#include "Schedule.h"
|
#include "Schedule.h"
|
||||||
#include "PolledTimeout.h"
|
#include "PolledTimeout.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
|
#include "coredecls.h"
|
||||||
|
|
||||||
typedef std::function<bool(void)> mFuncT;
|
typedef std::function<bool(void)> mFuncT;
|
||||||
|
|
||||||
@ -12,15 +13,14 @@ struct scheduled_fn_t
|
|||||||
scheduled_fn_t* mNext = nullptr;
|
scheduled_fn_t* mNext = nullptr;
|
||||||
mFuncT mFunc;
|
mFuncT mFunc;
|
||||||
esp8266::polledTimeout::periodicFastUs callNow;
|
esp8266::polledTimeout::periodicFastUs callNow;
|
||||||
|
schedule_e policy;
|
||||||
|
|
||||||
scheduled_fn_t() : callNow(esp8266::polledTimeout::periodicFastUs::alwaysExpired) { }
|
scheduled_fn_t() : callNow(esp8266::polledTimeout::periodicFastUs::alwaysExpired) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
static scheduled_fn_t* sFirst = nullptr;
|
static scheduled_fn_t* sFirst = nullptr;
|
||||||
static scheduled_fn_t* sLast = nullptr;
|
static scheduled_fn_t* sLast = nullptr;
|
||||||
|
|
||||||
static scheduled_fn_t* sUnused = nullptr;
|
static scheduled_fn_t* sUnused = nullptr;
|
||||||
|
|
||||||
static int sCount = 0;
|
static int sCount = 0;
|
||||||
|
|
||||||
IRAM_ATTR // called from ISR
|
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
|
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)
|
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)
|
if (repeat_us)
|
||||||
item->callNow.reset(repeat_us);
|
item->callNow.reset(repeat_us);
|
||||||
|
item->policy = policy;
|
||||||
item->mFunc = fn;
|
item->mFunc = fn;
|
||||||
|
|
||||||
if (sFirst)
|
if (sFirst)
|
||||||
sLast->mNext = item;
|
sLast->mNext = item;
|
||||||
else
|
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
|
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
|
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
|
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:
|
// Note to the reader:
|
||||||
// There is no exposed API to remove a scheduled function:
|
// There is no exposed API to remove a scheduled function:
|
||||||
@ -110,13 +111,22 @@ void run_scheduled_functions()
|
|||||||
fence = true;
|
fence = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp8266::polledTimeout::periodicFastMs yieldNow(100); // yield every 100ms
|
||||||
scheduled_fn_t* lastRecurring = nullptr;
|
scheduled_fn_t* lastRecurring = nullptr;
|
||||||
scheduled_fn_t* nextCall = sFirst;
|
scheduled_fn_t* nextCall = sFirst;
|
||||||
while (nextCall)
|
while (nextCall)
|
||||||
{
|
{
|
||||||
scheduled_fn_t* toCall = nextCall;
|
scheduled_fn_t* toCall = nextCall;
|
||||||
nextCall = nextCall->mNext;
|
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())
|
if (toCall->mFunc())
|
||||||
{
|
{
|
||||||
@ -142,6 +152,13 @@ void run_scheduled_functions()
|
|||||||
else
|
else
|
||||||
// function stays in list
|
// function stays in list
|
||||||
lastRecurring = toCall;
|
lastRecurring = toCall;
|
||||||
|
|
||||||
|
if (policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP && yieldNow)
|
||||||
|
{
|
||||||
|
// this is yield() in cont stack:
|
||||||
|
esp_schedule();
|
||||||
|
cont_yield(g_pcont);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fence = false;
|
fence = false;
|
||||||
|
@ -26,21 +26,33 @@
|
|||||||
|
|
||||||
#define SCHEDULED_FN_MAX_COUNT 32
|
#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
|
// * Run the lambda only once next time
|
||||||
//bool schedule_function(std::function<void(void)>&& fn);
|
bool schedule_function(std::function<void(void)>&& fn,
|
||||||
bool schedule_function(const 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
|
// * Run the lambda periodically about every <repeat_us> microseconds until
|
||||||
// it returns false.
|
// it returns false.
|
||||||
// * Note that it may be more than <repeat_us> microseconds between calls if
|
// * 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
|
// `yield` is not called frequently, and therefore should not be used for
|
||||||
// timing critical operations.
|
// timing critical operations.
|
||||||
//bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us);
|
bool schedule_function_us(std::function<bool(void)>&& fn,
|
||||||
bool schedule_function_us(const std::function<bool(void)>& fn, uint32_t repeat_us);
|
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.
|
// Run all scheduled functions.
|
||||||
// Use this function if your are not using `loop`, or `loop` does not return
|
// Use this function if your are not using `loop`, or `loop` does not return
|
||||||
// on a regular basis.
|
// on a regular basis.
|
||||||
void run_scheduled_functions();
|
void run_scheduled_functions(schedule_e policy = SCHEDULED_FUNCTION_ONCE_PER_LOOP);
|
||||||
|
|
||||||
#endif //ESP_SCHEDULE_H
|
#endif //ESP_SCHEDULE_H
|
||||||
|
@ -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() {
|
extern "C" void esp_yield() {
|
||||||
if (cont_can_yield(g_pcont)) {
|
if (cont_can_yield(g_pcont)) {
|
||||||
cont_yield(g_pcont);
|
esp_yield_within_cont();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void esp_schedule() {
|
extern "C" void esp_schedule() {
|
||||||
// always on CONT stack here
|
// always on CONT stack here
|
||||||
run_scheduled_functions();
|
|
||||||
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void __yield() {
|
extern "C" void __yield() {
|
||||||
if (cont_can_yield(g_pcont)) {
|
if (cont_can_yield(g_pcont)) {
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
cont_yield(g_pcont); //esp_yield();
|
esp_yield_within_cont();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
panic();
|
panic();
|
||||||
@ -124,6 +129,7 @@ static void loop_wrapper() {
|
|||||||
setup_done = true;
|
setup_done = true;
|
||||||
}
|
}
|
||||||
loop();
|
loop();
|
||||||
|
run_scheduled_functions(SCHEDULED_FUNCTION_ONCE_PER_LOOP);
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user