A thread parked in these host waits notices a queued signal only when its
own polling quantum or timeout ends. Linux returns EINTR at once.
PR #377 fixed nanosleep not returning on a queued signal; futex,
epoll_wait and select have the same defect. Measured on Apple M4,
against Linux 6.12 under qemu with HVF.
| signal to handler, median of 12 |
elfuse |
Linux 6.12 |
| nanosleep (after #377) |
0.080 ms |
0.044 ms |
| futex, finite timeout |
40.7 ms |
0.044 ms |
| futex, indefinite |
40.6 ms |
0.044 ms |
| epoll_wait, indefinite |
125 ms |
0.047 ms |
| select, 1 s timeout |
779 ms |
0.050 ms |
| epoll_wait, 1 s timeout |
777 ms |
0.047 ms |
futex re-checks signal_pending on a 100 ms quantum
(FUTEX_OS_SYNC_POLL_CAP_NS) and an indefinite epoll_wait on a 200 ms kevent
slice. A finite select or epoll_wait hands the guest's whole timeout to
pselect or kevent with no wakeup pipe fd and no slice, so the signal waits
for the timeout.
Reproducer: a sibling thread parks in each wait, the main thread sends
SIGUSR1 with pthread_kill after a settle delay, and the handler stamps
CLOCK_MONOTONIC.
A thread parked in these host waits notices a queued signal only when its
own polling quantum or timeout ends. Linux returns EINTR at once.
PR #377 fixed nanosleep not returning on a queued signal; futex,
epoll_wait and select have the same defect. Measured on Apple M4,
against Linux 6.12 under qemu with HVF.
futex re-checks signal_pending on a 100 ms quantum
(FUTEX_OS_SYNC_POLL_CAP_NS) and an indefinite epoll_wait on a 200 ms kevent
slice. A finite select or epoll_wait hands the guest's whole timeout to
pselect or kevent with no wakeup pipe fd and no slice, so the signal waits
for the timeout.
Reproducer: a sibling thread parks in each wait, the main thread sends
SIGUSR1 with pthread_kill after a settle delay, and the handler stamps
CLOCK_MONOTONIC.