图说Linux进程

2020-06-01 00:00:00 等待 调用 状态 进程 信号

进程在Linux里面普通不过了,可是你知道在内核里面都有哪些数据结构吗?


一、进程链表


每个进程在内核里面对应如下的数据结构


struct task_struct {


所有的进程是串在一个列表上的,struct list_head tasks;


struct list_head {

struct list_head *next, *prev;

};


这是一个双向列表,列表头是struct task_struct init_task = INIT_TASK(init_task)的实例。


有的同学马上就明白了。对啊,在Linux系统启动的时候,会首先启动一个Init进程,Init进程会在/etc/inittab下面将Daemon程序启动,这些Daemon进程是Init进程的子进程。后创建一个子进程运行tty,等待用户登录,成功登录后运行shell。


这Init进程的PID是1,ps命令就能看的。


但是这里的init_task却不是init进程,这个进程的PID是0,被称为idle进程,在这个结构后面链接的个tast_struct对应的才是init进程,PID为1.


一个进程往往有多个线程,不但进程对应一个task_struct,线程也在这链表里面。


二、进程状态


进程有状态volatile long state;



当一个进程创建的时候,初始化阶段,进程是处于TASK_UNINTERRUPTIBLE的状态,这个时候是不接受任何中断信号的。


一旦初始化完毕,进程就处于TASK_RUNNING的状态,处于这个状态不意味着进程已经在运行了,仅仅是放在队列中,等待内核调度它到CPU上,这个时候,这个进程除了等待CPU,不等待任何其他的资源或者事件。


终于轮到这个进程了,被内核Dispatch到某个CPU上,进程开始运行,但是状态还是TASK_RUNNING,并不改变,当运行完毕自己的时间片之后,进程被抢占,让出资源,回到队列,但是状态还是TASK_RUNNING。


当进程调用了一个系统调用,比如读取一个文件,需要等待这个I/O事件完成,这个时候这个进程会让出CPU,进入sleep的状态。


有两种Sleep的状态,一个是可以接受外界信号的,TASK_INTERRUPTIBLE,一个是不可以接受外界信号的,TASK_UNINTERRUPTIBLE。


当可中断的进程收到信号的时候,会被放在运行队列里面,等待被分配CPU,从而可以执行一个函数处理这个信号,在函数中可以退出当前的系统调用也可以做一些处理然后继续当前的系统调用。然而对于不可中断的进程是收不到信号的,所以只能等待当前系统调用结束。


当系统调用结束之后,进程又回到了可以运行的状态。


当进程退出的时候,进入僵尸状态,等待所有的资源被父进程回收,当结束后会设置exit_status。


当进程收到SIGSTOP信号的时候,例如在shell中ctrl-z或者debug程序的时候到达断点,进程进入到TASK_STOPPED状态,当收到SIGCONT的时候,恢复执行。


/* Used in tsk->state: */

#define TASK_RUNNING 0

#define TASK_INTERRUPTIBLE 1

#define TASK_UNINTERRUPTIBLE 2

#define __TASK_STOPPED 4

#define __TASK_TRACED 8

/* Used in tsk->exit_state: */

#define EXIT_DEAD 16

#define EXIT_ZOMBIE 32

#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)

/* Used in tsk->state again: */

#define TASK_DEAD 64

#define TASK_WAKEKILL 128

#define TASK_WAKING 256

#define TASK_PARKED 512

#define TASK_NOLOAD 1024

#define TASK_NEW 2048

#define TASK_STATE_MAX 4096

#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPNn"

/* Convenience macros for the sake of set_current_state: */

#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)

#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)

#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)

#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)

/* Convenience macros for the sake of wake_up(): */

#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)

#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED)


相关文章