Skip to the content.

jobctl

我在分析 signal 的时候,观察到这些字段:

task->jobctl

#define JOBCTL_STOP_DEQUEUED	(1UL << JOBCTL_STOP_DEQUEUED_BIT)
#define JOBCTL_STOP_PENDING	(1UL << JOBCTL_STOP_PENDING_BIT)
#define JOBCTL_STOP_CONSUME	(1UL << JOBCTL_STOP_CONSUME_BIT)
#define JOBCTL_TRAP_STOP	(1UL << JOBCTL_TRAP_STOP_BIT)
#define JOBCTL_TRAP_NOTIFY	(1UL << JOBCTL_TRAP_NOTIFY_BIT)
#define JOBCTL_TRAPPING		(1UL << JOBCTL_TRAPPING_BIT)
#define JOBCTL_LISTENING	(1UL << JOBCTL_LISTENING_BIT)
#define JOBCTL_TRAP_FREEZE	(1UL << JOBCTL_TRAP_FREEZE_BIT)
#define JOBCTL_PTRACE_FROZEN	(1UL << JOBCTL_PTRACE_FROZEN_BIT)

结合 codex 的分析,简单来说就是,当 thread 被 pstrace 的时候,有一系列的状态变化, 这些状态就是记录在 task->jobctl 中的

codex 的分析

第一层是用户语义:shell 需要管理“作业”。

例如:

sleep 100 cat

这不是一个进程,而是一组进程。用户按 Ctrl-Z,shell 期望整个 pipeline 停住;执行 fg,整个 pipeline 回到前台;执行 bg,整个 pipeline 继续后台跑。这个语义靠单个 task 的普通 signal pending 状态表达不了,所以 Unix 抽象出了:

这就是 POSIX job control 解决的问题:shell/终端以“进程组/作业”为单位管理前台、后台、停止、 继续。

第二层是 Linux 内核实现:task->jobctl 解决“停止/陷入/继续”这类状态机不好塞进普通信号或调度状态的问题。

普通信号机制只回答“某个 signal 是否 pending”。调度状态只回答“这个 task 当前能不能运行”。但 job control 需要更多信息,比如:

所以 jobctl 不是给用户态直接用的接口,而是内核用来维护这些复杂语义的状态字。

核心原因是:“停止一个任务”不是简单地把 task state 设成 stopped。它还涉及:

因此可以这样理解:

job control 是用户可见的作业管理语义; task->jobctl 是内核为了正确实现这种语义,以及复用类似“让任务进入受控停止点”的机制,而维护 的一组内部状态位。

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。