Uh oh!
There was an error while loading. Please reload this page.
Answer pselect6's poll fallback as select does - #318
Merged
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
jserv
reviewed
Aug 21, 2026
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
xalestarforce-pushed
the
pselect-fallback-pollnval
branch
from
August 22, 2026 03:34
54e9703 to
a2444a7Comparejserv
reviewed
Aug 22, 2026
Uh oh!
There was an error while loading. Please reload this page.
pselect6 leaves fd_set behind and waits in poll() when a host descriptor lands at or above FD_SETSIZE, and hands the guest poll()'s view of that wait in two places. macOS poll() answers POLLNVAL for every descriptor it will not put on a kqueue: /dev/null, /dev/zero, /dev/random, /dev/urandom, directories, and kqueue descriptors themselves. The fallback copies that revents into the request, where POLLNVAL maps to no fd_set bit, so a guest whose descriptor table is close to full is told a live /dev/null is not ready. Linux select() reports every one of them ready. poll_eval_unpollable() answers those entries for sys_ppoll already, so the fallback takes them out of the poll set on the pass that exposes them and hands them to the same function. A refused entry makes poll() return at once, so that single restart waits for nothing. The return value is the second place. poll() counts a descriptor once however many events it reports, while select() counts it once per set it is reported in. Measured against the qemu-system-aarch64 reference VM, a /dev/null in both readfds and writefds answers 2 there and 1 through the fallback, and a socket pair holding a byte answers the same way. The count comes from the bits the write-back lights. Reaching the fallback needs no descriptor pressure beyond a high number. host_fd_ref_open_io() borrows the host descriptor instead of duplicating it while one thread is active, so a single-threaded guest gets there as soon as a borrowed descriptor is numbered at or above FD_SETSIZE. The poll pass moves into pselect_fallback_pass() with its state in one struct, since sys_pselect6 crosses the 400-line clang-tidy advisory otherwise. An allocation failure there leaves the wait loop at once, ahead of the interrupt predicates that can overwrite errno. Verified: tests/test-poll.c carries three new cases and reports 22 passed, 0 failed both under elfuse and inside the reference VM, and its two high-descriptor cases fail against main as it stands. make check is clean, make lint reports no new finding, and tests/test-matrix.sh all stays within baseline with zero failures: elfuse-aarch64 255 passed, qemu-aarch64 234 passed, elfuse-x86_64 78 passed.
xalestarforce-pushed
the
pselect-fallback-pollnval
branch
from
August 22, 2026 08:23
a2444a7 to
272932bCompareUh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
pselect6 falls back to poll() when a host descriptor is out of the fd_set range, causing the guest to receive poll()'s behavior in two ways: descriptors refused by macOS poll() (/dev/null, /dev/zero, /dev/urandom, directories, and kqueue fds) arrive as not ready, whereas Linux select() reports them as ready; additionally, the return value counts each descriptor once, whereas select() counts it once per set. The refused entries are routed through poll_eval_unpollable(), the helper sys_ppoll() already uses for the same descriptor set, and the count comes from the bits set by the write-back.
Reproduction is covered by the two high-descriptor cases in
tests/test-poll.c, which fail on main and pass here.make checkis clean,make lintis unchanged, andtests/test-matrix.shpasses all within baseline with zero failures (elfuse-aarch64 255, qemu-aarch64 234, elfuse-x86_64 78).