1.2.1 进程属性:关键元素
进程属性定义了一个进程的所有关键特征和基本特征。这些元素包含进程的状态和标识以及其他重要的键值。
1.状态
一个进程从其产生之时起直至退出就一直处于不同的状态中,称为进程状态——它们定义了进程的当前状态。
● TASK_RUNNING (0):任务正在执行或在调度器运行队列中争抢CPU。
● TASK_INTERRUPTIBLE (1):任务处于可中断的等待状态;它仍然处于等待状态,直到所等待的条件变为真,例如互斥锁可用、I/O准备好的设备、睡眠时间超时,或者是一个专属的唤醒调用。在这个等待状态中,为进程生成的任何信号都被传递,使得等待条件被满足前唤醒进程。
● TASK_KILLABLE:这与TASK_INTERRUPTIBLE类似,不同之处在于中断只能发生在致命信号上,这使它成为TASK_INTERRUPTIBLE以外更好的选择。
● TASK_UNINTERRUPTIBLE (2):任务处于不可中断的等待状态,类似于TASK_ INTERRUPTIBLE,但是产生信号给这种睡眠进程不会导致其被唤醒。当它正在等待的事件发生时,进程才转换为TASK_RUNNING状态。该进程状态很少使用。
● TASK_STOPPED (4):该任务已经收到停止(STOP)信号。在接收到继续信号(SIGCONT)后,它会回到运行状态。
● TASK_TRACED (8):当一个进程可能正在被一个调试器仔细检查,便可认为它处于跟踪状态。
● EXIT_ZOMBIE (32):该进程已经被终止,但它的资源尚未回收。
● EXIT_DEAD (16):父进程使用wait方法收集子进程的退出状态后,子进程将终止,并且释放它所持有的所有资源。
图1-5描述了进程状态。
图1-5
2.pid
该字段保存了进程唯一的标识符,称为 PID。Linux中的PID是pid_t(整数)类型。虽然PID是一个整数,但通过/proc/sys/kernel/pid_max接口指定的默认最大值只有32 768。该文件中的值可以设置为任何值,最高可达222(PID_MAX_LIMIT,约为400万)。
为了管理 PID,内核使用了位图。该位图允许内核跟踪PID的使用情况,并且可以为新进程分配唯一的PID。每个PID都是由PID位图中的一个位来标识的;PID的值是根据其对应位的位置来确定的。在位图中,值为1的位表示正在使用相应的PID,值为0的位表示空闲的PID。每当内核需要分配一个唯一的PID时,它就会查找第一个未被设置的位并将其设置为1,相反地,释放一个PID时,它会将相应的位从1设置为0。
3.tgid
该字段保存了线程组id。为了便于理解,假设创建了一个新进程,它的PID和TGID是相同的,因为进程恰好是唯一的线程。当进程产生一个新的线程时,新的子进程将获得唯一的PID,但是继承了父线程的TGID,因为它属于同一个线程组。TGID主要用于支持多线程进程。我们将在本章后面的线程部分深入了解。
4.thread info
该字段保存了处理器特定的状态信息,并且它是任务结构体的关键元素。本章后文会包含有关thread_info的重要细节。
5.flags
该标志字段记录了进程相应的各种属性。该字段中的每一位对应于一个进程生命周期中的各个阶段。每个进程标志定义在<linux/sched.h>中。
#define PF_EXITING /* getting shut down */
#define PF_EXITPIDONE /* pi exit done on shut down */
#define PF_VCPU /* I'm a virtual CPU */
#define PF_WQ_WORKER /* I'm a workqueue worker */
#define PF_FORKNOEXEC /* forked but didn't exec */
#define PF_MCE_PROCESS /* process policy on mce errors */
#define PF_SUPERPRIV /* used super-user privileges */
#define PF_DUMPCORE /* dumped core */
#define PF_SIGNALED /* killed by a signal */
#define PF_MEMALLOC /* Allocating memory */
#define PF_NPROC_EXCEEDED /* set_user noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH /* if unset the fpu must be initialized before use */
#define PF_USED_ASYNC /* used async_schedule*(), used by module init */
#define PF_NOFREEZE /* this thread should not be frozen */
#define PF_FROZEN /* frozen for system suspend */
#define PF_FSTRANS /* inside a filesystem transaction */
#define PF_KSWAPD /* I am kswapd */
#define PF_MEMALLOC_NOIO0 /* Allocating memory without IO involved */
#define PF_LESS_THROTTLE /* Throttle me less: I clean memory */
#define PF_KTHREAD /* I am a kernel thread */
#define PF_RANDOMIZE /* randomize virtual address space */
#define PF_SWAPWRITE /* Allowed to write to swap */
#define PF_NO_SETAFFINITY /* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY /* Early kill for mce process policy */
#define PF_MUTEX_TESTER /* Thread belongs to the rt mutex tester */
#define PF_FREEZER_SKIP /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK /* this thread called freeze_processes and should not be
frozen */
6.exit_code和exit_signal
这些字段保存了任务的退出值和导致终止的信号的详细信息。这些字段将由父进程在子进程终止时通过wait()访问。
7.comm
该字段保存了用于启动进程的二进制可执行文件的名称。
8.ptrace
当使用ptrace()系统调用使进程转为跟踪模式时,将启用并设置该字段。