Skip to content

Commit 75119f4

Browse files
committed
Use CAS to minimize critical sections.
1 parent c6bc7b8 commit 75119f4

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

cores/esp8266/Schedule.cpp

+22-15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "Schedule.h"
2222
#include "PolledTimeout.h"
2323
#include "interrupts.h"
24+
#include <atomic>
2425

2526
typedef std::function<void(void)> mSchedFuncT;
2627
struct scheduled_fn_t
@@ -47,7 +48,7 @@ struct recurrent_fn_t
4748
static recurrent_fn_t* rFirst = nullptr;
4849
static 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,
158163
decltype(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

Comments
 (0)