Park rt_sigtimedwait instead of polling
rt_sigtimedwait waited by waking every 1 ms to take sig_lock and look for a signal, so a 2 s wait cost 17.6 ms of process CPU against 0.036 ms on Linux 6.12, and the guest sees that time in CLOCK_PROCESS_CPUTIME_ID and times. The wait now parks on the wakeup counter until a wake or the deadline, the way nanosleep does. A waited signal is normally blocked in every thread, so the queue paths never rang the wakeup pipe for it; they now ring it when a rt_sigtimedwait caller is parked. The park is capped at the next expiry of a POSIX timer that has no signal queued yet, and a timer armed from another thread rings the pipe so the waiter recomputes.
The probe from the issue now reports 0.09 ms of CPU for the 2 s wait, and a signal sent after 200 ms wakes the waiter at 0.213 s. tests/test-sigtimedwait.c gains three cases: a 1 s wait stays under 4 ms of CPU (11 ms on the old code), a timer wakes both timed and untimed waits, and a fast periodic timer with its signal already pending does not make a wait for another signal wake per period (11.2 ms of CPU without the guard, 0.05 ms with it). make check passes except test-thread-churn, a 60 s timeout that fails the same way on the unmodified base during a full run and passes alone on both. check-format, check-ascii, check-eintr-contract, check-lock-order and check-atomics are clean, except that clang-format-22 was not installed locally, so the format gate was skipped and is left to CI.
Fixes #480
Summary by cubic
Parks threads in rt_sigtimedwait instead of polling every 1 ms, cutting the CPU of a 2 s wait from 17.6 ms to 0.09 ms. The wait now sleeps on the wakeup counter, and queue sites ring the wakeup pipe when a waiter is parked. The park is capped at the next POSIX timer expiry whose signal is not yet queued, and setting a timer from another thread wakes the waiter to recompute. Fixes #480.
- Waits on signals normally blocked in every thread now wake their caller at delivery.
- A timer whose signal is already pending only adds overruns, so it does not shorten the park; while such a timer waits to enqueue, the park is capped at 1 ms, and dequeuing its signal wakes a parked waiter to recompute.
ITIMER_REALis advanced inside the wait, soalarm()reaches a lone thread waiting for SIGALRM;setitimerrings the waiter, and a far-off expiry is clamped before the nanosecond conversion.- Adds five tests: CPU usage, timer-driven wakeups, a pending-signal timer not spinning a different-signal wait, alarm waking a wait, and a far-off itimer leaving a short timeout intact.