Skip to content

Commit 09f6b87

Browse files
authored
scheduled functions: fixes (#6137)
* scheduled functions: properly reset structure * fence against recursion, rename variables for clarity * update comments
1 parent 0a8f2a1 commit 09f6b87

File tree

2 files changed

+50
-25
lines changed

2 files changed

+50
-25
lines changed

cores/esp8266/Schedule.cpp

+23-11
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ static scheduled_fn_t* get_fn_unsafe()
3333
result = sUnused;
3434
sUnused = sUnused->mNext;
3535
result->mNext = nullptr;
36+
result->callNow.reset(esp8266::polledTimeout::periodicFastUs::alwaysExpired);
3637
}
3738
// if no unused items, and count not too high, allocate a new one
3839
else if (sCount < SCHEDULED_FN_MAX_COUNT)
@@ -100,32 +101,43 @@ void run_scheduled_functions()
100101
// its purpose is that it is never called from an interrupt
101102
// (always on cont stack).
102103

104+
static bool fence = false;
105+
{
106+
InterruptLock lockAllInterruptsInThisScope;
107+
if (fence)
108+
// prevent recursive calls from yield()
109+
return;
110+
fence = true;
111+
}
112+
103113
scheduled_fn_t* lastRecurring = nullptr;
104-
scheduled_fn_t* toCall = sFirst;
105-
while (toCall)
114+
scheduled_fn_t* nextCall = sFirst;
115+
while (nextCall)
106116
{
107-
scheduled_fn_t* item = toCall;
108-
toCall = toCall->mNext;
109-
if (item->callNow)
117+
scheduled_fn_t* toCall = nextCall;
118+
nextCall = nextCall->mNext;
119+
if (toCall->callNow)
110120
{
111-
if (item->mFunc())
121+
if (toCall->mFunc())
112122
{
113-
lastRecurring = item;
123+
lastRecurring = toCall;
114124
}
115125
else
116126
{
117127
InterruptLock lockAllInterruptsInThisScope;
118128

119-
if (sFirst == item)
129+
if (sFirst == toCall)
120130
sFirst = sFirst->mNext;
121131
else if (lastRecurring)
122-
lastRecurring->mNext = item->mNext;
132+
lastRecurring->mNext = toCall->mNext;
123133

124-
if (sLast == item)
134+
if (sLast == toCall)
125135
sLast = lastRecurring;
126136

127-
recycle_fn_unsafe(item);
137+
recycle_fn_unsafe(toCall);
128138
}
129139
}
130140
}
141+
142+
fence = false;
131143
}

cores/esp8266/Schedule.h

+27-14
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,38 @@
33

44
#include <functional>
55

6-
#define SCHEDULED_FN_MAX_COUNT 32
6+
// This API is stabilizing
7+
// Function signatures may change, internal queue will remain FIFO.
8+
//
9+
// * Add the given lambda to a fifo list of lambdas, which is run when
10+
// - `loop` function returns,
11+
// - or `yield` is called,
12+
// - or `run_scheduled_functions` is called.
13+
//
14+
// * Use lambdas to pass arguments to a function, or call a class/static
15+
// member function.
16+
//
17+
// * Please ensure variables or instances used from inside lambda will exist
18+
// when lambda is later called
19+
//
20+
// * There is no mechanism for cancelling scheduled functions.
21+
//
22+
// * `yield` can be called from inside lambdas
23+
//
24+
// * Returns false if the number of scheduled functions exceeds
25+
// SCHEDULED_FN_MAX_COUNT.
726

8-
// This API was not considered stable but is now stabilizing.
9-
// Function signatures may change, queue must stay FIFO.
10-
// You have been warned.
27+
#define SCHEDULED_FN_MAX_COUNT 32
1128

12-
// Run given function ONCE next time `loop` function returns,
13-
// or `yield` is called,
14-
// or `run_scheduled_functions` is called.
15-
// Use std::bind to pass arguments to a function, or call a class member function.
16-
// Note: there is no mechanism for cancelling scheduled functions.
17-
// Keep that in mind when binding functions to objects which may have short lifetime.
18-
// Returns false if the number of scheduled functions exceeds SCHEDULED_FN_MAX_COUNT.
29+
// * Run the lambda only once next time
1930
//bool schedule_function(std::function<void(void)>&& fn);
2031
bool schedule_function(const std::function<void(void)>& fn);
2132

22-
// Run given function periodically about every <repeat_us> microseconds until it returns false.
23-
// Note that it may be more than <repeat_us> microseconds between calls if `yield` is not called
24-
// frequently, and therefore should not be used for timing critical operations.
33+
// * Run the lambda periodically about every <repeat_us> microseconds until
34+
// it returns false.
35+
// * Note that it may be more than <repeat_us> microseconds between calls if
36+
// `yield` is not called frequently, and therefore should not be used for
37+
// timing critical operations.
2538
//bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us);
2639
bool schedule_function_us(const std::function<bool(void)>& fn, uint32_t repeat_us);
2740

0 commit comments

Comments
 (0)