Skip to content

fix/esp32s3-tickless-timeout-overflow - #20024

Merged
xiaoxiang781216 merged 1 commit into
apache:masterfrom
FelipeMdeO:fix/esp32s3-tickless-timeout-overflow
Sep 1, 2026
Merged

fix/esp32s3-tickless-timeout-overflow#20024
xiaoxiang781216 merged 1 commit into
apache:masterfrom
FelipeMdeO:fix/esp32s3-tickless-timeout-overflow

Conversation

@FelipeMdeO

Copy link
Copy Markdown
Contributor

Summary

CONFIG_ESP32S3_TICKLESS hangs forever the first time a task sleeps
with a fractional-second timeout of ~134ms or more (e.g.
usleep(500000)) while another task also has a pending timeout —
e.g. apps/testing/ostest hangs immediately, since that's exactly
what user_main()'s first statement does.

Root cause

#define NSEC_2_CTICK(nsec)    (((nsec) * CTICK_PER_USEC) / NSEC_PER_USEC)

nsec is a 32-bit long and CTICK_PER_USEC is 16 (16MHz systimer),
so nsec * 16 overflows a 32-bit signed int for tv_nsec >= ~134ms.
The overflowed (negative) result gets added into up_timer_start()'s
uint64_t cpu_ticks, wrapping to a value near UINT64_MAX. The
systimer alarm then gets programmed that many ticks in the future —
effectively never — so the sleeping task never wakes up.

SEC_2_CTICK/USEC_2_CTICK have the same class of bug at higher
thresholds.

Fix

Cast to uint64_t before multiplying in all three macros, forcing
64-bit arithmetic (matching the already-safe CTICK_2_* macros).

Also fixed a pre-existing nxstyle nit (missing blank line) in
tickless_isr(), next to the changed code.

Testing

Board: Seeed XIAO ESP32-S3, built on current master.

  • Reproduced: instrumented up_timer_start() and confirmed the exact
    overflow (cpu_ticks=18446744073709121682 for a ~500-700ms sleep).
  • Before: ostest (CONFIG_ESP32S3_TICKLESS=y) hangs right after
    Started user_main, reproducible every time from a clean flash.
  • After: full ostest suite runs past that point and completes.
  • Plain single-task sleeps (sleep 3 from NSH) keep correct timing
    before and after (3.06s measured).

…C_2_CTICK

CONFIG_ESP32S3_TICKLESS hangs forever the first time a task calls a
sleep/timeout with a fractional-second component of roughly 134ms or
more (e.g. usleep(500000)) while another task is also pending a
timeout.

Root cause: NSEC_2_CTICK() computes ((nsec) * CTICK_PER_USEC) /
NSEC_PER_USEC. `nsec` (struct timespec's tv_nsec) is a 32-bit `long`,
and CTICK_PER_USEC is 16 (the S3's systimer runs at 16MHz), so the
multiplication overflows a 32-bit signed int for any tv_nsec at or
above INT32_MAX / 16 (~134,217,728 ns). The overflowed (negative)
result then gets added into up_timer_start()'s `uint64_t cpu_ticks`,
wrapping around to a value near UINT64_MAX. tickless_setcounter()
then programs the systimer alarm that many ticks in the future --
effectively never -- so nxsched_process_timer() is never called and
the waiting task sleeps forever.

Reproduced on real esp32s3-xiao hardware: apps/testing/ostest hung
indefinitely right after starting user_main(), whose first statement
is usleep(500000). Instrumented up_timer_start() to print its inputs
and observed exactly the described overflow (cpu_ticks close to
UINT64_MAX for tv_nsec=510000000). Confirmed root cause is the
concurrent-timeout case specifically: user_main's usleep() alone
works, and ostest_main's own usleep() alone works, but the two
together (matching ostest's actual task_create() + concurrent
usleep() pattern) reproduce the hang every time.

Fix: cast to uint64_t before multiplying in all three *_2_CTICK
macros, forcing 64-bit arithmetic throughout, matching how the
CTICK_2_* (division) macros are already overflow-safe.

Validated on esp32s3-xiao: with the fix, the full ostest suite (built
with CONFIG_ESP32S3_TICKLESS=y) runs past the point it used to hang
and completes end to end.

Note: while testing, ostest's own round-robin test (rr_test) failed
near the end of the run -- the two same-priority SCHED_RR threads did
not appear to interleave under tickless. That looks like a separate,
likely more architectural issue (time-slice preemption needs its own
periodic re-arm, independent of one-shot sleep timeouts) and is not
addressed by this fix; filing separately.

Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
@github-actions github-actions Bot added Arch: xtensa Issues related to the Xtensa architecture Size: XS The size of the change in this PR is very small labels Aug 31, 2026
@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@xiaoxiang781216
xiaoxiang781216 merged commit 3026e32 into apache:master Sep 1, 2026
38 of 39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: xtensa Issues related to the Xtensa architecture Size: XS The size of the change in this PR is very small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants