Skip to content

fix(starry,nginx): multi-worker signal interruption and EPOLLEXCLUSIVE handling#1018

Merged
ZR233 merged 6 commits into
rcore-os:devfrom
Antareske:fix/dev-starry-nginx-multiworker-kernel
Jun 4, 2026
Merged

fix(starry,nginx): multi-worker signal interruption and EPOLLEXCLUSIVE handling#1018
ZR233 merged 6 commits into
rcore-os:devfrom
Antareske:fix/dev-starry-nginx-multiworker-kernel

Conversation

@Antareske

Copy link
Copy Markdown
Contributor

修复 StarryOS 上 nginx 多 worker 生命周期阻塞

Summary

  • 修复 send_signal_to_thread / send_signal_to_process 对可投递信号仅 wake_task 的问题,改为 task.interrupt(),确保阻塞 syscall 可按 Linux 语义返回 EINTR
  • 修复 epoll_ctl 对 nginx 使用的 EPOLLEXCLUSIVE 标志返回 EINVAL 的问题,允许该标志通过内核参数校验

背景与问题

在 StarryOS 上复现 nginx master_process on; worker_processes 2; 场景时,存在两类问题叠加:

  1. worker 启动阶段失败:epoll_ctl(...)=EINVAL,导致 worker 直接退出。
  2. worker 阻塞阶段无法被信号稳定打断:信号送达后只唤醒任务,不设置 interrupt 标志,阻塞在 interruptible(...) 的路径难以及时返回 EINTR

改动细节

1) 信号打断语义修复

  • 文件:os/StarryOS/kernel/src/task/signal.rs
  • 改动:
    • send_signal_to_thread 中,可投递信号改为 task.interrupt()
    • send_signal_to_process 中,选中的目标线程也改为 task.interrupt()
  • 目的:让阻塞在 axtask::future::interruptible(...) 的 syscall(如 accept4)能及时被中断,返回 EINTR,与用户态信号处理/退出路径对齐。

2) epoll 参数兼容修复

  • 文件:os/StarryOS/kernel/src/file/epoll.rs
  • 改动:将 EPOLLEXCLUSIVE 纳入 EpollFlags 合法标志集合。
  • 目的:兼容 nginx worker 初始化时对 epoll 的使用,避免 epoll_ctl 因未知 flag 返回 EINVAL

验证结果

在尚未 merge 的 nginx CI 中测试:

  • debug 最小回归(x86_64):NGINX_MW_TEST_PASSED
  • phase1 脚本本体(x86_64):NGINX_PHASE1_TEST_PASSED
  • 代码质量检查:cargo fmtcargo xtask clippy --package starry-kernel 全部通过

风险与影响面

  • task.interrupt() 只用于“可投递信号”的路径,阻塞信号和 sigwait 特殊唤醒逻辑未改动,影响面可控。
  • EPOLLEXCLUSIVE 作为 flag 兼容项引入,不改变既有 epoll 事件消费主流程。

Test plan

以下内容均已通过:

  • cargo fmt
  • cargo xtask clippy --package starry-kernel
  • cargo xtask starry test qemu --target riscv64gc-unknown-none-elf
  • cargo xtask starry test qemu --target aarch64-unknown-none-softfloat
  • cargo xtask starry test qemu --target x86_64-unknown-none
  • cargo xtask starry app run -t nginx --arch x86_64 --qemu-config apps/starry/nginx/debug/qemu-x86_64-multiworker.toml
  • cargo xtask starry app run -t nginx --arch x86_64 --qemu-config apps/starry/nginx/debug/qemu-x86_64-phase1.toml
  • cargo xtask starry app run -t nginx --arch riscv64 --qemu-config apps/starry/nginx/debug/qemu-riscv64-multiworker.toml

后三项为尚未 merge 的 nginx CI 命令。

@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.

Review: LGTM ✅

变更概述

