Skip to content

调度器死锁:fork 后所有任务睡眠、CPU0 卡 idle、CPU1 卡 pick_next_task(lmbench 全量 5/5 复现) #2167

Description

@mistcoversmyeyes

现象

在 QEMU+KVM guest 上跑 lmbench 全量测试(AUTO_TEST=benchmark,runner/run.sh),init.sh 完成后、run.sh 第一个 fork 处死锁

  • 串口在 lmbench test environment initialized 后完全静默(run.sh 卡在 ENOUGH 预计算的 timeout ... enough 命令替换的 fork 上)
  • 用户态所有任务睡眠,无任何输出;600s 无输出被 monitor 判卡死
  • 连续复现 5/5;另有一次完整跑完 47 指标(竞争窗口未触发),说明是时序敏感的偶发死锁,不是必然

复现

# 分支 feat/lmbench @ 671b7580(QEMU 2 vCPU / 2G 内存)
make qemu-nographic AUTO_TEST=benchmark BENCHMARK_TEST_DIR=/opt/tests/benchmark/lmbench
# 等待 ~2-3 分钟 boot + init,之后串口无输出即复现

gdb 现场(QEMU -gdb attach)

CPU0(RIP 0xffff800000171856,arch_idle_func 内):

call  rcu::exit_idle
lock  decq (%rbx)
jne   arch_idle_func+64     ; 计数不为 0 则循环
...
call  Arc<ProcessControlBlock>::drop_slow

CPU0 不在正常 halt idle(正常 x86::halt() 时 QEMU CPU 应接近 0%,实测 QEMU 占用 ~140%),疑似走了 idle.rsIRQ 禁用分支 spin_loop()

CPU1:

#0 current_cpu_id
#4 <CompletelyFairScheduler as Scheduler>::pick_next_task

CPU1 卡在调度器选择路径。

初步分析

  • 卡点与用户态 fork(sys_fork → 调度器插入任务 → pick_next_task)强相关
  • kernel/src/arch/x86_64/process/idle.rs:26-28:IRQ 禁用时 idle 进入 spin_loop() 忙转——CPU0 的状态与"中断被关掉/时钟 tick 丢失"一致
  • kernel/src/sched/fair.rs:1704 pick_next_task:EEVDF 选择路径卡住
  • 怀疑方向:fork 路径上某处关中断后未恢复 / 调度器锁竞争 / idle 退出计数(RCU exit_idle)不归零导致 wakeup 丢失

影响

lmbench 全量基准无法稳定运行(第一个 fork 就可能死锁),同时解释了此前 process_fork_lat 偶发超时(rc=124)现象。

环境

  • QEMU 8.x + KVM(WSL2 / Linux 6.6 host)
  • 2 vCPU(q35, hpet=off),2G 内存,virtio-blk,user-mode NAT
  • DragonOS feat/lmbench @ 671b758(kernel.elf 编译于 7/31)

关联PR、Issue

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions