fix(sched): sched_yield 改为无条件切换,原实现只在时间片到期时才切
现场:app 用 4000 次 yield_cpu() 等 /dev/desk ready(explorer 负责 format 并置 ready=1),却全部超时——三个 app 都打出 [win] desk not ready (attach timeout) / create_window: connect FAILED / geometry win_id=-1,最后静默退出;而 explorer 的 [elf] wrapper pid=5 出现在所有 app 退完之后。根因:YIELD syscall 走 sched.Scheduler.try_reschedule(),而它只在 needs_reschedule(时间片到期,由 tick 置位)时才真正 _yield(),因此 N 次 sched_yield 全落在同一个时间片内一次都不切换 ⇒ 主动等待外设的进程被饿死、初始化者永远轮不上。修法:新增 Scheduler.yield_now() 无条件切换,YIELD 分支改用它;try_reschedule() 仍保留给中断/抢占路径使用。
This commit is contained in:
1 parent
2f20cf42aa
commit
453c353e01
2 files changed
+15
-1
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user