Skip to content

Implement epoll for FS#27201

Closed
guybedford wants to merge 3 commits into
emscripten-core:mainfrom
guybedford:epoll
Closed

Implement epoll for FS#27201
guybedford wants to merge 3 commits into
emscripten-core:mainfrom
guybedford:epoll

Conversation

@guybedford

Copy link
Copy Markdown
Collaborator

Resolves #5033, #10556.

With all the poll work, it kind of makes sense to just implement actual epoll at this point for compat and the extra functionality.

This adds the functions - epoll_create1, epoll_ctl, epoll_wait, epoll_pwait.

With -sNODERAWSOCKETS and -SNODERAWFS this allows real epolling on the file descriptors, without the once-style semantics of poll() being a requirement.

In the process this includes some of the refactorings from #27181 in unifying the notification / listener system for JS.

Supports EPOLLONESHOT, but EPOLLEXCLUSIVE is effectively ignored for the pthreads case still currently.

It does not yet support epoll for WASMFS, which would be a follow-on.

PR made with AI assistance, under my review

Comment thread system/lib/libc/musl/include/sys/epoll.h
Implements epoll_create1/epoll_ctl/epoll_wait/epoll_pwait in the JS
syscall layer on a unified fd-readiness wait-queue shared with poll().

- epoll instances are real FS fds, so close(2) and nesting work for free
- level- and edge-triggered (EPOLLET), EPOLLONESHOT, EPOLLRDHUP, and the
  EPOLLEXCLUSIVE ctl restriction (its wakeup-limiting is a no-op, single-
  threaded; only the EPOLL_CTL_MOD restriction is enforced)
- blocking epoll_wait suspends under PROXY_TO_PTHREAD, ASYNCIFY and JSPI
- sockets and pipes feed readiness via a producer wait-queue
- WASMFS epoll is out of scope (fails at link time)

Only sockets and pipes derive real readiness; every other stream type
(regular files across MEMFS/NODEFS/NODERAWFS, devices, ttys) has no poll
handler and is treated as always readable+writable, so epoll_ctl rejects
it with EPERM. This also fixes poll() crashing on a NODERAWFS regular
file, whose stream carries no stream_ops at all. Known limitation: as
before, ttys are not pollable (no poll handler), unlike Linux.
@sbc100

sbc100 commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Could you split this PR in to two parts:

  1. Add epoll headers and syscall implementations that just return errors. (i.e. all the boilerplate stuff)
  2. The actual working implementation.

We should be able to land (1) right away then we can focus on reviewing (2) .. which might take a little longer.

@guybedford

Copy link
Copy Markdown
Collaborator Author

Sure, I can post the two separate PRs instead. Let me do that.

@guybedford guybedford closed this Jun 26, 2026
@guybedford guybedford deleted the epoll branch June 26, 2026 19:11
sbc100 pushed a commit that referenced this pull request Jun 26, 2026
This adds the epoll syscall surface (headers, libc wrappers,
declarations and signatures) with no working implementation, so the
boilerplate can land ahead of the host integration. Split out from
#27201 so that the larger, more involved host implementation can be
reviewed separately.

The syscalls are fully wired in but return `-ENOSYS` everywhere for now:

* `sys/epoll.h` synced from upstream musl, and removed from the exclude
list in `update_musl.py`
* musl `epoll.c` wrappers compiled into libc
(`epoll_create`/`epoll_create1`/`epoll_ctl`/`epoll_wait`/`epoll_pwait`)
* `SYS_epoll_*` -> `__syscall_epoll_*` mappings, declarations in
`emscripten/syscalls.h`, and `libsigs.js` signatures
* legacy (non-WASMFS) JS `__syscall_epoll_*` return `-ENOSYS`
* WASMFS `__syscall_epoll_*` return `-ENOSYS`, matching the existing
socket stubs in `syscalls.cpp`
* `tools/native_sigs.py` regenerated for the new libc functions

The actual readiness/wait-queue host integration (the working epoll)
follows in a separate PR.
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.

epoll support

2 participants