Skip to content

fix(starry-kernel): align event notification semantics with Linux - #1925

Open
shilei-massclouds wants to merge 4 commits into
rcore-os:devfrom
shilei-massclouds:dev-fix-by-difftest
Open

fix(starry-kernel): align event notification semantics with Linux#1925
shilei-massclouds wants to merge 4 commits into
rcore-os:devfrom
shilei-massclouds:dev-fix-by-difftest

Conversation

@shilei-massclouds

Copy link
Copy Markdown
Contributor

Problem

StarryOS differed from Linux in several pipe, poll, eventfd, and epoll/signalfd behaviors:

  • Pipe buffering, readiness, capacity changes, and interrupted writes did not fully follow Linux semantics.
  • Poll mishandled negative file descriptors and unknown event bits.
  • Poll globally synthesized RDNORM and WRNORM, producing incorrect readiness masks for some file types.
  • Interrupted poll operations could return or restart incorrectly.
  • Eventfd accepted invalid write lengths and could access user memory before validating the length.
  • Eventfd validation was inconsistent between scalar and vectored writes.
  • Epoll ready-list handling differed from Linux for level-triggered aliases, edge-triggered notifications, and HUP events.
  • An EPOLLET signalfd shared across fork could lose the parent process registration and miss later wakeups.

These differences could cause incompatible return values, unexpected readiness events, unnecessary user-memory access,
partial-write loss, or blocked epoll waiters.

Changes

Pipe

  • Align pipe buffer merging and capacity behavior with Linux.
  • Preserve file-specific pipe readiness masks.
  • Preserve completed bytes when a blocking pipe write is interrupted.
  • Add deterministic kernel regression tests for pipe I/O and interruption behavior.

Poll and eventfd

  • Ignore all negative poll file descriptors and clear their revents.
  • Ignore unsupported requested poll event bits.
  • Preserve readiness masks reported by each file type instead of globally synthesizing RDNORM and WRNORM.
  • Correct interrupted poll results and syscall restart behavior.
  • Require eventfd writes to contain exactly 8 bytes.
  • Validate eventfd write lengths before importing user memory.
  • Apply eventfd length validation to vectored writes.
  • Extend the grouped QEMU tests for eventfd and the poll/select syscall family.

Epoll and signalfd

  • Align epoll ready-list handling with Linux level-triggered and edge-triggered behavior.
  • Avoid synthesizing readable events from HUP alone.
  • Preserve callback ordering for multiple epoll aliases.
  • Keep EPOLLET signalfd registrations in their owning process context across fork.
  • Extend axpoll, kernel axtests, and grouped QEMU tests for the updated readiness state machine.

Implementation Rationale

An invalid eventfd write length is a file-specific count error, so it must be rejected before accessing the user buffer.

Poll now preserves the exact readiness mask reported by each file type. Pipes, pidfds, and other implementations remain
responsible for reporting the event bits they support.

When an EPOLLET signalfd callback runs outside its owner process context after fork, it only wakes the original epoll
waiter. The owner process then rechecks readiness and restores the callback registration in the correct context. This
preserves process isolation without losing subsequent edge notifications.

Match Linux buffering, readiness, resize, and interrupted-write behavior.

Cover the invariants with deterministic kernel axtests.
Preserve Linux error precedence and interruption behavior, require exact eventfd write sizes, and report file-specific readiness masks.

Add grouped QEMU regressions for scalar and vectored eventfd writes, negative descriptors, and unknown poll bits.
Preserve level-trigger ordering, require fresh edge notifications, and keep signalfd edge registrations owned across fork.

Extend axpoll, kernel axtests, and grouped QEMU coverage for the readiness state machine.

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本 PR 修改共享 axpoll、StarryOS pipe/eventfd/poll,以及 epoll/signalfd 的就绪队列和唤醒逻辑,目标是对齐 Linux 的事件通知语义;实现还补充了 kernel axtest 和 qemu/system grouped C 覆盖。共享组件与内核边界的分层基本保持隔离,新增的 grouped C 子用例位于 system/<subcase>/,可由根 CMakeLists.txt 发现,失败路径也输出 STARRY_GROUPED_TEST_FAILED

阻塞问题

