Skip to content

emscripten: Add epoll support - #5427

Merged
tgross35 merged 1 commit into
rust-lang:mainfrom
guybedford:emscripten-apis
Aug 20, 2026
Merged

emscripten: Add epoll support#5427
tgross35 merged 1 commit into
rust-lang:mainfrom
guybedford:emscripten-apis

Conversation

@guybedford

Copy link
Copy Markdown
Contributor

This adds the epoll APIs for the wasm32-unknown-emscripten target. Emscripten restored the sys/epoll.h header in 6.0.2 (emscripten-core/emscripten#27206) and implements the epoll functions in the JS filesystem as of the upcoming 6.0.8 (emscripten-core/emscripten#27207).

  • Adds EPOLL_CLOEXEC and epoll_create, epoll_create1, epoll_ctl, epoll_wait and epoll_pwait for Emscripten (the epoll_event type and EPOLL* constants were already defined for the target)
  • Enables the epoll type, constant and function tests in test_emscripten, version-gated so that all currently released Emscripten versions (including the 3.1.68 CI pin) are unaffected
  • Fixes Emscripten version detection in libc-test: since Emscripten 5.0.1 the lowercase __EMSCRIPTEN_major__ macros are non-integer aliases of new uppercase forms, and the tiny version component is now tracked so that point releases can be distinguished

Tested against Emscripten stable 6.0.7, where the header, type and constant tests run and pass, with the function link tests remaining version-gated until 6.0.8, and against the fully gated skip path.

Comment thread libc-test/build/main.rs Outdated
@tgross35 tgross35 added the stable-nominated This PR should be considered for cherry-pick to libc's stable release branch label Aug 19, 2026
@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

Emscripten restored the `sys/epoll.h` header in 6.0.2 and implements
`epoll_create`, `epoll_create1`, `epoll_ctl`, `epoll_wait` and
`epoll_pwait` in the JS filesystem as of 6.0.8.

Version detection in libc-test now also tracks the tiny version
component so that point releases can be distinguished, and parses the
uppercase `__EMSCRIPTEN_MAJOR__` macro forms used since Emscripten
5.0.1, where the lowercase names became non-integer aliases.

Link: https://github.com/emscripten-core/emscripten/blob/4483d70a78098ed5d860dff2dc21f3025b2da2ee/system/lib/libc/musl/include/sys/epoll.h#L17
Link: https://github.com/emscripten-core/emscripten/blob/4483d70a78098ed5d860dff2dc21f3025b2da2ee/system/lib/libc/musl/include/sys/epoll.h#L70-L74
Link: emscripten-core/emscripten#27206
Link: emscripten-core/emscripten#27207
@rustbot

rustbot commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@tgross35 tgross35 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@tgross35
tgross35 added this pull request to the merge queue Aug 20, 2026
Merged via the queue into rust-lang:main with commit 04c162b Aug 20, 2026
59 checks passed
@guybedford
guybedford deleted the emscripten-apis branch August 20, 2026 03:14
tgross35 pushed a commit to tgross35/rust-libc that referenced this pull request Sep 4, 2026
Emscripten restored the `sys/epoll.h` header in 6.0.2 and implements
`epoll_create`, `epoll_create1`, `epoll_ctl`, `epoll_wait` and
`epoll_pwait` in the JS filesystem as of 6.0.8.

Version detection in libc-test now also tracks the tiny version
component so that point releases can be distinguished, and parses the
uppercase `__EMSCRIPTEN_MAJOR__` macro forms used since Emscripten
5.0.1, where the lowercase names became non-integer aliases.

Link: https://github.com/emscripten-core/emscripten/blob/4483d70a78098ed5d860dff2dc21f3025b2da2ee/system/lib/libc/musl/include/sys/epoll.h#L17
Link: https://github.com/emscripten-core/emscripten/blob/4483d70a78098ed5d860dff2dc21f3025b2da2ee/system/lib/libc/musl/include/sys/epoll.h#L70-L74
Link: emscripten-core/emscripten#27206
Link: emscripten-core/emscripten#27207

(backport <rust-lang#5427>)
(cherry picked from commit 04c162b)
@tgross35 tgross35 mentioned this pull request Sep 4, 2026
@tgross35 tgross35 added stable-applied This PR has been cherry-picked to libc's stable release branch and removed stable-nominated This PR should be considered for cherry-pick to libc's stable release branch labels Sep 4, 2026
tgross35 pushed a commit to tgross35/rust-libc that referenced this pull request Sep 4, 2026
Emscripten restored the `sys/epoll.h` header in 6.0.2 and implements
`epoll_create`, `epoll_create1`, `epoll_ctl`, `epoll_wait` and
`epoll_pwait` in the JS filesystem as of 6.0.8.

Version detection in libc-test now also tracks the tiny version
component so that point releases can be distinguished, and parses the
uppercase `__EMSCRIPTEN_MAJOR__` macro forms used since Emscripten
5.0.1, where the lowercase names became non-integer aliases.

Link: https://github.com/emscripten-core/emscripten/blob/4483d70a78098ed5d860dff2dc21f3025b2da2ee/system/lib/libc/musl/include/sys/epoll.h#L17
Link: https://github.com/emscripten-core/emscripten/blob/4483d70a78098ed5d860dff2dc21f3025b2da2ee/system/lib/libc/musl/include/sys/epoll.h#L70-L74
Link: emscripten-core/emscripten#27206
Link: emscripten-core/emscripten#27207

(backport <rust-lang#5427>)
(cherry picked from commit 04c162b)
guybedford added a commit to guybedford/tokio that referenced this pull request Sep 9, 2026
Follow-on to tokio-rs#8285, enabling `tokio::net` on Emscripten over mio's
epoll selector and Node's raw sockets (`-sNODERAWSOCKETS`).

The I/O driver is the native one. Under JSPI, Emscripten's `epoll_wait`
is a blocking wait that suspends on the host event loop, resuming on
readiness (or the mio waker pipe) or the deadline, so `park` and
`park_timeout` need nothing target-specific. The one addition is for
the scheduler's zero-duration maintenance park: a zero-timeout
`epoll_wait` is a synchronous probe, and the host loop is the only
producer of readiness, so the driver yields one host turn first, as the
zero-duration `ParkThread` park already does. Without JSPI a real wait
panics rather than spinning, matching the existing park semantics.
Under pthreads with `-sPROXY_TO_PTHREAD` the wait blocks on the worker
as on native, with no target-specific code at all.

TcpStream/TcpListener/UdpSocket, stream `AF_UNIX` sockets, `lookup_host`
and `AsyncFd` work as on native. Gated where Node lacks the primitive:
datagram `AF_UNIX` (`UnixDatagram`, `UnixSocket::new_datagram`),
`socketpair(2)` (`UnixStream::pair`), and `SO_PEERCRED` (`peer_cred`
reports unsupported). Name resolution goes through Emscripten's
synchronous `getaddrinfo`, which maps hostnames to synthetic addresses,
so the `localhost` tests are ignored on this target.

CI adds `net` to both emscripten test runs on the released emsdk: JSPI
(815 passed, 0 failed, 19 ignored) and pthreads, which regains
`-sPROXY_TO_PTHREAD` (818 passed, 0 failed, 19 ignored). The JSPI run
uses Rust beta until 1.99 is stable, which is where `OwnedFd::try_clone`
(mio's registry handle) gains Emscripten support. TEMPORARY: `mio` comes
from tokio-rs/mio#1969 until released, which in turn takes `libc` from
the `libc-0.2` branch for its emscripten epoll bindings
(rust-lang/libc#5427).
guybedford added a commit to guybedford/tokio that referenced this pull request Sep 11, 2026
Follow-on to tokio-rs#8285, enabling `tokio::net` on Emscripten over mio's
epoll selector and Node's raw sockets (`-sNODERAWSOCKETS`).

The I/O driver is the native one. Under JSPI, Emscripten's `epoll_wait`
is a blocking wait that suspends on the host event loop, resuming on
readiness (or the mio waker pipe) or the deadline, so `park` and
`park_timeout` need nothing target-specific beyond `jspi::io_wait`,
which makes the wait a park in the JSPI sense: it leaves the runtime
around the `epoll_wait` as the timer park does, so sibling activations
may drive their own runtime while it is suspended. It also handles the
scheduler's zero-duration maintenance park: a zero-timeout `epoll_wait`
is a synchronous probe, and the host loop is the only producer of
readiness, so the driver yields one host turn first, as the
zero-duration `ParkThread` park already does. Without JSPI a real wait
panics rather than spinning, matching the existing park semantics.
Under pthreads with `-sPROXY_TO_PTHREAD` the wait blocks on the worker
as on native, with no target-specific code at all.

A wait with no deadline is a real `epoll_wait` that a socket could wake,
so it suspends rather than panicking as the reactor-less park does; the
`rt_emscripten_block_on` test of that panic is gated off `net`.

TcpStream/TcpListener/UdpSocket, stream `AF_UNIX` sockets, `lookup_host`
and `AsyncFd` work as on native. Gated where Node lacks the primitive:
datagram `AF_UNIX` (`UnixDatagram`, `UnixSocket::new_datagram`),
`socketpair(2)` (`UnixStream::pair`), and `SO_PEERCRED` (`peer_cred`
reports unsupported). Name resolution goes through Emscripten's
synchronous `getaddrinfo`, which maps hostnames to synthetic addresses,
so the `localhost` tests are ignored on this target.

CI adds `net` to both emscripten test runs on the released emsdk: JSPI
(846 passed, 0 failed, 19 ignored) and pthreads, which regains
`-sPROXY_TO_PTHREAD` (818 passed, 0 failed, 19 ignored). The JSPI lane
links a `--pre-js` that fails a test binary whose `main` never returns:
a park that suspends with no wake source leaves Node's event loop to
drain and the process to exit 0, which cargo would otherwise take as
success. The JSPI run uses Rust beta until 1.99 is stable, which is
where `OwnedFd::try_clone` (mio's registry handle) gains Emscripten
support. TEMPORARY: `mio` comes from tokio-rs/mio#1969 until released,
which in turn takes `libc` from the `libc-0.2` branch for its emscripten
epoll bindings (rust-lang/libc#5427).
guybedford added a commit to guybedford/tokio that referenced this pull request Sep 11, 2026
Follow-on to tokio-rs#8285, enabling `tokio::net` on Emscripten over mio's
epoll selector and Node's raw sockets (`-sNODERAWSOCKETS`).

The I/O driver is the native one. Under JSPI, Emscripten's `epoll_wait`
is a blocking wait that suspends on the host event loop, resuming on
readiness (or the mio waker pipe) or the deadline, so `park` and
`park_timeout` need nothing target-specific beyond `jspi::io_wait`,
which makes the wait a park in the JSPI sense: it leaves the runtime
around the `epoll_wait` as the timer park does, so sibling activations
may drive their own runtime while it is suspended. It also handles the
scheduler's zero-duration maintenance park: a zero-timeout `epoll_wait`
is a synchronous probe, and the host loop is the only producer of
readiness, so the driver yields one host turn first, as the
zero-duration `ParkThread` park already does. Without JSPI a real wait
panics rather than spinning, matching the existing park semantics.
Under pthreads with `-sPROXY_TO_PTHREAD` the wait blocks on the worker
as on native, with no target-specific code at all.

A wait with no deadline is a real `epoll_wait` that a socket could wake,
so it suspends rather than panicking as the reactor-less park does; the
`rt_emscripten_block_on` test of that panic is gated off `net`.

TcpStream/TcpListener/UdpSocket, stream `AF_UNIX` sockets, `lookup_host`
and `AsyncFd` work as on native. Gated where Node lacks the primitive:
datagram `AF_UNIX` (`UnixDatagram`, `UnixSocket::new_datagram`),
`socketpair(2)` (`UnixStream::pair`), and `SO_PEERCRED` (`peer_cred`
reports unsupported). Name resolution goes through Emscripten's
synchronous `getaddrinfo`, which maps hostnames to synthetic addresses,
so the `localhost` tests are ignored on this target.

CI adds `net` to both emscripten test runs on the released emsdk: JSPI
(846 passed, 0 failed, 19 ignored) and pthreads, which regains
`-sPROXY_TO_PTHREAD` (818 passed, 0 failed, 19 ignored). The JSPI lane
links a `--pre-js` that fails a test binary whose `main` never returns:
a park that suspends with no wake source leaves Node's event loop to
drain and the process to exit 0, which cargo would otherwise take as
success. The JSPI run uses Rust beta until 1.99 is stable, which is
where `OwnedFd::try_clone` (mio's registry handle) gains Emscripten
support. TEMPORARY: `mio` comes from tokio-rs/mio#1969 until released,
which in turn takes `libc` from the `libc-0.2` branch for its emscripten
epoll bindings (rust-lang/libc#5427).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

O-linux O-linux-like O-unix stable-applied This PR has been cherry-picked to libc's stable release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants