21
21
#include " Schedule.h"
22
22
#include " PolledTimeout.h"
23
23
#include " interrupts.h"
24
+ #include < atomic>
24
25
25
26
typedef std::function<void (void )> mSchedFuncT ;
26
27
struct scheduled_fn_t
@@ -47,7 +48,7 @@ struct recurrent_fn_t
47
48
static recurrent_fn_t * rFirst = nullptr ;
48
49
static recurrent_fn_t * rLast = nullptr ;
49
50
// The target time for scheduling the next timed recurrent function
50
- static decltype (micros()) rTarget;
51
+ static std::atomic< decltype(micros())> rTarget;
51
52
52
53
// As 32 bit unsigned integer, micros() rolls over every 71.6 minutes.
53
54
// For unambiguous earlier/later order between two timestamps,
@@ -133,13 +134,17 @@ bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
133
134
134
135
esp8266::InterruptLock lockAllInterruptsInThisScope;
135
136
136
- // prevent new item overwriting an already expired rTarget.
137
137
const auto now = micros ();
138
138
const auto itemRemaining = item->callNow .remaining ();
139
- const auto remaining = rTarget - now;
140
- if (!rFirst || (remaining <= HALF_MAX_MICROS && remaining > itemRemaining))
139
+ for (auto _rTarget = rTarget.load (); ;)
141
140
{
142
- rTarget = now + itemRemaining;
141
+ const auto remaining = _rTarget - now;
142
+ if (!rFirst || (remaining <= HALF_MAX_MICROS && remaining > itemRemaining))
143
+ {
144
+ // if (!rTarget.compare_exchange_weak(_rTarget, now + itemRemaining)) continue;
145
+ rTarget = now + itemRemaining; // interrupt lock is active, no ABA issue
146
+ }
147
+ break ;
143
148
}
144
149
145
150
if (rLast)
@@ -158,9 +163,8 @@ bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
158
163
decltype (micros()) get_scheduled_recurrent_delay_us()
159
164
{
160
165
if (!rFirst) return HALF_MAX_MICROS;
161
- // handle already expired rTarget.
162
166
const auto now = micros ();
163
- const auto remaining = rTarget - now;
167
+ const auto remaining = rTarget. load () - now;
164
168
return (remaining <= HALF_MAX_MICROS) ? remaining : 0 ;
165
169
}
166
170
@@ -233,9 +237,9 @@ void run_scheduled_recurrent_functions()
233
237
recurrent_fn_t * prev = nullptr ;
234
238
bool done;
235
239
240
+ rTarget.store (micros () + HALF_MAX_MICROS);
236
241
// prevent scheduling of new functions during this run
237
242
stop = rLast;
238
- rTarget = micros () + HALF_MAX_MICROS;
239
243
240
244
do
241
245
{
@@ -268,17 +272,20 @@ void run_scheduled_recurrent_functions()
268
272
}
269
273
else
270
274
{
271
- esp8266::InterruptLock lockAllInterruptsInThisScope;
272
-
273
- // prevent current item overwriting an already expired rTarget.
274
275
const auto now = micros ();
275
276
const auto currentRemaining = current->callNow .remaining ();
276
- const auto remaining = rTarget - now;
277
- if (remaining <= HALF_MAX_MICROS && remaining > currentRemaining)
277
+ for (auto _rTarget = rTarget.load (); ;)
278
278
{
279
- rTarget = now + currentRemaining;
279
+ const auto remaining = _rTarget - now;
280
+ if (remaining <= HALF_MAX_MICROS && remaining > currentRemaining)
281
+ {
282
+ // if (!rTarget.compare_exchange_weak(_rTarget, now + currentRemaining)) continue;
283
+ esp8266::InterruptLock lockAllInterruptsInThisScope;
284
+ if (rTarget != _rTarget) { _rTarget = rTarget; continue ; }
285
+ rTarget = now + currentRemaining;
286
+ }
287
+ break ;
280
288
}
281
-
282
289
prev = current;
283
290
current = current->mNext ;
284
291
}
0 commit comments