当前 head 的组织 CI 不是全绿:Test starry riscv64 qemu / run_container 失败(job 93032187488)。我在相同 head 本地运行 cargo xtask starry test qemu --arch riscv64 也以 exit 1 复现;qemu/system 运行到 bug-epollet-second-chunk 后在 axsync/src/mutex.rs:165 panic:Thread(82) tried to acquire mutex it already owns。该用例直接覆盖本 PR 修改的 epoll/EPOLLET ready/wakeup 路径,因此不能视为无关 CI。请定位并消除 callback、ready queue 和 waiter wake 边界中的同线程重入取锁,为该交错补充确定性回归测试,并重跑 riscv64 system QEMU。

验证与检查

  • 通过:python3 /tmp/review_pr_helper.py prepare-review --repo /workspace/repo --pr 1925 --head-sha 34369a5d120c3796f2a90aec0231a381baeeaf3b --base-ref origin/devgit diff --check origin/dev...HEADcargo fmt --checkcargo test -p axpoll --all-features(14 个测试通过)。
  • 失败:cargo xtask starry test qemu --arch riscv64,如上所述在 qemu/system 的 EPOLLET case panic;组织 CI 同一 head 同样失败。其余检查中 success=15、skipped=37、cancelled=22、failure=1;跳过/取消的矩阵项不改变该直接相关失败的结论。
  • 历史 review、inline review 和 issue 评论均为空;未发现需要继承或关闭的旧线程。
  • 未引入 [patch.crates-io]。已检查开放 PR 的 epoll/eventfd 检索结果;除当前 PR 外的命中是不同的测试或应用场景,没有发现需要先后合入的重叠实现。

Starry syscall 语义映射(Linux man-pages;比较目标为当前 Linux man-pages 语义)

Syscall 结论 对应标准 简要依据
write 待修复(受 F-001 阻塞) write(2) eventfd 写长度和 pipe 部分写路径已审查;整体 kernel runtime 未通过。
writev 待修复(受 F-001 阻塞) writev(2) 新增 eventfd 聚集长度验证须以完整 QEMU 通过为准。
pwritev / pwritev2 待修复(受 F-001 阻塞) pwritev2(2) offset=-1 复用 vector stream-write 验证路径。
poll 待修复(受 F-001 阻塞) poll(2) 已核对负 fd、未知 bits、revents 回写逻辑;完整系统回归失败。
ppoll 待修复(受 F-001 阻塞) ppoll(2) poll 共享 do_poll 和中断回写路径。
epoll_create / epoll_create1 待修复(受 F-001 阻塞) epoll_create1(2) 相关 epoll 实例的就绪队列运行时失败。
epoll_ctl 待修复(受 F-001 阻塞) epoll_ctl(2) 新注册、边沿回调和 ready 发布路径受失败覆盖。
epoll_wait 待修复(受 F-001 阻塞) epoll_wait(2) 失败用例直接进入 EPOLLET wait/wakeup 路径。
epoll_pwait / epoll_pwait2 待修复(受 F-001 阻塞) epoll_pwait2(2) epoll_wait 共享 epoll 实例及 waiter 注册。
eventfd / eventfd2 待修复(受 F-001 阻塞) eventfd(2) 写入长度语义已有 grouped C 覆盖,但系统 suite 未完成。

功能开发准则适用:这是一项共享组件和用户可见 ABI 语义扩展/修复;PR 描述说明了问题、调用方与方案,base 与开放 PR 检索未发现重复实现。当前阻塞项是可复现的运行时正确性问题,而非文档或风格问题。修复并通过上述 riscv64 QEMU 回归后可重新评审。

Powered by gpt-5.6-terra

@shilei-massclouds

Copy link
Copy Markdown
Contributor Author

本 PR 修改共享 axpoll、StarryOS pipe/eventfd/poll,以及 epoll/signalfd 的就绪队列和唤醒逻辑,目标是对齐 Linux 的事件通知语义;实现还补充了 kernel axtest 和 qemu/system grouped C 覆盖。共享组件与内核边界的分层基本保持隔离,新增的 grouped C 子用例位于 system/<subcase>/,可由根 CMakeLists.txt 发现,失败路径也输出 STARRY_GROUPED_TEST_FAILED

阻塞问题

当前 head 的组织 CI 不是全绿:Test starry riscv64 qemu / run_container 失败(job 93032187488)。我在相同 head 本地运行 cargo xtask starry test qemu --arch riscv64 也以 exit 1 复现;qemu/system 运行到 bug-epollet-second-chunk 后在 axsync/src/mutex.rs:165 panic:Thread(82) tried to acquire mutex it already owns。该用例直接覆盖本 PR 修改的 epoll/EPOLLET ready/wakeup 路径,因此不能视为无关 CI。请定位并消除 callback、ready queue 和 waiter wake 边界中的同线程重入取锁,为该交错补充确定性回归测试,并重跑 riscv64 system QEMU。

