进程是处于执行期的程序以及它所管理的资源(如打开的文件、挂起的信号、进程状态、地址空间等等)的总称
Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息。它定义在include/linux/sched.h文件中。
这个结构体中包含了很多的信息,下面就让我们来一一简单的看看这些结构体内容,对进程描述符有一个基本的理解。
进程状态
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
state成员的可能取值如下
/*
* Task state bitmask. NOTE! These bits are also
* encoded in fs/proc/array.c: get_task_state().
*
* We have two separate sets of flags: task->state
* is about runnability, while task->exit_state are
* about the task exiting. Confusing, but this way
* modifying one set can't modify the other one by
* mistake.
*/
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define __TASK_STOPPED 4
#define __TASK_TRACED 8
/* in tsk->exit_state */
#define EXIT_DEAD 16
#define EXIT_ZOMBIE 32
#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
/* in tsk->state again */
#define TASK_DEAD 64
#define TASK_WAKEKILL 128 /** wake on signals that are deadly **/
#define TASK_WAKING 256
#define TASK_PARKED 512
#define TASK_NOLOAD 1024
#define TASK_STATE_MAX 2048
/* Convenience macros for the sake of set_task_state */
#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)
上面的这些状态又分为下面的几类
5个互斥状态
state可以是5个互斥状态中的一种,系统中的进程必须处于5个状态中的一种。
这个5个状态的具体描述如下
状态 | 描述 |
---|---|
TASK_RUNNING | 表示进程要么正在执行,要么正要准备执行(已经就绪),正在等待cpu时间片的调度 |
TASK_INTERRUPTIBLE | 进程因为等待一些条件而被挂起(阻塞)而所处的状态。这些条件主要包括:硬中断、资源、一些信号……,一旦等待的条件成立,进程就会从该状态(阻塞)迅速转化成为就绪状态TASK_RUNNING |
TASK_UNINTERRUPTIBLE | 意义与TASK_INTERRUPTIBLE类似,除了不能通过接受一个信号来唤醒以外,对于处于TASK_UNINTERRUPIBLE状态的进程,哪怕我们传递一个信号或者有一个外部中断都不能唤醒他们。只有它所等待的资源可用的时候,他才会被唤醒。这个标志很少用,但是并不代表没有任何用处,其实他的作用非常大,特别是对于驱动刺探相关的硬件过程很重要,这个刺探过程不能被一些其他的东西给中断,否则就会让进城进入不可预测的状态 |
TASK_STOPPED | 进程被停止执行,当进程接收到SIGSTOP、SIGTTIN、SIGTSTP或者SIGTTOU信号之后就会进入该状态 |
TASK_TRACED | r表示进程被debugger等进程监视,进程执行被调试程序所停止,当一个进程被另外的进程所监视,每一个信号都会让进城进入该状态 |
5个互斥状态
两个附加的进程状态既可以被添加到state域中,又可以被添加到exit_state域中。只有当进程终止的时候,才会达到这两种状态.
/* task state */
int exit_state;
int exit_code, exit_signal;
状态 | 描述 |
---|---|
EXIT_ZOMBIE | 进程的执行被终止,但是其父进程还没有使用wait()等系统调用来获知它的终止信息,此时进程成为僵尸进程 |
EXIT_DEAD | 进程的最终状态 |
新增睡眠状态
进程状态 TASK_UNINTERRUPTIBLE 和 TASK_INTERRUPTIBLE 都是睡眠状态
进程标识符(PID)
pid_t pid;
pid_t tgid;
通过查看源代码我们发现pid_t的类型就是一个整型,每个进程在创建的时候都会返回一个进程标识符(PID),就好像一个身份证号码一样,用来唯一标识一个进程。
在CONFIG_BASE_SMALL配置为0的情况下,PID的取值范围是0到32767,即系统中的进程数最大为32768个。
进程内核栈
void *stack;
这里关于进程内核栈,专门写一篇博客,可以看过来
进程内核栈
进程标记
unsigned int flags; /* per process flags, defined below */
反应进程状态的信息,但不是运行状态,用于内核识别进程当前的状态,以备下一步操作
flags成员的可能取值如下,这些宏以PF(ProcessFlag)开头
例如
PF_FORKNOEXEC 进程刚创建,但还没执行。
PF_SUPERPRIV 超级用户特权。
PF_DUMPCORE dumped core。
PF_SIGNALED 进程被信号(signal)杀出。
PF_EXITING 进程开始关闭。
表示进程亲属关系的成员
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->real_parent->pid)
*/
struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
/*
* children/sibling forms the list of my natural children
*/
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
struct task_struct *group_leader; /* threadgroup leader */
在Linux系统中,所有进程之间都有着直接或间接地联系,每个进程都有其父进程,也可能有零个或多个子进程。拥有同一父进程的所有进程具有兄弟关系。
字段 | 描述 |
---|---|
real_parent | 指向其父进程,如果创建它的父进程不再存在,则指向PID为1的init进程 |
parent | 指向其父进程,当它终止时,必须向它的父进程发送信号。它的值通常与real_parent相同 |
children | 表示链表的头部,链表中的所有元素都是它的子进程 |
sibling | 用于把当前进程插入到兄弟链表中 |
group_leader | 指向其所在进程组的领头进程 |
ptrace系统调用
ptrace 提供了一种父进程可以控制子进程运行,并可以检查和改变它的核心image
Performance Event
Performance Event是一款随 Linux 内核代码一同发布和维护的性能诊断工具。这些成员用于帮助PerformanceEvent分析进程的性能问题
进程调度
优先级
用来描述进程的调度方式,调度策略
进程地址空间
内核除了管理本身的内存外,还必须管理用户空间中进程的内存,我们称这个内存为进程地址空间,也就是系统中每个用户空间进程所看到的内存
还有其他的一些
判断标志
时间
信号处理
其他