進程在Linux里面最普通不過了,可是你知道在內核里面都有哪些數(shù)據(jù)結構嗎?
一、進程鏈表
每個進程在內核里面對應如下的數(shù)據(jù)結構
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系統(tǒng)啟動的時候,會首先啟動一個Init進程,Init進程會在/etc/inittab下面將Daemon程序啟動,這些Daemon進程是Init進程的子進程。最后創(chuàng)建一個子進程運行tty,等待用戶登錄,成功登錄后運行shell。
這Init進程的PID是1,ps命令就能看的。
但是這里的init_task卻不是init進程,這個進程的PID是0,被稱為idle進程,在這個結構后面鏈接的第一個tast_struct對應的才是init進程,PID為1.
一個進程往往有多個線程,不但進程對應一個task_struct,線程也在這鏈表里面。
二、進程狀態(tài)
進程有狀態(tài)volatile long state;
當一個進程創(chuàng)建的時候,初始化階段,進程是處于TASK_UNINTERRUPTIBLE的狀態(tài),這個時候是不接受任何中斷信號的。
一旦初始化完畢,進程就處于TASK_RUNNING的狀態(tài),處于這個狀態(tài)不意味著進程已經(jīng)在運行了,僅僅是放在隊列中,等待內核調度它到CPU上,這個時候,這個進程除了等待CPU,不等待任何其他的資源或者事件。
終于輪到這個進程了,被內核Dispatch到某個CPU上,進程開始運行,但是狀態(tài)還是TASK_RUNNING,并不改變,當運行完畢自己的時間片之后,進程被搶占,讓出資源,回到隊列,但是狀態(tài)還是TASK_RUNNING。
當進程調用了一個系統(tǒng)調用,比如讀取一個文件,需要等待這個I/O事件完成,這個時候這個進程會讓出CPU,進入sleep的狀態(tài)。
有兩種Sleep的狀態(tài),一個是可以接受外界信號的,TASK_INTERRUPTIBLE,一個是不可以接受外界信號的,TASK_UNINTERRUPTIBLE。
當可中斷的進程收到信號的時候,會被放在運行隊列里面,等待被分配CPU,從而可以執(zhí)行一個函數(shù)處理這個信號,在函數(shù)中可以退出當前的系統(tǒng)調用也可以做一些處理然后繼續(xù)當前的系統(tǒng)調用。然而對于不可中斷的進程是收不到信號的,所以只能等待當前系統(tǒng)調用結束。
當系統(tǒng)調用結束之后,進程又回到了可以運行的狀態(tài)。
當進程退出的時候,進入僵尸狀態(tài),等待所有的資源被父進程回收,當結束后會設置exit_status。
當進程收到SIGSTOP信號的時候,例如在shell中ctrl-z或者debug程序的時候到達斷點,進程進入到TASK_STOPPED狀態(tài),當收到SIGCONT的時候,恢復執(zhí)行。
/* 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)