验证与检查

  • 通过:python3 /tmp/review_pr_helper.py prepare-review --repo /workspace/repo --pr 1925 --head-sha 34369a5d120c3796f2a90aec0231a381baeeaf3b --base-ref origin/devgit diff --check origin/dev...HEADcargo fmt --checkcargo test -p axpoll --all-features(14 个测试通过)。
  • 失败:cargo xtask starry test qemu --arch riscv64,如上所述在 qemu/system 的 EPOLLET case panic;组织 CI 同一 head 同样失败。其余检查中 success=15、skipped=37、cancelled=22、failure=1;跳过/取消的矩阵项不改变该直接相关失败的结论。
  • 历史 review、inline review 和 issue 评论均为空;未发现需要继承或关闭的旧线程。
  • 未引入 [patch.crates-io]。已检查开放 PR 的 epoll/eventfd 检索结果;除当前 PR 外的命中是不同的测试或应用场景,没有发现需要先后合入的重叠实现。

Starry syscall 语义映射(Linux man-pages;比较目标为当前 Linux man-pages 语义)

Syscall 结论 对应标准 简要依据
write 待修复(受 F-001 阻塞) write(2) eventfd 写长度和 pipe 部分写路径已审查;整体 kernel runtime 未通过。
writev 待修复(受 F-001 阻塞) writev(2) 新增 eventfd 聚集长度验证须以完整 QEMU 通过为准。
pwritev / pwritev2 待修复(受 F-001 阻塞) pwritev2(2) offset=-1 复用 vector stream-write 验证路径。
poll 待修复(受 F-001 阻塞) poll(2) 已核对负 fd、未知 bits、revents 回写逻辑;完整系统回归失败。
ppoll 待修复(受 F-001 阻塞) ppoll(2)poll 共享 do_poll 和中断回写路径。
epoll_create / epoll_create1 待修复(受 F-001 阻塞) epoll_create1(2) 相关 epoll 实例的就绪队列运行时失败。
epoll_ctl 待修复(受 F-001 阻塞) epoll_ctl(2) 新注册、边沿回调和 ready 发布路径受失败覆盖。
epoll_wait 待修复(受 F-001 阻塞) epoll_wait(2) 失败用例直接进入 EPOLLET wait/wakeup 路径。
epoll_pwait / epoll_pwait2 待修复(受 F-001 阻塞) epoll_pwait2(2)epoll_wait 共享 epoll 实例及 waiter 注册。
eventfd / eventfd2 待修复(受 F-001 阻塞) eventfd(2) 写入长度语义已有 grouped C 覆盖,但系统 suite 未完成。
功能开发准则适用:这是一项共享组件和用户可见 ABI 语义扩展/修复;PR 描述说明了问题、调用方与方案,base 与开放 PR 检索未发现重复实现。当前阻塞项是可复现的运行时正确性问题,而非文档或风格问题。修复并通过上述 riscv64 QEMU 回归后可重新评审。

Powered by gpt-5.6-terra

Thanks for catching this. The panic was caused by the EPOLLET callback synchronously re-registering the target file. A
target such as TcpSocket may invoke that callback while holding its internal service mutex, so re-registration attempted
to acquire the same mutex again on the same thread.

The callback now only publishes epoll-owned ready state and wakes an epoll waiter. The consumed target waker is rearmed
later from the epoll_wait task context, outside the target callback and its internal locks.

I also added a deterministic kernel regression test that detects any direct poll() or register() re-entry from an edge-
triggered callback.

Validation:

  • Starry kernel axtest on riscv64: 398/398 passed
  • bug-epollet-second-chunk: passed
  • Full riscv64 Starry QEMU suite: 2/2 cases passed
  • Starry kernel clippy: 25/25 checks passed
  • Formatting and diff checks passed

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

本次提交将 axpoll 的单 waiter 唤醒能力用于 StarryOS epoll,并调整 pipe/eventfd/poll 的就绪语义、eventfd 写入长度校验、EPOLLET/signalfd 回调重注册和 grouped QEMU 回归用例。改动跨共享组件与用户可见 syscall ABI;feature-development.md 因共享组件和 ABI 语义扩展而适用,按高风险路径审查。实现沿用 FileLike/Pollable 边界,没有引入 crates.io patch 或新的跨层依赖。

