diff --git a/VKernel/Kernel/sched/sched.vp b/VKernel/Kernel/sched/sched.vp index 88a5fe3..033c0d7 100644 --- a/VKernel/Kernel/sched/sched.vp +++ b/VKernel/Kernel/sched/sched.vp @@ -249,12 +249,20 @@ class Scheduler: @staticmethod def exit_current_thread(): - """用户线程显式退出(THREAD_EXIT):回收资源 → 标记 DONE → 让出,永不返回。""" + """用户线程显式退出(THREAD_EXIT):标记 DONE → 回收资源 → 让出,永不返回。 + + 次序很重要:**先**置 THREAD_DONE,**再** free_user_thread。反过来的话,在 + "已释放用户栈/上下文、但 state 还是 RUNNING" 这段窗口里只要发生一次再调度 + (定时器 IRQ → try_reschedule → _yield 的选择只按 state 过滤),本线程就会被 + 再次选中并带着失效上下文回到用户态 ⇒ 在已回收的栈上取指 0: + 现场 [0E] rip=0x0 err=0x15(用户态取指缺页)cr2=0x0 rsp=0x7fffffde0000,tid 为该 app 线程, + 紧跟在 [syscall] exit called 之后。 + """ s: Scheduler* = _sched_ptr tid: int = s.current_tid - proc.free_user_thread(proc.find_user_slot_by_tid(tid)) if tid > 0 and tid < MAX_THREADS: s.threads[tid].state = THREAD_DONE + proc.free_user_thread(proc.find_user_slot_by_tid(tid)) Scheduler._yield() # _yield 可能因"只有自己可运行"而直接返回:此后绝不能再跑用户代码(栈已回收)。 while True: