淺淺分析task_struct結構體
task_struct結構體是Linux下的進程控制塊PCB,PCB里包含著一個進程的所有信息。
要了解task_struct結構體,就必須要知道什么是進程。進程可以有以下幾個定義:
一個正在執(zhí)行的程序。
一個正在計算機上執(zhí)行的程序實例。
能分配給處理器并由處理器執(zhí)行的實體。
一個具有以下特征的活動單元:一組指令序列的執(zhí)行、一個當前狀態(tài)和相關的系統(tǒng)資源集合。
也可以把進程當成由一組元素組成的實體,進程的兩個基本元素是程序代碼(可能被執(zhí)行相同程序的其他進程共享)和與代碼相關聯(lián)的數(shù)據(jù)集。假設處理器開始執(zhí)行該程序代碼,且我們把這個執(zhí)行實體稱為進程。在進程執(zhí)行時,任意給的一個時間,進程都可以唯一地被表征為以下元素:
標識符:跟這個進程相關的唯一標識符,用來區(qū)別其他進程。 狀態(tài):如果進程正在執(zhí)行,那么進程處于執(zhí)行狀態(tài)。 優(yōu)先級:相對于其他進程的優(yōu)先級。 程序計數(shù)器:程序中即將被執(zhí)行的下一條指令的地址。 內存指針:包括程序代碼和進程相關數(shù)據(jù)的指針,還有和其他進程共享的內存塊的指針。 上下文數(shù)據(jù):進程執(zhí)行時處理器的寄存器中的數(shù)據(jù)。 I/O狀態(tài)信息:包括顯示的I/O請求,分配給進程的I/O設備(如磁帶驅動器)和被進程使用的文件列表。 審計信息:可包括處理器時間總和,使用的時鐘數(shù)總和,時間限制,審計號等。 前述的列表信息被存放在一個稱為進程控制塊(PCB)的數(shù)據(jù)結構中,該控制塊由操作系統(tǒng)創(chuàng)建和管理。
要了解PCB,就需要知道操作系統(tǒng)執(zhí)行一個程序的過程,如下圖:

進程是動態(tài)運行的事例,但是并不是所有的進程都在運行,
每個進程在內核中都有一個進程控制塊(PCB)來維護進程相關的信息,在Linux下內核的進程控制塊就是task_struct結構體。
task_struct結構體是Linux內核中的一種數(shù)據(jù)結構,接下來就進入本文的重點:剖析task_struct結構體
【文章福利】小編推薦自己的Linux內核技術交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)??