本 PR 修复了 StarryOS 上 nginx 多 worker 模式运行时的两个问题:

  1. EPOLLEXCLUSIVE 标志兼容 (epoll.rs):将 EPOLLEXCLUSIVE 加入 EpollFlags 合法集合,避免 epoll_ctl 返回 EINVAL。标志目前仅作兼容接受,不改变唤醒语义——在 StarryOS 单执行器模型下此设计合理,后续可按需实现 exclusive wakeup 避免惊群效应。

  2. 信号打断语义修复 (signal.rs):将 send_signal_to_threadsend_signal_to_process 中的 ax_task::wake_task(&task) 改为 task.interrupt(),确保阻塞在 interruptible(...) 中的 syscall 能正确返回 EINTR。改动与已有的 send_signal_thread_inner 一致,且 sigwait 路径仍使用 wake_task,语义正确。

代码分析

  • task.interrupt() 设置 interrupted 标志并唤醒任务,interruptible() 包装器检测到该标志后返回 Err(Interrupted),转换为用户态 -EINTR
  • 注释更新准确描述了新行为意图。
  • 影响面可控:仅影响信号投递路径中「可投递信号」的唤醒方式。

验证结果

  • cargo fmt --check:✅ 通过
  • cargo clippy --package starry-kernel:✅ 全部 13 个 feature 组合通过
  • Starry QEMU 测试 (x86_64):✅ 运行 16 个用例,15/16 直接通过,nginx-smoke 首次为 flaky(重跑通过)
  • 未增加新 apps 测试,不需要额外 QEMU 验证。

CI 状态

CI 全部 skipped(fork PR 权限限制),本地验证结果良好。

前序 Review 评论

无前序 review 评论或未解决 issue。

总结

改动小而精确,修复了正确的语义问题,本地验证通过。建议合并。

Powered by mimo-v2.5-pro

@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.

代码审查:LGTM ✅

变更概述

本 PR 修复 StarryOS 上 nginx 多 worker 模式的两个问题:

  1. 信号打断语义修复 (signal.rs):将 send_signal_to_threadsend_signal_to_process 中的 ax_task::wake_task(&task) 改为 task.interrupt(),与已有的 send_signal_thread_inner 保持一致。sigwait 路径(第 546 行)仍正确使用 wake_task,语义正确。

  2. EPOLLEXCLUSIVE 标志兼容 (epoll.rs):将 EPOLLEXCLUSIVE 加入 EpollFlags 合法集合。sys_epoll_ctl 中通过 EpollFlags::from_bits() 校验标志位,未注册的标志会导致 EINVAL。此改动仅作兼容接受,不改变 epoll 事件消费主流程。

代码分析

  • task.interrupt() 设置 interrupted 标志并唤醒任务,interruptible() 包装器检测到该标志后返回 Err(Interrupted),转换为用户态 -EINTR。这是 Linux 信号投递的正确语义。
  • send_signal_thread_inner(第 454 行)已经使用 task.interrupt(),本 PR 使公共 API 与内部 helper 对齐。
  • 影响面可控:仅影响「可投递信号」的唤醒方式;阻塞信号和 sigwait 特殊唤醒逻辑未改动。
  • 无新增 apps 测试,无需额外 QEMU 验证。

本地验证结果

  • cargo fmt --check:✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings:✅ 通过(0 warnings)
  • cargo test:预期失败(内核 crate 链接器符号缺失,属预存限制,与本 PR 无关)

CI 状态

CI 全部 skipped(fork PR 权限限制),不是本 PR 导致的失败。

重复/重叠分析

  • 无冲突的 open PR。PR #1017(apk cmake 测试)、#1016 与本 PR 无关。
  • 基线分支已有 send_signal_thread_inner 使用 task.interrupt(),本 PR 使公共函数与之对齐,非重复实现。
  • 相关历史 PR:#797(添加 wake_task)、#535(sigwaitinfo 修复)、#910(EPOLLET 修复),均为不同方面。

前序 Review 评论

无前序 review 评论或未解决 issue。mai-team-app[bot] 的 APPROVE 审查技术分析合理。

总结

改动小而精确,修复了正确的语义问题,与现有代码模式一致,本地验证通过。建议合并。

Powered by mimo-v2.5-pro

@ZR233 ZR233 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.

这轮需要 request changes:实现方向没问题,但这两个改动都属于 StarryOS syscall/信号 ABI 行为,需要补 normal test-suit 回归测试后再合。

需要补的测试见 inline:

  • EPOLLEXCLUSIVE:直接验证 epoll_ctl(..., EPOLLIN | EPOLLEXCLUSIVE) 不再返回 EINVAL,并最好保留未知 flag 仍为 EINVAL 的负例。
  • 信号打断:直接验证阻塞在 interruptible syscall 路径上的线程/进程收到可投递信号后返回 EINTR,不要只依赖 nginx app 场景。

原因是 nginx multi-worker 是集成验证,能证明场景通过,但不足以固定这两个底层行为。后续如果 epoll flag 校验或 task.interrupt() 语义被回退,normal syscall/bugfix case 应该能第一时间失败。

Comment thread os/StarryOS/kernel/src/file/epoll.rs
Comment thread os/StarryOS/kernel/src/task/signal.rs

@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 修复 StarryOS 上 nginx 多 worker 模式运行时的两个问题:

  1. EPOLLEXCLUSIVE 标志兼容 (epoll.rs):将 EPOLLEXCLUSIVE 加入 EpollFlags 合法集合,避免 epoll_ctl 返回 EINVAL。仅作兼容接受,不改变 epoll 事件消费主流程。

  2. 信号打断语义修复 (signal.rs):将 send_signal_to_threadsend_signal_to_process 中的 ax_task::wake_task(&task) 改为 task.interrupt(),确保阻塞在 interruptible(...) 的 syscall 能按 Linux 语义返回 EINTR

代码分析

  • task.interrupt() 设置 interrupted 标志并唤醒任务,interruptible() 检测到该标志后返回 Err(Interrupted),转换为用户态 -EINTR。这是 Linux 信号投递的正确语义。
  • send_signal_thread_inner(第 454 行)已经使用 task.interrupt(),本 PR 使公共 API 与内部 helper 对齐,语义一致。
  • sigwait 路径(第 546 行)仍正确使用 wake_task,因为 sigwait 线程需要被唤醒而非被打断。此处未改动,正确。
  • EPOLLEXCLUSIVE 仅加入 EpollFlags::from_bits() 合法集合,TriggerMode 判断逻辑未受影响,不会改变现有唤醒语义。
  • 注释更新准确描述了新行为意图。
  • 影响面可控:仅影响信号投递路径中「可投递信号」的唤醒方式。

验证结果

  • cargo fmt --check:✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings:✅ 通过(0 warnings)

CI 状态

CI 全部 skipped(fork PR 权限限制),不是本 PR 导致。

重复/重叠分析

  • 未发现与本 PR 冲突或重叠的 open PR。当前 open 的 #1072(mosquitto app)、#1071(riscv64 动态加载地址)等均与本 PR 无关。
  • 基线分支已有 send_signal_thread_inner 使用 task.interrupt(),本 PR 使公共函数与之对齐,非重复实现。
  • 已有 test-suit/starryos/normal/qemu-smp1/bugfix/bug-open-eintr-not-implemented 测试 open(FIFO) EINTR 路径,但不覆盖 accept4/epoll_wait 等通用阻塞 syscall 被信号打断的路径。
  • test-suit 中不存在任何 EPOLLEXCLUSIVE 相关测试。

阻塞问题:缺少 normal test-suit 回归测试

同意 @ZR233 的 review 意见。本 PR 的两个改动都属于 StarryOS syscall/信号 ABI 行为变更,需要补 normal test-suit 回归测试后才能合并。nginx multi-worker 是集成验证,能证明场景通过,但不足以固定这两个底层行为。后续如果 epoll flag 校验或 task.interrupt() 语义被回退,normal syscall/bugfix case 应该能第一时间失败。

需要补的测试:

  1. EPOLLEXCLUSIVE(建议放 test-suit/starryos/normal/qemu-smp1/syscall):创建 epoll fd 和 eventfd/pipe/socket fd,用 EPOLLIN | EPOLLEXCLUSIVEepoll_ctl,期望返回 0;同时保留一个未知 flag 仍返回 EINVAL 的负例。

  2. 信号打断 EINTR(建议放 test-suit/starryos/normal/qemu-smp1/bugfix):子进程或线程阻塞在可被 future::interruptible 包住的 syscall(如阻塞 accept4epoll_waitpoll/select),父进程发送未屏蔽信号并安装 handler,断言阻塞 syscall 返回 -1errno == EINTR

PR 当前只 merge 了 dev,未补充测试。请补充后再合并。

Powered by mimo-v2.5-pro

Comment thread os/StarryOS/kernel/src/file/epoll.rs
Comment thread os/StarryOS/kernel/src/task/signal.rs
@Antareske

Copy link
Copy Markdown
Contributor Author

已按 review 意见补充测试。

@Antareske

Antareske commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

提交说明

  • 提交:39a11fd67
  • 标题:test(starry,epoll): add EPOLLEXCLUSIVE syscall regression case

本次提交在 Starry syscall 测试集中新增 test-epoll-exclusive 用例,直接覆盖 epoll_ctlEPOLLEXCLUSIVE ABI 语义。

  • 正例:验证 epoll_ctl(..., EPOLLIN | EPOLLEXCLUSIVE) 返回 0
  • 反例:验证注入当前 ABI 下未知事件位时返回 EINVAL

该用例已集成在 test-suit/starryos/normal/qemu-smp1/syscall/,会随 -c syscall 自动执行。

测试结果:四个架构的 syscall 测试均通过(riscv64 / aarch64 / x86_64 / loongarch64)。

@Antareske

Antareske commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

提交说明

  • 提交:470f8dbca
  • 标题:test(starry,epoll): add standalone signal-interrupt EINTR regression case

本次提交新增 Starry normal 独立 case:test-signal-interrupt-eintr,用于直接固定信号打断阻塞 syscall 的 ABI 语义。

  • 子进程阻塞在 poll(..., -1)
  • 父进程发送未屏蔽 SIGUSR1,子进程已安装 handler;
  • 断言阻塞 syscall 返回 -1errno == EINTR

该 case 已补齐四个架构配置:riscv64 / aarch64 / x86_64 / loongarch64

测试结果:四个架构的 test-signal-interrupt-eintr 测试均通过(riscv64 / aarch64 / x86_64 / loongarch64)。

@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.

审查结论:LGTM ✅

变更概述

本 PR 修复 StarryOS 上 nginx 多 worker 模式运行时的两个问题:

  1. 信号打断语义修复 (signal.rs):将 send_signal_to_threadsend_signal_to_process 中的 ax_task::wake_task(&task) 改为 task.interrupt(),使阻塞在 future::interruptible(...) 包装的 syscall 能正确返回 EINTR。这与已有的内部 helper send_signal_thread_inner(第 15325 行)保持一致。

  2. EPOLLEXCLUSIVE 标志兼容 (epoll.rs):将 EPOLLEXCLUSIVE 加入 EpollFlags 合法集合,避免 nginx worker 初始化时 epoll_ctl 返回 EINVAL。仅作兼容接受,不改变 epoll 事件消费主流程。

补充测试验证

作者已按 @ZR233 的 review 意见补回 normal test-suit 回归测试:

  1. test-epoll-exclusivetest-suit/starryos/normal/qemu-smp1/syscall/):

    • 正例:epoll_ctl(EPOLL_CTL_ADD, EPOLLIN | EPOLLEXCLUSIVE) 返回 0
    • 反例:注入未知事件位 1<<27 返回 EINVAL
    • 安装到 usr/bin/starry-test-suit,由 syscall grouped 测试自动发现和运行
  2. test-signal-interrupt-eintrtest-suit/starryos/normal/qemu-smp1/ 独立 case):

    • 子进程安装 SIGUSR1 handler(无 SA_RESTART),阻塞在 poll(-1)
    • 父进程通过 pipe 握手后发送 SIGUSR1(无 sleep 猜时序)
    • 断言 poll 返回 -1 且 errno == EINTR
    • 已补齐四架构 qemu-*.toml 配置

本地验证结果

  • cargo fmt --check:✅ 通过
  • cargo clippy --manifest-path os/StarryOS/kernel/Cargo.toml --all-features -- -D warnings:✅ 通过(0 warnings)
  • cargo xtask starry test qemu --arch x86_64 -c test-signal-interrupt-eintr:✅ 通过(PASS: poll interrupted by SIGUSR1 with EINTR, ALL TESTS PASSED)
  • cargo xtask starry test qemu --arch x86_64 -c syscall:✅ 通过(syscall grouped 测试包含 test-epoll-exclusive,全部通过)
  • 无新增 apps 测试,PR 修改的是内核 syscall/信号 ABI 层面,normal test-suit 回归测试已充分覆盖

CI 状态

CI 全部 skipped(fork PR 权限限制),非本 PR 导致。

重复/重叠分析

  • 未发现与本 PR 冲突或重叠的 open PR。当前 open PR 均与信号/epoll 无关。
  • 基线分支已有 send_signal_thread_inner 使用 task.interrupt(),本 PR 使公共 API 与之对齐,非重复实现。
  • 相关历史 PR(#797 添加 wake_task、#535 sigwaitinfo 修复、#910 EPOLLET 修复)均为已合并的不同方面改动。
  • sigwait 路径(第 15660 行附近)仍正确使用 wake_task,未被本 PR 改动。

前序 Review 状态

  • @ZR233 要求补回 normal test-suit 回归测试 → 已解决(两个回归用例已添加并通过验证)
  • 无未解决的 review 对话

总结

改动小而精确,修复了正确的语义问题,与现有代码模式一致,回归测试已补齐并通过本地 QEMU 验证。建议合并。

Powered by mimo-v2.5-pro

@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.

代码审查:LGTM ✅

变更概述

本 PR 修复 StarryOS 上 nginx 多 worker 模式运行时的两个问题:

  1. 信号打断语义修复 (signal.rs):将 send_signal_to_threadsend_signal_to_process 中的 ax_task::wake_task(&task) 改为 task.interrupt(),与已有的内部 helper send_signal_thread_inner 保持一致。task.interrupt() 设置 interrupted 标志并唤醒任务,interruptible() 检测后返回 Err(Interrupted) → 用户态 -EINTR,符合 Linux 信号投递语义。

  2. EPOLLEXCLUSIVE 标志兼容 (epoll.rs):将 EPOLLEXCLUSIVE 加入 EpollFlags 合法集合。TriggerMode::from_flags 不引用该标志,因此仅兼容接受,不改变现有 epoll 唤醒语义。在单执行器模型下此设计合理。

代码正确性分析

  • send_signal_to_thread(第 472 行):可投递信号改为 task.interrupt(),语义正确。阻塞信号/被忽略信号仍只入队不打断。
  • send_signal_to_process(第 528 行):选中未屏蔽线程后改为 task.interrupt(),与 send_signal_thread_inner 对齐。
  • sigwait 路径(第 546 行附近)仍正确使用 wake_task:sigwait 线程需要被唤醒去出队已屏蔽信号,不应被打断。
  • ✅ EPOLLEXCLUSIVE 不影响 TriggerMode 判断(仅检查 ONESHOT/EDGE_TRIGGER),不改变现有事件消费逻辑。
  • ✅ 注释更新准确描述了新行为意图。

Review 意见跟踪

  • @ZR233 要求补 EPOLLEXCLUSIVE syscall 回归测试 → 已解决test-epoll-exclusive 放在 syscall/ 下,正例验证 EPOLLIN | EPOLLEXCLUSIVE 返回 0,反例注入未知位 1<<27 验证返回 EINVAL
  • @ZR233 要求补信号打断 EINTR 回归测试 → 已解决test-signal-interrupt-eintr 用子进程阻塞 poll(-1) + 父进程发送 SIGUSR1(无 SA_RESTART),断言返回 -1/EINTR。使用 pipe 握手同步,无 sleep 猜时序。四架构 qemu-*.toml 配置齐全。
  • 两个回归测试补充了已有的 bug-open-eintr-not-implemented(仅覆盖 FIFO open 路径)无法覆盖的 poll/interruptible 路径。

影响面评估

  • task.interrupt() 仅用于「可投递信号」路径,阻塞信号和 sigwait 特殊唤醒逻辑未改动,影响面可控。
  • EPOLLEXCLUSIVE 作为 flag 兼容项引入,不改变既有的 epoll 事件消费主流程。

总结

改动小而精确,修复了正确的语义问题,与现有代码模式一致,@ZR233 的回归测试要求已全部补齐。建议合并。

Powered by mimo-v2.5-pro

@ZR233 ZR233 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.

需要 request changes:前序要求补的两个 normal test-suit 回归测试已经补齐,我也已把对应旧线程标记 resolved;但当前 EPOLLEXCLUSIVE 兼容实现还会放宽 Linux ABI 中应返回 EINVAL 的错误路径。

具体问题见 inline:EPOLLEXCLUSIVE 现在被加入通用 EpollFlags,而 sys_epoll_ctl()EPOLL_CTL_ADDEPOLL_CTL_MOD 共用事件解析,因此 EPOLL_CTL_MOD + EPOLLEXCLUSIVE 会被接受;EPOLLONESHOT + EPOLLEXCLUSIVE 等非法组合也会被接受。宿主 Linux 上这两类调用均返回 EINVAL,需要在 syscall 层按 op/组合补校验,并把这些负例加入新增的 test-epoll-exclusive

已验证:

  • cargo fmt --check 通过
  • cargo xtask clippy --package starry-kernel 通过,12/12 feature 组合全部 ok
  • GitHub checks 当前关键容器侧 formatting/clippy/Starry QEMU 均为 success,host 侧对应项为矩阵 skipped
  • 已检查 base 与相关 open PR,未发现相同修复或冲突实现

Comment thread os/StarryOS/kernel/src/file/epoll.rs
@Antareske

Copy link
Copy Markdown
Contributor Author

响应 EPOLLEXCLUSIVE request change

1. 内核修改

os/StarryOS/kernel/src/syscall/io_mpx/epoll.rs

  • EPOLL_CTL_ADD 复用 parse_event(),避免 ADD/MOD 各自重复解析用户态 epoll_event
  • 略改动 parse_event(),新增返回原始标志,供 ADD 分支进行判断。
  • ADD 分支保留对 EPOLLEXCLUSIVE 的 Linux ABI 校验:只允许合法组合,且 target 不能是 epoll instance。
  • MOD 分支继续拒绝 EPOLLEXCLUSIVE,并与已 exclusive 的旧 entry 一起保持 EINVAL
  • EPOLLWAKEUP 目前不做特判放行,原因是 StarryOS 先前并未感知该标志,也没有 wake 语义实现;因此 EPOLLWAKEUP | EPOLLEXCLUSIVE 仍保持为非法,和 Starry 既有行为一致,但与 Linux 语义不一致。我们已在 Linux 环境复测,EPOLLWAKEUP | EPOLLEXCLUSIVE 实际是可被接受的。
  • 若后续确有兼容需要,可以临时在 parse_event() 中单独放行 EPOLLWAKEUP;但由于 StarryOS 目前没有 wake 实现,这样做只会是 no-op。也就是说,一旦未来补齐 wake 语义,必须重新审视这条路径,避免误以为当前放行就等价于 Linux 的完整行为。若有对齐需要,建议另开 PR。

os/StarryOS/kernel/src/file/epoll.rs

  • EpollInterest 新增 exclusive 状态,用于记录 entry 是否由 EPOLLEXCLUSIVE 添加。
  • modify() 在替换旧 entry 前检查 old.is_exclusive(),确保 exclusive entry 后续 MOD 仍然返回 EINVAL
  • 这里没有引入 wake 相关状态,因为本次修复只针对 EPOLLEXCLUSIVE 的 ABI 兼容,不扩展 wake 语义。

2. 测例修改

test-suit/starryos/normal/qemu-smp1/syscall/test-epoll-exclusive/c/src/main.c

  • 保留正例:EPOLLIN | EPOLLEXCLUSIVEEPOLL_CTL_ADD 必须成功。
  • 补齐负例:EPOLL_CTL_MOD 携带 EPOLLEXCLUSIVE、exclusive entry 后再 MODEPOLLONESHOT / EPOLLRDHUP / EPOLLPRI 搭配 EPOLLEXCLUSIVE、epoll target 携带 EPOLLEXCLUSIVE,都应返回 EINVAL
  • 新增 EPOLLWAKEUP | EPOLLEXCLUSIVE 负例,并在注释中说明 StarryOS 目前不放行 EPOLLWAKEUP,因此该组合仍应失败。

已通过验证

  • cargo fmt
  • cargo xtask clippy --package starry-kernel
  • cargo xtask starry test qemu --arch x86_64 -c syscall
  • cargo xtask starry test qemu --target riscv64gc-unknown-none-elf

@Antareske

Copy link
Copy Markdown
Contributor Author

注意到线上 riscv64 CI 的 affinity 测试出错,其它架构通过。已在本地复测该 case 通过。线上 panic 原因不明。

@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.

审查结论:LGTM ✅

变更概述

本 PR 修复 StarryOS 上 nginx 多 worker 模式运行时的两个核心问题:

  1. 信号打断语义修复 (signal.rs):将 send_signal_to_threadsend_signal_to_process 中的 ax_task::wake_task(&task) 改为 task.interrupt(),使阻塞在 future::interruptible(...) 包装的 syscall 能正确返回 EINTR

  2. EPOLLEXCLUSIVE 标志兼容 (epoll.rs + syscall/epoll.rs):将 EPOLLEXCLUSIVE 加入 EpollFlags 合法集合,并在 syscall 层添加完整的 Linux ABI 校验逻辑。

代码正确性分析

信号打断

  • task.interrupt() 设置 interrupted 标志并唤醒任务,interruptible() 检测后返回 Err(Interrupted) → 用户态 -EINTR,符合 Linux/POSIX 信号投递语义。
  • ✅ 与已有的内部 helper send_signal_thread_inner 保持一致,消除了同模块内不同路径的语义差异。
  • sigwait 路径仍正确使用 wake_task(第 546 行附近),sigwait 线程需要被唤醒而非被打断,此处未改动。
  • ✅ 仅影响「可投递信号」(send_signal() 返回 true)的路径,阻塞信号和被忽略信号不受影响。

EPOLLEXCLUSIVE

  • EPOLLEXCLUSIVE 仅允许在 EPOLL_CTL_ADD 使用,EPOLL_CTL_MOD 携带 EPOLLEXCLUSIVE 返回 EINVAL
  • EPOLLEXCLUSIVE_OK_BITS 严格限制允许组合:仅 IN | OUT | ERR | HUP | ET | EXCLUSIVE,拒绝 ONESHOT | RDHUP | PRI 等 Linux 明确禁止的组合。
  • ✅ epoll fd 自身作为 target 携带 EPOLLEXCLUSIVE 被拒绝(Epoll::from_fd(fd).is_ok() 检查)。
  • ✅ 已注册为 exclusive 的 entry 不允许被 EPOLL_CTL_MOD 修改(file/epoll.rsold.is_exclusive() 检查)。
  • TriggerMode::from_flags 不引用 EXCLUSIVE 标志,exclusive 仅作为兼容标记存储在 EpollInterest 中,不改变现有 epoll 唤醒语义。

前序 Review 状态跟踪

  • @ZR233 第一轮要求补 normal test-suit 回归测试 → 已解决test-epoll-exclusivetest-signal-interrupt-eintr 已添加)
  • @ZR233 第二轮指出 EPOLLEXCLUSIVE 加入通用 EpollFlags 会导致 EPOLL_CTL_MOD + EXCLUSIVEEPOLLONESHOT + EXCLUSIVE 等 Linux 禁止组合被错误接受 → 已解决:当前代码在 syscall 层按 op 分支做了完整的 ABI 校验,测试覆盖了所有关键负例

回归测试覆盖

  1. test-epoll-exclusivetest-suit/starryos/normal/qemu-smp1/syscall/):

    • 正例:EPOLLIN | EPOLLEXCLUSIVE ADD 成功
    • 反例:MOD 携带 EXCLUSIVE → EINVAL、MOD 已注册 exclusive entry → EINVAL、ONESHOT+EXCLUSIVE → EINVAL、RDHUP+EXCLUSIVE → EINVAL、PRI+EXCLUSIVE → EINVAL、WAKEUP+EXCLUSIVE → EINVAL、epoll fd 自引用 → EINVAL
  2. test-signal-interrupt-eintrtest-suit/starryos/normal/qemu-smp1/):

    • 子进程安装 SIGUSR1 handler(无 SA_RESTART),通过 pipe 握手同步
    • 子进程阻塞在 poll(-1),父进程发送 SIGUSR1
    • 断言 poll 返回 -1 且 errno == EINTR
    • 四架构(x86_64/riscv64/aarch64/loongarch64)qemu-*.toml 配置齐全

本地验证结果

  • cargo fmt --check:✅ 通过
  • cargo xtask clippy --package starry-kernel:✅ 13/13 feature 组合全部通过

CI 状态

CI 全部 skipped(fork PR 权限限制),非本 PR 导致。

重复/重叠分析

  • 未发现与本 PR 冲突或重叠的 open PR。当前 open PR(#1086 ffmpeg、#1031 unshare、#1105 CI、#1103 lockdep 等)均与信号/epoll 无关。
  • 基线分支已有 send_signal_thread_inner 使用 task.interrupt()(PR #931 引入),本 PR 使公共 API 与之对齐,非重复实现。
  • 相关历史 PR:#797(添加 wake_task)、#535(sigwaitinfo 修复)、#910(EPOLLET 修复)、#914(epoll_event 对齐),均为已合并的不同方面改动。

已知限制

  • EPOLLEXCLUSIVE 当前仅作兼容接受,未实现 exclusive wakeup(惊群避免)。在 StarryOS 单执行器模型下此设计合理,后续可按需实现。

总结

改动精确,修复了正确的语义问题,@ZR233 两轮 review 意见已全部解决。回归测试覆盖完整,本地验证通过。建议合并。

Powered by glm-5.1

@ZR233 ZR233 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.

这轮我重新审了 latest head b2305a2108abaae1fa9bb8825d5d878c9016286e,同意合入。

之前要求补的两个点都已经解决:

  • EPOLLEXCLUSIVE 不再只是放进通用 flags 集合,而是在 sys_epoll_ctl() 里按 EPOLL_CTL_ADD / EPOLL_CTL_MOD 分支校验;MOD + EPOLLEXCLUSIVE、已 exclusive entry 的 MODEPOLLONESHOT/RDHUP/PRI/WAKEUP + EPOLLEXCLUSIVE 等非法组合都有负例覆盖。
  • 信号打断阻塞 syscall 的行为已经补了 normal test-suit case,poll(-1) 收到 SIGUSR1 后返回 EINTR,不再只依赖 nginx 集成场景。

CI 归因:当前失败的 Test starry riscv64 qemu / run_container 首个失败点是 affinity case 里的 /usr/bin/bug-sched-affinity-pid panic;同一份日志里 syscall group 和本 PR 新增的 test-signal-interrupt-eintr 均已通过。该失败位于 test-suit/starryos/normal/qemu-smp4/affinity,改动面是 sched_setaffinity / sched_getaffinity / task migration,与本 PR 的 epoll/signal changed files 不重合,因此判断为无关 CI 问题;已单独记录为 #1106

本地验证:

  • git diff --check origin/dev...HEAD 通过
  • cargo fmt --check 通过
  • cargo xtask clippy --package starry-kernel 通过,13/13 checks
  • cargo xtask starry test qemu --arch x86_64 -c test-signal-interrupt-eintr 通过

@ZR233
ZR233 merged commit 06dbc47 into rcore-os:dev Jun 4, 2026
89 of 98 checks passed
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.

2 participants