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