(1)進程的標識 PID(process identifier):
pid_t pid;//進程的唯一標識 pid_t tgid;// 線程組的領頭線程的pid成員的值 32位無符號整型數(shù)據(jù)。但最大值取32767。表示每一個進程的標識符。也是內核提供給用戶程序的借口,用戶程序通過pid操作程序。因為Unix的原因引入還引入了線程組的概念。稱為:tgid。一個線程組中的所有線程使用和該線程組中的第一個輕量級線程的pid,被存在tgid成員中。當進程沒有線程時,tgid=pid;當有多線程時,tgid表示的是主線程的id,而pid表示每一個線程自己的id。
(2)進程的狀態(tài) volatile long state
state的可能取值是:
#define TASK_RUNNING 0//進程要么正在執(zhí)行,要么準備執(zhí)行
#define TASK_INTERRUPTIBLE 1 //可中斷的睡眠,可以通過一個信號喚醒
#define TASK_UNINTERRUPTIBLE 2 //不可中斷睡眠,不可以通過信號進行喚醒
#define __TASK_STOPPED 4 //進程停止執(zhí)行
#define __TASK_TRACED 8 //進程被追蹤
/* in tsk->exit_state */
#define EXIT_ZOMBIE 16 //僵尸狀態(tài)的進程,表示進程被終止,但是父進程還沒有獲取它的終止信息,比如進程有沒有執(zhí)行完等信息。
#define EXIT_DEAD 32 //進程的最終狀態(tài),進程死亡
/* in tsk->state again */
#define TASK_DEAD 64 //死亡
#define TASK_WAKEKILL 128 //喚醒并殺死的進程
#define TASK_WAKING 256 //喚醒進程
(3)進程的優(yōu)先級 long priority
Priority的值給出進程每次獲取CPU后可使用的時間(按jiffies計)。優(yōu)先級可通過系統(tǒng)sys_setpriorty改變(在kernel/sys.c中)。
程序計數(shù)器:程序中即將被執(zhí)行的下一條指令的地址。 內存指針:包括程序代碼和進程相關數(shù)據(jù)的指針,還有和其他進程共享的內存塊的指針。 上下文數(shù)據(jù):進程執(zhí)行時處理器的寄存器中的數(shù)據(jù)。 I/O狀態(tài)信息:包括顯示的I/O請求,分配給進程的I/O設備(如磁帶驅動器)和被進程使用的文件列表。 審計信息:可包括處理器時間總和,使用的時鐘數(shù)總和,時間限制,審計號等。
(4)進程調度信息
表示當前進程或一個進程允許運行的時間,待到該進程的時間片運行結束,CPU會從運行隊列上拿出另一個進程運行。
need_resched:調度標志 Nice:靜態(tài)優(yōu)先級 Counter:動態(tài)優(yōu)先級;重新調度進程時會在run_queue中選出Counter值最大的進程。也代表該進程的時間片,運行中不斷減少。 Policy:調度策略開始運行時被賦予的值 rt_priority:實時優(yōu)先級
(5)進程通信有關信息(IPC:Inter_Process Communication)
unsigned long signal:進程接收到的信號。每位表示一種信號,共32種。置位有效。 unsigned long blocked:進程所能接受信號的位掩碼。置位表示屏蔽,復位表示不屏蔽。 Spinlock_t sigmask_lock:信號掩碼的自旋鎖 Long blocked:信號掩碼 Struct sem_undo *semundo:為避免死鎖而在信號量上設置的取消操作 Struct sem_queue *semsleeping:與信號量操作相關的等待隊列 struct signal_struct *sig:信號處理函數(shù)
(6)進程信息
Linux中存在多進程,而多進程中進程之間的關系可能是父子關系,兄弟關系。 除了祖先進程外,其他進程都有一個父進程,通過folk創(chuàng)建出子進程來執(zhí)行程序。除了表示各自的pid外,子進程的絕大多數(shù)信息都是拷貝父進程的信息。且父進程對子進程手握生殺大權,即子進程時是父進程創(chuàng)建出來的,而父進程也可以發(fā)送命令殺死子進程。
(7)時間信息
Start_time:進程創(chuàng)建時間 Per_cpu_utime:進程在執(zhí)行時在用戶態(tài)上耗費的時間。 Pre_cpu_stime:進程在執(zhí)行時在系統(tǒng)態(tài)上耗費的時間。 ITIMER_REAL:實時定時器,不論進程是否運行,都在實時更新。 ITIMER_VIRTUAL:虛擬定時器,只有進程運行在用戶態(tài)時才會更新。 ITIMER_PROF:概況定時器,進程在運行處于用戶態(tài)和系統(tǒng)態(tài)時更新。
(8)文件信息
文件的打開和關閉都是資源的一種操作,Linux中的task_struct中有兩個結構體儲存這兩個信息。
Sruct fs_struct *fs:進程的可執(zhí)行映象所在的文件系統(tǒng),有兩個索引點,稱為root和pwd,分別指向對應的根目錄和當前目錄。
Struct files_struct *files:進程打開的文件
(8)地址空間/虛擬內存信息
每個進程都有自己的一塊虛擬內存空間,用mm_struct來表示,mm_struct中使用兩個指針表示一段虛擬地址空間,然后在最終時通過頁表映射到真正的物理內存上。
(9)頁面管理信息
Int swappable:進程占用的內存頁面是否可換出。 Unsigned long min_flat,maj_flt,nswap:進程累計換出、換入頁面數(shù)。 Unsigned long cmin_flat,cmaj_flt,cnswap:本進程作為祖先進程,其所有層次子進程的累計換出、換入頁面數(shù)。
(10)對稱對處理機信息
Int has_cpu: 進程是否當前擁有CPU Int processor: 進程當前正在使用的CPU Int lock_depth: 上下文切換時內核鎖的深度
(11)上下文信息:
struct desc_struct *ldt:進程關于CPU段式存儲管理的局部描述符表的指針。 struct thread_struct tss:任務狀態(tài)段。與Intel的TSS進行互動,當前運行的TSS保存在PCB的tss中,新選中的的進程的tss保存在TSS。
(12)信號量數(shù)據(jù)成員
struct sem_undo *semundo:進程每一次操作一次信號量,都會生成一個undo操作。保存在sem_undo結構體中,最終在進程異常終止結束的時候,sem_undo的成員semadj就會指向一個數(shù)組,這個數(shù)組中每個成員都表示之前每次undo的量。 truct sem_queue *semsleeping:進程在操作信號量造成堵塞時,進程會被送入semsleeping指示的關于該信號量的sem_queue隊列。
(13)進程隊列指針
struct task_struct *next_task,*prev_task:所有進程均有各自的PCB。且各個PCB會串在一起,形成一個雙向鏈表。其next_task和prev_task就表示上一個或下一個PCB,即前后指針。進程鏈表的頭和尾都是0號進程。 struct task_struct *next_run,*prev_run:由進程的run_queue中產生作用的,指向上一個或下一個可運行的進程,鏈表的頭和尾都是0號進程。 struct task_struct *p_opptr:原始父進程(祖先進程) struct task_struct *p_pptr :父進程 struct task_struct *p_cptr:子進程 struct task_struct *p_ysptr:弟進程 struct task_struct *p_osptr:兄進程 以上分別是指向原始父進程(original parent)、父進程(parent)、子進程(youngest child)及新老兄弟進程(younger sibling,older sibling)的指針。
current:當前正在運行進程的指針。 struct task_struct init_task:0號進程的PCB,進程的跟=根,始終是INIT_TASK。 char comm[16]:進程正在執(zhí)行的可執(zhí)行文件的文件名。 int errno:進程最后一次出錯的錯誤號。0表示無錯誤。
