Skip to content

feat(epoll): implement Linux-compatible epoll_pwait2(2) #2238

Description

@fslongjin

Is your feature request related to a problem?

Yes. Native runtimes such as CodeBuddy Code 2.142.0 invoke epoll_pwait2(2) during startup. DragonOS currently defines syscall number 441 as SYS_EPOLL_PWAIT2 on x86_64, RISC-V 64, and LoongArch 64, but does not register an implementation, so the syscall falls through to ENOSYS.

A DragonOS guest trace captured two concrete failures:

Unsupported syscall ID: 441 -> SYS_EPOLL_PWAIT2,
args: [4, ..., 1024, <timespec>, <sigmask>, 8]

Unsupported syscall ID: 441 -> SYS_EPOLL_PWAIT2,
args: [15, ..., 1024, NULL, <sigmask>, 8]

This is an independent compatibility gap from the separately observed sched_setscheduler(2) failure.

Describe the solution you would like

Implement syscall 441 with Linux 6.6-compatible semantics:

int epoll_pwait2(int epfd,
                 struct epoll_event *events,
                 int maxevents,
                 const struct timespec *timeout,
                 const sigset_t *sigmask,
                 size_t sigsetsize);

The implementation should:

  • read the legacy __kernel_timespec ABI without truncating it to milliseconds;
  • use a relative, monotonic timeout with nanosecond resolution;
  • treat a null timeout as an infinite wait and {0, 0} as a non-blocking poll;
  • reject negative tv_sec or tv_nsec outside [0, 999999999] with EINVAL;
  • return EFAULT for inaccessible timeout, event, or signal-mask memory;
  • validate epfd, maxevents, sigmask, and sigsetsize as Linux does;
  • install the supplied signal mask only for the duration of the wait, never block SIGKILL or SIGSTOP, and restore the saved mask correctly after success, timeout, or interruption;
  • preserve Linux-compatible EINTR behavior;
  • share the core epoll wait path with epoll_wait(2) and epoll_pwait(2), while retaining the precision and ABI differences of each syscall;
  • register the syscall on every supported architecture that exposes SYS_EPOLL_PWAIT2.

The current common helper accepts an integer millisecond timeout. It should be generalized to accept an optional high-resolution timespec, with epoll_wait(2) performing its millisecond conversion at the syscall boundary. The existing epoll_pwait(2) argument parsing and signal-mask restoration path should also be audited during this refactor rather than copied blindly.

Reference implementation: Linux v6.6 fs/eventpoll.c.

Acceptance criteria

  • A raw syscall 441 test passes on DragonOS for zero, finite, sub-millisecond, and null timeouts.
  • Ready events wake the call and are copied to userspace correctly.
  • A finite timeout does not return before its lower bound, including a sub-millisecond timeout.
  • Invalid timespec values, pointers, descriptors, maxevents, and sigsetsize produce Linux-compatible errno values.
  • Temporary signal masks are applied during the wait and restored after success, timeout, and EINTR.
  • A pending unmasked signal interrupts the wait with Linux-compatible behavior.
  • Relevant gVisor epoll tests, including EpollTest.EpollPwait2Timeout, no longer skip/fail because of ENOSYS.
  • New DragonOS dunitest coverage is added and included in CI.
  • make kernel succeeds.
  • Tests pass inside an SMP DragonOS QEMU guest.
  • CodeBuddy Code 2.142.0 no longer produces unsupported syscall 441 messages during startup.

Alternatives considered

  1. Return success without waiting. Rejected because it breaks event-loop ordering and can cause busy loops.
  2. Forward to epoll_wait(2) after rounding to milliseconds. Rejected because it loses the nanosecond timeout contract and changes observable timing.
  3. Handle only the exact CodeBuddy arguments. Rejected as a workload-specific workaround rather than Linux ABI compatibility.
  4. Make userspace fall back after ENOSYS. Rejected because DragonOS aims to provide Linux binary compatibility and other native runtimes use this syscall.

Implementation planning requirement

Before changing code, compare the observed behavior, the DragonOS epoll and signal implementations, and Linux 6.6.139 in depth. Review the plan for Linux semantics, DragonOS architecture, concurrency and lifetime invariants, error paths, and boundary conditions. Do not use workload-specific behavior, test-specific bypasses, or other workarounds.

After implementation, compare the DragonOS code against Linux again. If the review finds a semantic mismatch, architectural problem, missing edge case, concurrency/lifetime risk, or workaround, return to the planning stage before continuing.

Linux reference source is available locally at ~/code/linux-6.6.139/.

Additional context

The implementation should remain a standalone epoll compatibility feature. It should not be bundled into the scheduler work merely because both missing syscalls were observed in the same CodeBuddy startup trace.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requesttestUnitest/User space test

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions