diff --git a/VKernel/Kernel/intr/syscall.vp b/VKernel/Kernel/intr/syscall.vp index 09076b0..e94ff15 100644 --- a/VKernel/Kernel/intr/syscall.vp +++ b/VKernel/Kernel/intr/syscall.vp @@ -463,7 +463,9 @@ export def syscall_handler(num: uint64, arg1: uint64, arg2: uint64, arg3: uint64 elif n == int(Syscall.GETPID): return GETPID() elif n == int(Syscall.YIELD): - sched.Scheduler.try_reschedule() + # sched_yield 是"主动放弃剩余时间片",必须无条件切换;try_reschedule() 只在 + # 时间片到期时才切,作为 syscall 会让等待外设的进程白等(见 Scheduler.yield_now 注释)。 + sched.Scheduler.yield_now() return 0 elif n == int(Syscall.SPAWN): path_ptr_sp: rawptr = rawptr(arg1) diff --git a/VKernel/Kernel/sched/sched.vp b/VKernel/Kernel/sched/sched.vp index 033c0d7..4440b67 100644 --- a/VKernel/Kernel/sched/sched.vp +++ b/VKernel/Kernel/sched/sched.vp @@ -169,6 +169,18 @@ class Scheduler: s.needs_reschedule = 0 Scheduler._yield() + @staticmethod + def yield_now(): + """显式让出 CPU:**无条件**切换。 + + 与 try_reschedule() 的区别很关键:后者只在 needs_reschedule(时间片到期)时切换, + 那是"抢占式调度器在中断里做的判断"。而 sched_yield 的语义是"我主动放弃剩余时间片", + 必须立刻切走 —— 否则主动等待外设的进程会白等:它的 N 次 yield 全落在同一个时间片内、 + 一次都不切换。现场:app 用 4000 次 yield_cpu() 等 /dev/desk ready,全部超时退出, + 而 explorer(共享区初始化者)直到所有 app 退完才被调度 ⇒ 建窗全失败 ⇒ 静默退出。 + """ + Scheduler._yield() + @staticmethod def disable(): s: Scheduler* = _sched_ptr