This commit is contained in:
J. Nick Koston
2026-04-14 20:42:25 -10:00
parent a8cb5b44cd
commit 3912ede2cf
+26 -10
View File
@@ -34,9 +34,10 @@ void HOT yield() { ::yield(); }
// that Arduino library code and ISR handlers (e.g. Wiegand, ZyAura) calling
// ::millis() directly also get the fast version. Interrupts are briefly disabled
// to protect the static state from concurrent ISR access. The critical section
// is bounded: the common path (delta < 10 ms) runs at most 10 subtract-and-
// compare iterations (~100 ns). Large gaps (WiFi scan, boot) fall back to a
// constant-time multiply-by-reciprocal (~2.5 μs, rare).
// is bounded on *both* paths: the common path (delta < 10 ms) runs at most 10
// subtract-and-compare iterations (~100 ns). The rare path drops out of the
// critical section before doing the expensive /1000, so unrelated peripherals
// and the WiFi MAC are not blocked while the divide runs.
// Threshold above which we use constant-time /1000 instead of the while loop.
// 10 ms means the while loop runs at most 10 iterations (~100 ns) on the
// common path, well within the WiFi stack's ~10 μs interrupt latency budget.
@@ -56,20 +57,35 @@ uint32_t IRAM_ATTR HOT millis() {
uint32_t delta = now_us - state.last_us;
state.last_us = now_us;
state.remainder += delta;
if (state.remainder >= MILLIS_RARE_PATH_THRESHOLD_US) {
// Rare path: large gap (WiFi scan, boot, long block). Constant-time
// conversion keeps the critical section bounded.
uint32_t ms = state.remainder / US_PER_MS;
state.cache += ms;
state.remainder -= ms * US_PER_MS;
} else {
if (state.remainder < MILLIS_RARE_PATH_THRESHOLD_US) {
// Common path: small gap. Loop runs at most
// MILLIS_RARE_PATH_THRESHOLD_US / US_PER_MS iterations.
while (state.remainder >= US_PER_MS) {
state.cache++;
state.remainder -= US_PER_MS;
}
uint32_t result = state.cache;
xt_wsr_ps(ps);
return result;
}
// Rare path: large gap (WiFi scan, boot, long block). Take the accumulated
// μs out of the shared state, drop the critical section, then divide. This
// keeps interrupts unmasked during the ~2.5 μs __umulsidi3 — the rare path
// fires precisely when the system was already blocked, which is also when
// WiFi/peripheral ISRs most need to run on time.
//
// Concurrency on single-core ESP8266: only an ISR can preempt us. An ISR
// that calls millis() during the divide sees remainder=0 and a tiny delta,
// takes the common path, and returns the pre-commit cache. Monotonic — and
// any μs it adds to remainder are preserved by the `+=` on commit.
uint32_t pending_us = state.remainder;
state.remainder = 0;
xt_wsr_ps(ps);
uint32_t ms_to_add = pending_us / US_PER_MS;
uint32_t us_left = pending_us - ms_to_add * US_PER_MS;
ps = xt_rsil(15);
state.cache += ms_to_add;
state.remainder += us_left;
uint32_t result = state.cache;
xt_wsr_ps(ps);
return result;