6
6
#include " interrupts.h"
7
7
#include " coredecls.h"
8
8
9
- typedef std::function<bool (void )> mFuncT ;
10
-
9
+ typedef std::function<void (void )> mSchedFuncT ;
11
10
struct scheduled_fn_t
12
11
{
13
12
scheduled_fn_t * mNext = nullptr ;
14
- mFuncT mFunc ;
15
- esp8266::polledTimeout::periodicFastUs callNow;
16
- schedule_e policy;
17
-
18
- scheduled_fn_t () : callNow(esp8266::polledTimeout::periodicFastUs::alwaysExpired) { }
13
+ mSchedFuncT mFunc ;
19
14
};
20
15
21
16
static scheduled_fn_t * sFirst = nullptr ;
22
17
static scheduled_fn_t * sLast = nullptr ;
23
18
static scheduled_fn_t * sUnused = nullptr ;
24
19
static int sCount = 0 ;
25
20
21
+ typedef std::function<bool (void )> mRecFuncT ;
22
+ struct recurrent_fn_t
23
+ {
24
+ recurrent_fn_t * mNext = nullptr ;
25
+ mRecFuncT mFunc ;
26
+ esp8266::polledTimeout::periodicFastUs callNow;
27
+ recurrent_fn_t (esp8266::polledTimeout::periodicFastUs interval): callNow(interval) { }
28
+ };
29
+
30
+ static recurrent_fn_t * rFirst = nullptr ; // fifo not needed
31
+
32
+ // Returns a pointer to an unused sched_fn_t,
33
+ // or if none are available allocates a new one,
34
+ // or nullptr if limit is reached
26
35
IRAM_ATTR // called from ISR
27
- static scheduled_fn_t * get_fn_unsafe ()
36
+ static scheduled_fn_t * get_fn_unsafe ()
28
37
{
29
38
scheduled_fn_t * result = nullptr ;
30
39
// try to get an item from unused items list
@@ -33,38 +42,33 @@ static scheduled_fn_t* get_fn_unsafe()
33
42
result = sUnused ;
34
43
sUnused = sUnused ->mNext ;
35
44
result->mNext = nullptr ;
36
- result->callNow .reset (esp8266::polledTimeout::periodicFastUs::alwaysExpired);
37
45
}
38
46
// if no unused items, and count not too high, allocate a new one
39
47
else if (sCount < SCHEDULED_FN_MAX_COUNT)
40
48
{
41
- result = new scheduled_fn_t ;
42
- ++sCount ;
49
+ result = (scheduled_fn_t *)malloc (sizeof (scheduled_fn_t ));
50
+ if (result)
51
+ ++sCount ;
43
52
}
44
53
return result;
45
54
}
46
55
47
- static void recycle_fn_unsafe (scheduled_fn_t * fn)
56
+ static void recycle_fn_unsafe (scheduled_fn_t * fn)
48
57
{
49
58
fn->mFunc = nullptr ; // special overload in c++ std lib
50
59
fn->mNext = sUnused ;
51
60
sUnused = fn;
52
61
}
53
62
54
63
IRAM_ATTR // (not only) called from ISR
55
- bool schedule_function_us ( std::function<bool (void )>&& fn, uint32_t repeat_us, schedule_e policy )
64
+ bool schedule_function ( const std::function<void (void )>& fn)
56
65
{
57
- assert (repeat_us < decltype (scheduled_fn_t ::callNow)::neverExpires); // ~26800000us (26.8s)
58
-
59
66
esp8266::InterruptLock lockAllInterruptsInThisScope;
60
67
61
68
scheduled_fn_t * item = get_fn_unsafe ();
62
69
if (!item)
63
70
return false ;
64
71
65
- if (repeat_us)
66
- item->callNow .reset (repeat_us);
67
- item->policy = policy;
68
72
item->mFunc = fn;
69
73
70
74
if (sFirst )
@@ -76,88 +80,110 @@ bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us, sc
76
80
return true ;
77
81
}
78
82
79
- IRAM_ATTR // (not only) called from ISR
80
- bool schedule_function_us (const std::function<bool (void )>& fn, uint32_t repeat_us, schedule_e policy)
83
+ bool schedule_recurrent_function_us (const std::function<bool (void )>& fn, uint32_t repeat_us)
81
84
{
82
- return schedule_function_us (std::function<bool (void )>(fn), repeat_us, policy);
83
- }
85
+ assert (repeat_us < decltype (recurrent_fn_t ::callNow)::neverExpires); // ~26800000us (26.8s)
84
86
85
- IRAM_ATTR // called from ISR
86
- bool schedule_function (std::function<void (void )>&& fn, schedule_e policy)
87
- {
88
- return schedule_function_us ([fn]() { fn (); return false ; }, 0 , policy);
87
+ esp8266::InterruptLock lockAllInterruptsInThisScope;
88
+
89
+ recurrent_fn_t * item = new recurrent_fn_t (repeat_us);
90
+ if (!item)
91
+ return false ;
92
+
93
+ item->mFunc = fn;
94
+
95
+ if (rFirst)
96
+ {
97
+ item->mNext = rFirst;
98
+ rFirst = item;
99
+ }
100
+ else
101
+ rFirst = item;
102
+
103
+ return true ;
89
104
}
90
105
91
- IRAM_ATTR // called from ISR
92
- bool schedule_function (const std::function<void (void )>& fn, schedule_e policy)
106
+ void run_scheduled_functions ()
93
107
{
94
- return schedule_function (std::function<void (void )>(fn), policy);
108
+ esp8266::polledTimeout::periodicFastMs yieldNow (100 ); // yield every 100ms
109
+
110
+ while (sFirst )
111
+ {
112
+ sFirst ->mFunc ();
113
+
114
+ {
115
+ esp8266::InterruptLock lockAllInterruptsInThisScope;
116
+
117
+ auto to_recycle = sFirst ;
118
+ sFirst = sFirst ->mNext ;
119
+ if (!sFirst )
120
+ sLast = nullptr ;
121
+ recycle_fn_unsafe (to_recycle);
122
+ }
123
+
124
+ if (yieldNow)
125
+ {
126
+ // because scheduled function are allowed to last:
127
+ // this is yield() in cont stack:
128
+ esp_schedule ();
129
+ cont_yield (g_pcont);
130
+ }
131
+ }
95
132
}
96
133
97
- void run_scheduled_functions (schedule_e policy )
134
+ void run_scheduled_recurrent_functions ( )
98
135
{
99
136
// Note to the reader:
100
137
// There is no exposed API to remove a scheduled function:
101
138
// Scheduled functions are removed only from this function, and
102
139
// its purpose is that it is never called from an interrupt
103
140
// (always on cont stack).
104
141
142
+ if (!rFirst)
143
+ return ;
144
+
105
145
static bool fence = false ;
106
146
{
107
- esp8266::InterruptLock lockAllInterruptsInThisScope;
147
+ // fence is like a mutex but as we are never called from ISR,
148
+ // locking is useless here. Leaving comment for reference.
149
+ // esp8266::InterruptLock lockAllInterruptsInThisScope;
150
+
108
151
if (fence)
109
152
// prevent recursive calls from yield()
153
+ // (even if they are not allowed)
110
154
return ;
111
155
fence = true ;
112
156
}
113
157
114
- esp8266::polledTimeout::periodicFastMs yieldNow ( 100 ); // yield every 100ms
115
- scheduled_fn_t * lastRecurring = nullptr ;
116
- scheduled_fn_t * nextCall = sFirst ;
117
- while (nextCall )
158
+ recurrent_fn_t * prev = nullptr ;
159
+ recurrent_fn_t * current = rFirst ;
160
+
161
+ while (current )
118
162
{
119
- scheduled_fn_t * toCall = nextCall;
120
- nextCall = nextCall->mNext ;
121
-
122
- // run scheduled function:
123
- // - when its schedule policy allows it anytime
124
- // - or if we are called at loop() time
125
- // and
126
- // - its time policy allows it
127
- if ( ( toCall->policy == SCHEDULED_FUNCTION_WITHOUT_YIELDELAYCALLS
128
- || policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP)
129
- && toCall->callNow )
163
+ if (current->callNow && !current->mFunc ())
130
164
{
131
- if (toCall->mFunc ())
165
+ // remove function from stack
166
+ esp8266::InterruptLock lockAllInterruptsInThisScope;
167
+
168
+ auto to_ditch = current;
169
+
170
+ if (prev)
132
171
{
133
- // function stays in list
134
- lastRecurring = toCall ;
172
+ current = current-> mNext ;
173
+ prev-> mNext = current ;
135
174
}
136
175
else
137
176
{
138
- // function removed from list
139
- esp8266::InterruptLock lockAllInterruptsInThisScope;
140
-
141
- if (sFirst == toCall)
142
- sFirst = sFirst ->mNext ;
143
- else if (lastRecurring)
144
- lastRecurring->mNext = toCall->mNext ;
145
-
146
- if (sLast == toCall)
147
- sLast = lastRecurring;
148
-
149
- recycle_fn_unsafe (toCall);
177
+ rFirst = rFirst->mNext ;
178
+ current = rFirst;
150
179
}
180
+
181
+ delete (to_ditch);
151
182
}
152
183
else
153
- // function stays in list
154
- lastRecurring = toCall;
155
-
156
- if (policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP && yieldNow)
157
184
{
158
- // this is yield() in cont stack:
159
- esp_schedule ();
160
- cont_yield (g_pcont);
185
+ prev = current;
186
+ current = current->mNext ;
161
187
}
162
188
}
163
189
0 commit comments