Linux-6.0.19自定义调度器僵死进程处理问题求助
Linux 6.0.19 调度器处理僵死任务的核心流程
1. 进程终止时的状态切换与出队触发
进程终止进入do_exit()流程的最后阶段,会通过set_task_state(current, TASK_DEAD)将自身状态标记为TASK_DEAD,随后调用schedule()触发调度切换。
此时内核进入核心调度逻辑__schedule(),在该函数中会检查被切换出去的进程(prev)的状态:如果prev->__state不是TASK_RUNNING(这里就是TASK_DEAD),且不属于抢占场景,就会执行以下操作:
dequeue_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK); prev->on_rq = 0;
这一步就是把僵死进程从调度器对应的运行队列中彻底移除,dequeue_task会调用你自定义调度器类中实现的出队逻辑(比如CFS的dequeue_task_fair)。
2. 调度器接口函数的角色
pick_next_task_my_sched:仅负责从运行队列中挑选下一个要执行的任务,不会处理僵死任务的出队——因为僵死任务已经在__schedule()阶段被移出队列了。put_prev_task_my_sched:主要用于保存当前任务切换前的调度状态(比如CFS会更新任务的vruntime),同样不负责僵死任务的出队逻辑。
3. finish_task_switch中的收尾处理
在切换到新任务之后,finish_task_switch()会处理被替换下来的僵死进程,对应代码位于/kernel/sched/core.c中:
if (prev->__state == TASK_DEAD) { if (prev->sched_class->task_dead) prev->sched_class->task_dead(rq, prev); release_task(prev); }
这里的关键逻辑:
- 如果你的自定义调度器类实现了
task_dead回调,内核会先调用它,用于清理调度器私有的队列结构(比如释放你为任务分配的调度器特定数据)。 - 随后调用
release_task()完成进程资源的最终回收(比如释放PID、信号资源等)。
自定义调度器的避坑提示
你遇到的空指针问题,大概率是因为:
- 僵死进程被标记为
TASK_DEAD后,仍未从你的自定义运行队列中正确移除,导致后续pick_next_task或其他操作访问了已失效的任务指针。 - 未正确实现
dequeue_task回调,处理TASK_DEAD任务时出现指针访问错误。 - 未实现
task_dead回调,导致调度器私有资源未被及时释放,引发野指针问题。
内容的提问来源于stack exchange,提问作者Abhishek Ghosh
相关产品推荐
相关产品推荐

