FelipeMdeO opened a new pull request, #20047:
URL: https://github.com/apache/nuttx/pull/20047
## Summary
`apps/testing/ostest`'s full suite hangs or crashes under
`CONFIG_SCHED_TICKLESS` due to two separate, generic (arch-independent)
scheduler bugs. Both are required together to get the suite passing
end-to-end under tickless.
* `sched/sched_addreadytorun.c`: `nxsched_reassess_timer()` (which
arms the round-robin timeslice timer) was only ever called from
`sched_unlock.c`, gated on the task that *was* running having
already exhausted its timeslice. Nothing armed the timer when a
*new* `SCHED_RR` task started running via an ordinary context
switch, so under tickless (no periodic tick to fall back on) two
same-priority `SCHED_RR` threads never interleaved -- one just ran
to completion before the other's first iteration was recorded.
* `sched/wdog/wdog.h`: `wd_timer_start()` computed the delay to the
next watchdog expiration with no clamp. An already-due watchdog
(common with back-to-back short-delay `wd_start()`/`wd_cancel()`
calls) made that delta go negative -- which arch code's
`NSEC_2_CTICK()`-style macros then cast to unsigned, turning
"already due" into a multi-year alarm that never fires. Clamping to
*zero* isn't sufficient either: oneshot hardware comparators (e.g.
the ESP32-S3 systimer) only interrupt on the counter *crossing* the
target from below, so arming for "right now" can miss the edge and
never fire at all.
Neither bug is specific to any one chip -- both are in generic
`sched/` code reachable by any architecture combining
`CONFIG_SCHED_TICKLESS` with `CONFIG_RR_INTERVAL > 0` (round-robin
bug) or any watchdog user issuing short/zero delays (wdog bug). The
round-robin bug is additionally confirmed on 3 independent tickless
backends across 2 architectures (Xtensa ESP32-S3, RISC-V ESP32-C3
legacy and shared backends).
The in-tree `boards/xtensa/esp32s3/esp32s3-devkit/configs/tickless` example
(`CONFIG_ESP32S3_TICKLESS` + `CONFIG_TESTING_OSTEST`, both already
enabled by default in that defconfig) reproduces the round-robin crash
immediately and deterministically on real hardware -- see the
Reproduction and Testing sections below.
## Impact
* Impact on hardware (will arch(s) / board(s) / driver(s) change)?
**YES -- fixes generic `sched/` code exercised by any board using
`CONFIG_SCHED_TICKLESS`; no board/driver files touched.**
* Anything else to consider or add? The `CONFIG_SMP` path of the round-robin
fix (`nxsched_switch_running()`) is intentionally **not** addressed here -- no
SMP hardware was available to validate against. Flagging for maintainer input
on whether that gap should block this PR or be tracked separately.
## Testing
I confirm that changes are verified on local setup and works as intended:
* Build Host(s): Ubuntu 24.04.4 LTS, x86_64, GCC (`xtensa-esp-elf-gcc`,
crosstool-NG esp-14.2.0_20241119, 14.2.0).
* Target(s):
* `xtensa (esp32s3-xiao)`:
`boards/xtensa/esp32s3/esp32s3-xiao/configs/usbnsh` +
`CONFIG_ESP32S3_TICKLESS=y` + `CONFIG_TESTING_OSTEST=y`
(`kconfig-tweak`).
* `xtensa (esp32s3-devkit)`: in-tree `esp32s3-devkit:tickless` example
config, unmodified.
* `riscv (esp32c3-legacy-devkit)`: in-tree `:tickless` config (own
`esp32c3_tickless.c` backend) -- round-robin fix only.
* `riscv (esp32c3-devkit)`: in-tree `:tickless` config (shared
`esp_tickless.c` backend) -- round-robin fix only.
### How to reproduce (before this fix)
Simplest repro uses only in-tree, unmodified files -- no board-specific
changes needed:
```
./tools/configure.sh esp32s3-devkit:tickless
make -j$(nproc)
# flash nuttx.bin, open the console, then at the nsh> prompt:
nsh> ostest
```
(Any board with `CONFIG_ESP32S3_TICKLESS`/equivalent tickless backend
+ `CONFIG_TESTING_OSTEST` + `CONFIG_RR_INTERVAL > 0` reproduces the
round-robin crash identically -- this is just the simplest way to get
there with zero custom config, since it's an existing in-tree example.)
**Console output before the fix** (`esp32s3-devkit:tickless`, stock
`master`):
```
user_main: round-robin scheduler test
rr_test: Set thread priority to 1
rr_test: Set thread policy to SCHED_RR
rr_test: Starting first get_primes_thread
First get_primes_thread: 88
rr_test: Starting second get_primes_thread
Second get_primes_thread: 89
rr_test: Waiting for threads to complete -- this should take awhile
If RR scheduling is working, they should start and complete at
about the same time
get_primes_thread id=1 started, looking for primes < 30000, doing 10 run(s)
get_primes_thread id=1 finished, found 3246 primes, last one was 29989
get_primes_thread id=2 started, looking for primes < 30000, doing 10 run(s)
get_primes_thread id=2 finished, found 3246 primes, last one was 29989
rr_test: Roundrobin Failed
dump_assert_info: Current Version: NuttX 13.0.1-RC0 f595ba31e2 Sep 1 2026
19:54:51 xtensa
dump_assert_info: Assertion failed : at file: :0 task: ostest process:
ostest 0x420239f0
up_dump_register: PC: 42022bc1 PS: 00060523
up_dump_register: A0: 80376c78 A1: 3fc98bd0 A2: 00000000 A3:
3fc8d9f0
[... full register + stack dump omitted ...]
ostest_main: Exiting with status 256
```
Note `id=1` fully finishing (`found 3246 primes`) before `id=2` even
*starts* -- the two same-priority `SCHED_RR` threads never
interleaved, so `rr_test`'s own pass check
(`apps/testing/ostest/roundrobin.c:263-280`, which requires a thread
switch within the first `CONFIG_TESTING_OSTEST_RR_RUNS` entries of
`g_rr_values[]`) fails and hits `ASSERT(false)`.
The watchdog bug (bug 2/2 in this PR) is timing-dependent and didn't
trigger on that particular `esp32s3-devkit` run, but reliably hung
`apps/testing/ostest/wdog.c`'s `wdog_test()` forever on
`esp32s3-xiao` (confirmed via a temporary progress printf that every
one of its 4 threads got stuck on the very first iteration of
`wdtest_rand()`'s busy-wait for its own watchdog callback -- the
callback never fired).
### After this fix
**Full, unmodified `apps/testing/ostest` suite, `esp32s3-xiao`,
`CONFIG_SCHED_TICKLESS` + `CONFIG_TESTING_OSTEST`, both commits
applied -- runs to completion with no hangs, no failed asserts:**
```
user_main: wdog test
wdog_test start...
[... 4 threads x wdtest_once/wdtest_recursive/wdtest_rand, all complete ...]
wdog_test end...
End of test memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena 5de60 5de60
...
user_main: round-robin scheduler test
rr_test: Set thread priority to 1
rr_test: Set thread policy to SCHED_RR
rr_test: Starting first get_primes_thread
First get_primes_thread: 249
rr_test: Starting second get_primes_thread
Second get_primes_thread: 250
rr_test: Waiting for threads to complete -- this should take awhile
If RR scheduling is working, they should start and complete at
about the same time
get_primes_thread id=1 started, looking for primes < 30000, doing 10 run(s)
get_primes_thread id=2 started, looking for primes < 30000, doing 10 run(s)
get_primes_thread id=1 finished, found 3246 primes, last one was 29989
get_primes_thread id=2 finished, found 3246 primes, last one was 29989
rr_test: Done
[... sporadic, dual sporadic, barrier (8 threads), setjmp, priority
inheritance, scheduler lock, smp call, nxevent, perf event
counter -- all pass ...]
Final memory usage:
VARIABLE BEFORE AFTER
======== ======== ========
arena 5de60 5de60
ordblks 2 5
mxordblk 58658 54320
uordblks 5758 57e0
fordblks 58708 58680
user_main: Exiting
ostest_main: Exiting with status 0
```
Note both `id=1` and `id=2` now start together (`get_primes_thread
id=1 started` immediately followed by `id=2 started`, instead of one
finishing before the other starts), and `rr_test: Done` (not
`Roundrobin Failed`) confirms `roundrobin.c`'s own interleaving check
passed.
The round-robin fix alone was additionally validated with just
`rr_test()` (skipping the rest of the suite) on both
`esp32c3-legacy-devkit:tickless` and `esp32c3-devkit:tickless` --
PASS on both, confirming the fix is backend- and architecture-independent.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]