审查结果:本轮没有保留 active finding。曾核查 EPOLLET 消费后重注册的候选丢失通知窗口;追踪 do_epoll_wait -> register_waiter_wakers -> poll_events_with 后确认每次 syscall 在消费 ready queue 前均先安装 waiter waker,候选前提不成立,已撤回。HUP 不再伪造 IN、eventfd 对 write/writev 先校验总长度、pipe 的 PIPE_BUF/部分写及 poll 精确 mask 与 PR 的直接 syscall 回归覆盖相符。

验证:

  • python3 /tmp/review_pr_helper.py prepare-review --repo /workspace/repo --pr 1925 --head-sha d1a97f71f430cc201f9276df617f8e08528d6561 --base-ref origin/devgit diff --check origin/dev...HEADcargo fmt --check 通过。
  • cargo clippy --manifest-path components/axpoll/Cargo.toml --all-features -- -D warnings 通过;cargo test --manifest-path components/axpoll/Cargo.toml --all-features 通过(14 个测试);cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings 通过。
  • 组织 CI 当前 head d1a97f71 的 attempt 2 仍在运行,尚无失败结论;已完成的格式、sync-lint 和部分矩阵检查成功。先前 riscv64 QEMU failure 属于父提交 34369a5d,不作为当前 head 的失败。该 CI 完成前本 review 保持 COMMENT,不作批准结论。
  • 历史 changes-requested review 针对父提交的 EPOLLET 同线程锁重入;当前提交 d1a97f71 延迟 rearm,作者补充了 callback-boundary axtest。当前无 inline review thread;该修复已作为本轮代码路径审查的一部分。
  • base 中未发现重复实现;开放 PR 的 epoll/eventfd 命中经检查为不同测试或场景,没有依赖顺序或重复实现。

Starry syscall 语义映射(比较目标:当前 Linux man-pages 语义;完整 QEMU CI 仍待当前 head 完成):

Syscall 评审结论 对应标准 简要依据
write 未发现代码级问题,CI 待完成 write(2) eventfd 在访问 user buffer 前验证 8-byte 长度。
writev 未发现代码级问题,CI 待完成 writev(2) 先读取 iovec 元数据并求长度,再验证各 segment。
pwritev 未发现代码级问题,CI 待完成 pwritev(2) 普通 offset 写与 stream-write 分支已审查。
pwritev2 未发现代码级问题,CI 待完成 pwritev2(2) offset=-1 分支同步应用 eventfd 长度验证。
poll 未发现代码级问题,CI 待完成 poll(2) 保留 file 返回的精确 mask,负 fd 的 revents 清零有 grouped 覆盖。
ppoll 未发现代码级问题,CI 待完成 ppoll(2) poll 共用 do_poll 路径。
epoll_create 未发现代码级问题,CI 待完成 epoll_create1(2) 相关实例 ready/waiter 状态机已审查。
epoll_create1 未发现代码级问题,CI 待完成 epoll_create1(2) 相关实例 ready/waiter 状态机已审查。
epoll_ctl 未发现代码级问题,CI 待完成 epoll_ctl(2) HUP mask、alias callback 顺序与 edge callback 边界已审查。
epoll_wait 未发现代码级问题,CI 待完成 epoll_wait(2) 调用链在消费前注册 waiter waker;避免 callback 锁重入。
epoll_pwait 未发现代码级问题,CI 待完成 epoll_pwait(2) epoll_wait 共用等待和 ready-list 实现。
epoll_pwait2 未发现代码级问题,CI 待完成 epoll_pwait2(2) epoll_wait 共用等待和 ready-list 实现。
eventfd 未发现代码级问题,CI 待完成 eventfd(2) C regression 覆盖 raw write/writev 长度、EINVAL/EFAULT 顺序和 poll mask。
eventfd2 未发现代码级问题,CI 待完成 eventfd(2) 新增 grouped test 由 qemu/system 根 CMake 和 runner 发现。

Checklist 已完成:约束/领域准则、实现与并发边界、测试发现与失败传播、base/open-PR 重叠、Cargo patch、focused validation 和 current-head 校验。未完成项仅为组织 CI 的进行中状态;因此不批准也不请求修改。

Powered by gpt-5.6-terra

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