Skip to content

unix: Wake sleeping operations immediately on scheduled callbacks. - #8

Closed
andrewleech wants to merge 3 commits into
review/unix-sleep-process-pendingfrom
unix-sleep-process-pending
Closed

andrewleech wants to merge 3 commits into
review/unix-sleep-process-pendingfrom
unix-sleep-process-pending

Conversation

@andrewleech

@andrewleech andrewleech commented Feb 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

On the unix port, time.sleep() and MICROPY_INTERNAL_WFE() were unresponsive to scheduled callbacks — time.sleep() used select() or sleep() with no wakeup mechanism, and WFE busy-polled with a 500us delay.

This adds a signal-based notification so that when something is scheduled (via MICROPY_SCHED_HOOK_SCHEDULED), a signal is sent to the process. A sig_atomic_t flag is set by both mp_hal_signal_event() and the signal handler. mp_unix_sched_sleep() uses pselect() to atomically unblock the signal and enter the wait, avoiding the TOCTOU race where signals for already-queued callbacks could be consumed before the sleep. The signal is blocked process-wide at init so only the thread inside pselect() can receive it, and pthread_sigmask is used on threaded builds for POSIX correctness.

time.sleep() is reworked to loop over mp_unix_sched_sleep() with elapsed-time tracking, processing pending callbacks each iteration. Negative values now raise ValueError to match CPython. WFE uses the same sleep primitive so it blocks properly and wakes on events rather than spinning.

Uses SIGRTMIN+7 where real-time signals are available, falling back to SIGURG.

Testing

Tested on the unix port (Linux), both standard and coverage variants. Windows codepath (_WIN32) is left unchanged — it keeps the existing select()/delay_us behaviour.

Trade-offs and Alternatives

Could have used a pipe/eventfd self-pipe pattern instead of signals, which would avoid any signal-number collision concerns. Signals are simpler and don't require managing an fd, and the chosen signal numbers avoid known conflicts with GC (SIGRTMIN+5) and thread terminate (SIGRTMIN+6).

The time.sleep() rewrite replaces the MICROPY_SELECT_REMAINING_TIME Linux-specific assumption about select() modifying the timeout struct with explicit mp_hal_ticks_ms() tracking, which is portable. Precision drops from microseconds to milliseconds which is acceptable for time.sleep().

Generative AI

I used generative AI tools when creating this PR, but a human has checked the code and is responsible for the description above.

@github-actions

github-actions Bot commented Feb 24, 2026 •

Copy link
Copy Markdown

Code size report:

Reference:  zephyr/mpconfigport: Remove duplicate builtins.open definition. [1ab9b66]
Comparison: unix: Use sched signal in MICROPY_INTERNAL_WFE. [merge of 3bd023c]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64: +1353 +0.158% standard[incl +40(data) +160(bss)]
      stm32:    +0 +0.000% PYBV10
      esp32:    +0 +0.000% ESP32_GENERIC
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

Install an empty signal handler (without SA_RESTART) for a dedicated
signal so that select() calls return EINTR when the scheduler queues a
callback. mp_hal_signal_event() sends this signal via kill(getpid()),
and MICROPY_SCHED_HOOK_SCHEDULED calls it from mp_sched_schedule().

This replaces the need for a self-pipe mechanism while remaining
async-signal-safe.

Signed-off-by: Andrew Leech <[email protected]>
Rewrite time.sleep() to use mp_unix_sched_sleep(), a select() call with
no file descriptors that returns early on EINTR from the scheduler
signal. The sleep loop recomputes remaining time on each iteration,
handling both signal wakeups and time.sleep(0) correctly.

Signed-off-by: Andrew Leech <[email protected]>
Replace the fixed 500us delay in MICROPY_INTERNAL_WFE with
mp_unix_sched_sleep(), which sleeps for the full requested timeout but
wakes immediately on EINTR from the scheduler signal.

Signed-off-by: Andrew Leech <[email protected]>
@andrewleech
andrewleech force-pushed the unix-sleep-process-pending branch from aa6bac2 to 3bd023c Compare February 24, 2026 09:38
Repository owner deleted a comment from mpy-reviewer Bot Feb 24, 2026
Repository owner deleted a comment from mpy-reviewer Bot Feb 24, 2026
Repository owner deleted a comment from mpy-reviewer Bot Feb 24, 2026
Repository owner deleted a comment from mpy-reviewer Bot Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants