fix(loongarch64): ack timer irq before dispatch#1222
Conversation
There was a problem hiding this comment.
审查结论:变更正确,已合并
该 PR 已在审查前被合并至 dev 分支,以下为事后审查意见。
变更内容
PR 修复了 LoongArch 平台 one-shot timer IRQ 处理中的竞态条件:timer IRQ 的中断应答(TICLR 清除 / someboot::timer::ack())原在 dispatch_irq() / _handle_irq() 之后执行,而 dispatch 路径会重新编程下一次 one-shot 定时器事件。当新事件 deadline 很近时,late acknowledge 可能将刚 arm 的 pending 中断也一并清除,导致依赖 timer 的 sleep 任务永远无法被唤醒,表现为 usleep/nanosleep 后概率性 hang。
修改将 timer IRQ 应答移至 dispatch 之前,确保只清除当前中断,不会误伤 dispatch 期间新 arm 的事件。
涉及三个文件:
platforms/ax-plat-loongarch64-qemu-virt/src/irq.rs:静态平台,ticlr::clear_timer_interrupt()移到 dispatch 前,并用 match 分支替代原来分离的 else/match 结构platforms/somehal/src/arch/loongarch64/mod.rs:动态平台,someboot::timer::ack()移到_handle_irq()前.claude/skills/arch-platform-porting/SKILL.md:归档排查规则
实现逻辑评估
one-shot timer 先 ack 再 dispatch 是标准实践。Linux 内核 timer 驱动同样遵循此顺序。LoongArch 手册中 TICLR 为写 1 清 0 寄存器,对当前 pending 位操作,不会影响后续新产生的中断——但前提是 ack 在 dispatch/rearm 之前完成。本次修改正确。
静态平台的 handle() 重构同时消除了原 else 分支中 Timer 未做特殊处理的潜在问题(原代码 Timer 走通用 dispatch 路径但缺少 ack),新 match 结构使每种 IRQ 类型的处理路径清晰可见。
CI 状态
CI workflow 结论为 success。关键 job 均通过:
- Check formatting / run_host: success
- Run sync-lint / run_container: success(含 fmt + clippy)
- Run clippy / run_host: success
- Test arceos loongarch64 qemu / run_host: success(覆盖变更的静态平台)
- 其他架构测试(x86_64, aarch64, riscv64)因路径过滤被 skip,符合预期
部分 check runs 显示 conclusion: skipped 是 CI 矩阵中 run_host/run_container 互斥和路径过滤的正常行为,不是 CI 缺失。
重复/重叠分析
- base 分支 (
dev) 中不存在等效修复 - 搜索
repo:rcore-os/tgoskits type:pr state:open loongarch timer返回 PR #1207(AxVisor LoongArch guest 支持)和 PR #1150(IRQ binding 重构),均不与此 timer ack 修复重叠 - 无冲突或重复
总结
修复逻辑正确,CI 全部通过,无重复或重叠。虽然 PR 已合并,但从代码审查角度应予以通过。
Powered by deepseek-v4-pro
问题
starry test qemu --arch loongarch64在 CI 中概率性超时,最近失败点出现在 signal 相关 system tests 中,例如test-pidfd-send-signal和test-rt_sigpending。继续对比日志后发现,卡住点并不固定在某个 signal syscall,而是共同发生在 signal 操作后进入usleep/nanosleep等 timer-based sleep 后不再被唤醒。修改
_handle_irq()。ax-plat-loongarch64-qemu-virt的 timer IRQ 处理顺序:先清TICLR,再 dispatch timer IRQ。逻辑
LoongArch timer 当前作为 one-shot timer 使用。timer IRQ dispatch 路径会重新 arm 下一次 timer event。如果在 dispatch 之后才清
TICLR,当下一次 near-deadline event 已经变为 pending 时,这个 late acknowledge 可能把新事件也清掉,导致等待 timer 的任务无法再被唤醒,从而表现为概率性 hang。因此 timer IRQ 需要先清掉本次 interrupt,再进入会重新编程下一次 one-shot timer 的 dispatch 路径。这样不会把 dispatch 期间新 arm 出来的 pending timer event 清掉。
验证
cargo fmt --all -- --checkcargo xtask clippy --package somehalcargo xtask clippy --package ax-plat-loongarch64-qemu-virtcargo xtask starry test qemu --arch loongarch64 -c qemu-smp1/system/syscall-test-rt_sigpending,顺序压力 5 次通过cargo xtask starry test qemu --arch loongarch64 -c qemu-smp1/system/syscall-test-pidfd-send-signal,顺序压力 5 次通过cargo xtask starry test qemu --arch loongarch64,qemu-smp1/system和qemu-smp4/system均通过