Skip to content

Wake select and epoll_wait on a queued signal - #386

Open
xalestar wants to merge 1 commit into
sysprog21:mainfrom
xalestar:fix-select-epoll-signal-wake
Open

xalestar wants to merge 1 commit into
sysprog21:mainfrom
xalestar:fix-select-epoll-signal-wake

Conversation

@xalestar

@xalestar xalestar commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Part of #378; futex is left for after #383.

A thread parked in a host wait learns of a guest signal only through the wakeup pipe. pselect6 joined the pipe for an indefinite wait only, and epoll_pwait never did, so the handler ran only once the current 200 ms slice ended.

pselect6 now joins the pipe for every wait except a zero timeout, which does not park and would only drain a wake meant for a sibling. epoll_pwait parks in poll() on the kqueue fd plus the pipe, then collects with a zero-timeout kevent(), so the pipe is never registered on the guest's epoll instance.

Reproduction: tests/test-wait-signal-latency.c parks a sibling thread in each wait on an empty pipe, sends SIGUSR1 with pthread_kill, and takes the median signal-to-handler gap over 8 rounds against a 20 ms bound. On 0a63368 all three cases fail at about 42 ms (select with a timeout, epoll_wait with and without one); with this change all three pass.

Validation, rebased on 0a63368:

  • make check: exit 0
  • test-wait-signal-latency, test-wait-process-signal, test-wait-sigmask-signal, test-nanosleep-signal-latency: pass
  • make test-matrix-elfuse-aarch64: 291 passed, 1 failed, 10 skipped. The failure is test-sigio (no SIGURG on a TCP OOB byte). It also fails 3/3 on 0a63368 and does not touch select or epoll.
  • The qemu lane was not run.

Summary by cubic

Wakes threads parked in select/pselect6 and epoll_wait/epoll_pwait immediately when a guest signal is queued, instead of letting the handler wait out the rest of the 200 ms slice.

  • pselect6 now joins the wakeup pipe on every wait except a zero-timeout poll, which does not park.
  • epoll_pwait now parks in poll() on the kqueue fd plus the pipe, then collects with a zero-timeout kevent(), so the pipe never shows up on the guest's epoll instance.
  • Adds tests/test-wait-signal-latency.c to measure signal-to-handler latency for finite and indefinite waits.
  • The futex case is left for a separate change (part of A guest signal does not interrupt futex, epoll_wait or a finite select #378).

Written for commit 3b9c809. Summary will update on new commits.

Review in cubic

@xalestar
xalestar force-pushed the fix-select-epoll-signal-wake branch from 526a2d7 to 3b03f71 Compare September 16, 2026 08:16

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread tests/test-wait-signal-latency.c
A thread parked in a host wait learns of a guest signal only through
the wakeup pipe. pselect6 joined the pipe for an indefinite wait alone,
and epoll_pwait never did, so a queued signal sat out the rest of the
200 ms slice before the handler ran.

pselect6 now joins the pipe for every wait but a zero timeout, which
does not park and would only drain a wake meant for a sibling.
epoll_pwait parks in poll() on the kqueue fd and the pipe, then
collects with a zero-timeout kevent(). Registering the pipe on the
kqueue itself would put a host fd on the guest's epoll instance.

tests/test-wait-signal-latency.c measures signal-to-handler delay for
a finite select and for finite and indefinite epoll_wait. On main the
median is about 42 ms for each; with this change all three are under
the 20 ms bound.

futex has the same defect and is left for a separate change.

Refs sysprog21#378
@xalestar
xalestar force-pushed the fix-select-epoll-signal-wake branch from 3b03f71 to 3b9c809 Compare September 16, 2026 08:36
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.

1 participant