2121#include " Schedule.h"
2222#include " PolledTimeout.h"
2323#include " interrupts.h"
24+ #include < atomic>
2425
2526typedef std::function<void (void )> mSchedFuncT ;
2627struct scheduled_fn_t
@@ -47,7 +48,7 @@ struct recurrent_fn_t
4748static recurrent_fn_t * rFirst = nullptr ;
4849static recurrent_fn_t * rLast = nullptr ;
4950// The target time for scheduling the next timed recurrent function
50- static decltype (micros()) rTarget;
51+ static std::atomic< decltype (micros())> rTarget;
5152
5253// As 32 bit unsigned integer, micros() rolls over every 71.6 minutes.
5354// For unambiguous earlier/later order between two timestamps,
@@ -133,13 +134,17 @@ bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
133134
134135 esp8266::InterruptLock lockAllInterruptsInThisScope;
135136
136- // prevent new item overwriting an already expired rTarget.
137137 const auto now = micros ();
138138 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 (); ;)
141140 {
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 ;
143148 }
144149
145150 if (rLast)
@@ -158,9 +163,8 @@ bool schedule_recurrent_function_us(const std::function<bool(void)>& fn,
158163decltype (micros()) get_scheduled_recurrent_delay_us()
159164{
160165 if (!rFirst) return HALF_MAX_MICROS;
161- // handle already expired rTarget.
162166 const auto now = micros ();
163- const auto remaining = rTarget - now;
167+ const auto remaining = rTarget. load () - now;
164168 return (remaining <= HALF_MAX_MICROS) ? remaining : 0 ;
165169}
166170
@@ -233,9 +237,9 @@ void run_scheduled_recurrent_functions()
233237 recurrent_fn_t * prev = nullptr ;
234238 bool done;
235239
240+ rTarget.store (micros () + HALF_MAX_MICROS);
236241 // prevent scheduling of new functions during this run
237242 stop = rLast;
238- rTarget = micros () + HALF_MAX_MICROS;
239243
240244 do
241245 {
@@ -268,17 +272,20 @@ void run_scheduled_recurrent_functions()
268272 }
269273 else
270274 {
271- esp8266::InterruptLock lockAllInterruptsInThisScope;
272-
273- // prevent current item overwriting an already expired rTarget.
274275 const auto now = micros ();
275276 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 (); ;)
278278 {
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 ;
280288 }
281-
282289 prev = current;
283290 current = current->mNext ;
284291 }
0 commit comments