task_struct結構體, 理解結構體中的各個字段的含義

首先什麼是進程?

1>進程是程序的一個執行的實例;

2>進程是正在執行的程序

3>進程是能分配處理器並由處理器執行的實體

按內核的觀點來談進程:它所擔當分配系統資源(CPU時間,內存)的實體。

進程的兩個基本的元素如下:

一、程序代碼(可能被執行相同程序的其它進程共享)二是和代碼相關聯的數據集。這裏和代碼相關聯的數據集指的是數據段和進程控制塊。進程是一種動態描述,但是並不代表所有的進程都在運行。(進程在內存中因策略或調度需求,會處於各種狀態)。

task_struct:

爲了管理進程,操作系統必須對每個進程所做的事情進行清楚的描述,爲此,操作系統使用數據結構來代表處理不同的實體,這個數據結構就是通常所說的進程描述符或進程控制塊(PCB)。

在linux操作系統下這就是task_struct結構 ,所屬的頭文件#include   <sched.h>每個進程都會被分配一個task_struct結構,它包含了這個進程的所有信息,在任何時候操作系統都能夠跟蹤這個結構的信息,宰割結構是linux內核彙總最重要的數據結構,下面我們會詳細的介紹。

這個進程的主要信息:

1、與進程相關的唯一標識符,區別正在執行的進程和其他進程

2、狀態:描述進程的狀態,因爲進程有阻塞、掛起、運行等好幾個狀態,所以都有個表示符來記錄進程的執行狀態。

3、優先級:如果有好幾個進程正在執行,就涉及到進程的執行的先後順序,這和進程的優先級這個標識符有關。

4、程序計數器:程序中即將被執行指令的下一條地址。

5、內存指針:程序代碼和進程相關數據的指針。

6、上下文數據:進程執行時處理器的寄存器中的數據。

7、I/O狀態信息:包括顯示的I/O請求,分配給進程的I/O設備和被進程使用的文件列表。

8、記賬信息:包括處理機的時間總和,記賬號等等。

保存進程信息的數據結構叫tast_struct,進程的信息可以通過/proc系統文件夾查看。要獲取PID爲400的進程信息,你需要查看/proc/400這個文件夾。

接下來就來給出一些task_struct各個字段的介紹:


task_struct  //進程描述符

Struct  task_struct

{

1、支持對稱多處理器方式(SMP)時的數據成員

(1)int processor;  //進程正在使用的CPU

(2)int last_processor;  //進程最後一次使用的CPU

(3)int lock_depth;  //上下文切換時系統內核鎖的深度

2、其他數據成員

(1)unsigned short used_math;  //是否使用MPU

(2)char comm[16];  //進程正在運行的可執行文件的文件名

(3)struct rlimit rlim[RLIM_NLIMITS];  //結構rlimit用於資源管理,定義在linux/include/linux/resource.h中,成員共有兩項:rlim_cur是資源的當前最大數目;rlim_max是資源可有的最大數目。

(4)int errno;  //最後一次出錯的系統調用錯誤號,0表示無錯誤。系統調用返回時,全程量也擁有該錯誤。

(5)long debugreg[8];  //保存INTEL CPU調試寄存器的值,在ptrace系統調用中使用。

(6)struct exec_domain *exec_domain;  //Linux可以運行由80386平臺其它UNIX操作系統生成的符合iBCS2標準的程序。關於此類程序與Linux程序差異的消息就由exec_domain結構保存。

(7)unsigned long personality;  //Linux 可以運行由80386平臺其它UNIX操作系統生成的符合iBCS2標準的程序。 Personality進一步描述進程執行的程序屬於何種UNIX平臺的“個性”信息。通常有PER_Linux、PER_Linux_32BIT、 PER_Linux_EM86、PER_SVR3、PER_SCOSVR3、PER_WYSEV386、PER_ISCR4、PER_BSD、 PER_XENIX和PER_MASK等,

(8)struct linux_binfmt *binfmt;  //指向進程所屬的全局執行文件格式結構,共有a。out、script、elf和java等四種。結構定義在include/linux/binfmts.h中(core_dump、load_shlib(fd)、load_binary、use_count)。

(9)int exit_code,exit_signal;  //引起進程退出的返回代碼exit_code,引起錯誤的信號名exit_signal。

(10)int dumpable:1;  //布爾量,表示出錯時是否可以進行memory dump。

(11)int did_exec:1;  //按POSIX要求設計的布爾量,區分進程是正在執行老程序代碼,還是在執行execve裝入的新代碼。

(12) int tty_old_pgrp;  //進程顯示終端所在的組標識。

(13) struct tty_struct *tty;  //指向進程所在的顯示終端的信息。如果進程不需要顯示終端,如0號進程,則該指針爲空。結構定義在include/linux/tty.h中。

(14) struct wait_queue *wait_chldexit;  //在進程結束時,或發出系統調用wait4後,爲了等待子進程的結束,而將自己(父進程)睡眠在該隊列上。結構定義在include/linux/wait.h中。

3、調度數據成員

(1) volatile long states;  //表示進程的當前狀態:

ASK_RUNNING:正在運行或在就緒隊列run-queue中準備運行的進程,實際參與進程調度。

TASK_INTERRUPTIBLE:處於等待隊列中的進程,待資源有效時喚醒,也可由其它進程通過信號(signal)或定時中斷喚醒後進入就緒隊列run-queue。

TASK_UNINTERRUPTIBLE:處於等待隊列中的進程,待資源有效時喚醒,不可由其它進程通過信號(signal)或定時中斷喚醒。

TASK_ZOMBIE:表示進程結束但尚未消亡的一種狀態(僵死狀態)。此時,進程已經結束運行且釋放大部分資源,但尚未釋放進程控制塊。

TASK_STOPPED:進程被暫停,通過其它進程的信號才能喚醒。導致這種狀態的原因有二,或者是對收到SIGSTOP、SIGSTP、SIGTTIN或SIGTTOU信號的反應,或者是受其它進程的ptrace系統調用的控制而暫時將CPU交給控制進程。

TASK_SWAPPING: 進程頁面被交換出內存的進程。

(2) unsigned long flags;  //進程標誌:

PF_ALIGNWARN 打印“對齊”警告信息。

PF_PTRACED 被ptrace系統調用監控。

PF_TRACESYS 正在跟蹤。

PF_FORKNOEXEC 進程剛創建,但還沒執行。

PF_SUPERPRIV 超級用戶特權。

PF_DUMPCORE dumped core。

PF_SIGNALED 進程被信號(signal)殺出。

PF_STARTING 進程正被創建。

PF_EXITING 進程開始關閉。

PF_USEDFPU 該進程使用FPU(SMP only)。

PF_DTRACE delayed trace (used on m68k)。

(3)long priority;  //進程優先級。 Priority的值給出進程每次獲取CPU後可使用的時間(按jiffies計)。優先級可通過系統調用sys_setpriorty改變(在kernel/sys.c中)。

(4)unsigned long rt_priority;  //rt_priority 給出實時進程的優先級,rt_priority+1000給出進程每次獲取CPU後可使用的時間(同樣按jiffies計)

(5)long counter;  //在輪轉法調度時表示進程當前還可運行多久。在進程開始運行是被賦爲priority的值,以後每隔一個tick(時鐘中斷)遞減1,減到0時引起新一輪調 度。重新調度將從run_queue隊列選出counter值最大的就緒進程並給予CPU使用權,因此counter起到了進程的動態優先級的作用 (priority則是靜態優先級)。

(6)unsigned long policy;  //該進程的進程調度策略,可以通過系統調用sys_sched_setscheduler()更改(見kernel/sched.c)。調度策略有:

SCHED_OTHER 0 非實時進程,基於優先權的輪轉法(round robin)。
SCHED_FIFO 1 實時進程,用先進先出算法。
SCHED_RR 2 實時進程,用基於優先權的輪轉法。
4、信號處理
(1) unsigned long signal; //進程接收到的信號。每位表示一種信號,共32種。置位有效。
(2) unsigned long blocked;  //進程所能接受信號的位掩碼。置位表示屏蔽,復位表示不屏蔽。
(3) struct signal_struct *sig;  //因爲signal和blocked都是32位的變量,Linux最多隻能接受32種信號。對每種信號,各進程可以由PCB的sig屬性選擇使用自定義的處理 函數,或是系統的缺省處理函數。指派各種信息處理函數的結構定義在include/linux/sched.h中
5、進程隊列指針
(1)struct task_struct *next_task,*prev_task; //所有進程(以PCB的形式)組成一個雙向鏈表。next_task和就是鏈表的前後指針。鏈表的頭和尾都是init_task(即0號進程)。
(2)struct task_struct *next_run,*prev_run;  //由正在運行或是可以運行的,其進程狀態均爲TASK_RUNNING的進程所組成的一個雙向循環鏈表,即run_queue就緒隊列。該鏈表的前後向指針用next_run和prev_run,鏈表的頭和尾都是init_task(即0號進程)。

(3)struct task_struct *p_opptr,*p_pptr;和struct task_struct *p_cptr,*p_ysptr,*p_osptr;  //以上分別是指向原始父進程(original parent)、父進程(parent)、子進程(youngest child)及新老兄弟進程(younger sibling,older sibling)的指針

6、進程標識

(1) unsigned short uid,gid;  //uid和gid是運行進程的用戶標識和用戶組標識。

(2) int groups[NGROUPS];  //與多數現代UNIX操作系統一樣,Linux允許進程同時擁有一組用戶組號。在進程訪問文件時,這些組號可用於合法性檢查。

(3) unsigned short euid,egid; //euid 和egid又稱爲有效的uid和gid。出於系統安全的權限的考慮,運行程序時要檢查euid和egid的合法性。通常,uid等於euid,gid等於 egid。有時候,系統會賦予一般用戶暫時擁有root的uid和gid(作爲用戶進程的euid和egid),以便於進行運作。

(4) unsigned short fsuid,fsgid;  //fsuid 和fsgid稱爲文件系統的uid和gid,用於文件系統操作時的合法性檢查,是Linux獨特的標識類型。它們一般分別和euid和egid一致,但在 NFS文件系統中NFS服務器需要作爲一個特殊的進程訪問文件,這時只修改客戶進程的fsuid和fsgid。

(5) unsigned short suid,sgid;  //suid和sgid是根據POSIX標準引入的,在系統調用改變uid和gid時,用於保留真正的uid和gid。

(6) int pid,pgrp,session;  //進程標識號、進程的組織號及session標識號,相關係統調用(見程序kernel/sys.c)有sys_setpgid、sys_getpgid、sys_setpgrp、sys_getpgrp、sys_getsid及sys_setsid幾種。

(7) int leader;//是否是session的主管,布爾量。

7、 時間數據成員

(1) unsigned long timeout;  //用於軟件定時,指出進程間隔多久被重新喚醒。採用tick爲單位。

(2) unsigned long it_real_value,it_real_iner;  //用於itimer(interval timer)軟件定時。採用jiffies爲單位,每個tick使it_real_value減到0時向進程發信號SIGALRM,並重新置初值。初值由 it_real_incr保存。具體代碼見kernel/itimer.c中的函數it_real_fn()。

(3) struct timer_list real_timer;  //一種定時器結構(Linux共有兩種定時器結構,另一種稱作old_timer)。數據結構的定義在include/linux/timer.h中,相關操作函數見kernel/sched.c中add_timer()和del_timer()等。

(4) unsigned long it_virt_value,it_virt_incr;  //關於進程用戶態執行時間的itimer軟件定時。採用jiffies爲單位。進程在用戶態運行時,每個tick使it_virt_value減1,減到0時 向進程發信號SIGVTALRM,並重新置初值。初值由it_virt_incr保存。具體代碼見kernel/sched.c中的函數 do_it_virt()。

(5) unsigned long it_prof_value,it_prof_incr;  //同樣是 itimer軟件定時。採用jiffies爲單位。不管進程在用戶態或內核態運行,每個tick使it_prof_value減1,減到0時向進程發信號 SIGPROF,並重新置初值。初值由it_prof_incr保存。 具體代碼見kernel/sched.c中的函數do_it_prof。

(6) long utime,stime,cutime,cstime,start_time;  //以上分別爲進程在用戶態的運行時間、進程在內核態的運行時間、所有層次子進程在用戶態的運行時間總和、所有層次子進程在覈心態的運行時間總和,以及創建該進程的時間。

8、 信號量數據成員

(1) struct sem_undo *semundo;  //進程每操作一次信號量,都生成一個對此次操作的undo操作,它由sem_undo結構描述。這些屬於同一進程的undo操作組成的鏈表就由semundo 屬性指示。當進程異常終止時,系統會調用undo操作。sem_undo的成員semadj指向一個數據數組,表示各次undo的量。結構定義在 include/linux/sem.h。

(2) struct sem_queue *semsleeping;  //每一信號量集合對應一個sem_queue等待隊列(見include/linux/sem.h)。進程因操作該信號量集合而阻塞時,它被掛到semsleeping指示的關 於該信號量集合的sem_queue隊列。反過來,semsleeping。sleeper指向該進程的PCB。

9、 進程上下文環境

(1) struct desc_struct *ldt;  //進程關於CPU段式存儲管理的局部描述符表的指針,用於仿真WINE Windows的程序。其他情況下取值NULL,進程的ldt就是arch/i386/traps.c定義的default_ldt。

(2) struct thread_struct tss;  //任務狀態段,其內容與INTEL CPU的TSS對應,如各種通用寄存器.CPU調度時,當前運行進程的TSS保存到PCB的tss,新選中進程的tss內容複製到CPU的TSS。結構定義在include/linux/tasks.h中。

(3) unsigned long saved_kernel_stack;  //MS-DOS的仿真程序(或叫系統調用vm86)保存的堆棧指針。

(4) unsigned long kernel_stack_page;  //在內核態運行時,每個進程都有一個內核堆棧,其基地址就保存在kernel_stack_page中。

10、 文件系統數據成員

(1) struct fs_struct *fs;  //fs 保存了進程本身與VFS的關係消息,其中root指向根目錄結點,pwd指向當前目錄結點,umask給出新建文件的訪問模式(可由系統調用umask更 改),count是Linux保留的屬性

struct files_struct *files;  //files包含了進程當前所打開的文件(struct file *fd[NR_OPEN])。在Linux中,一個進程最多隻能同時打開NR_OPEN個文件。而且,前三項分別預先設置爲標準輸入、標準輸出和出錯消息輸出文件。 

(3) int link_count;  //文件鏈(link)的數目。

11、 內存數據成員

(1) struct mm_struct *mm;  //linux 中,採用按需分頁的策略解決進程的內存需求。task_struct的數據成員mm指向關於存儲管理的mm_struct結構。其中包含了一個虛存隊列 mmap,指向由若干vm_area_struct描述的虛存塊。同時,爲了加快訪問速度,mm中的mmap_avl維護了一個AVL樹。在樹中,所有的 vm_area_struct虛存塊均由左指針指向相鄰的低虛存塊,右指針指向相鄰的高虛存塊。 結構定義在include/linux/sched.h中。

12、頁面管理

(1) int swappable:1;  //進程佔用的內存頁面是否可換出。swappable爲1表示可換出。

(2) unsigned long swap_address;  //虛存地址比swap_address低的進程頁面,以前已經換出或已換出過,進程下一次可換出的頁面自swap_address開始。

(3)unsigned long min_flt,maj_flt;  // 進程累計的minor缺頁次數和major缺頁次數。

(4) unsigned long nswap;  //該進程累計換出的頁面數。

(5) unsigned long cmin_flt,cmaj_flt,cnswap;  //以本進程作爲祖先的所有層次子進程的累計換入頁面、換出頁面計數。

(6) unsigned long old_maj_flt,dec_flt;

(7) unsigned long swap_cnt;  //下一次信號最多可換出的頁數。

13. 進程隊列的全局變量

(1) current;  //當前正在運行的進程的指針,在SMP中則指向CPU組中正被調度的CPU的當前進程.

(2) struct task_struct init_task;  //即0號進程的PCB,是進程的“根”,始終保持初值INIT_TASK。

(3) struct task_struct *task[NR_TASKS];  //進程隊列數組,規定系統可同時運行的最大進程數(見kernel/sched.c)。NR_TASKS定義在include/linux/tasks.h 中,值爲512。每個進程佔一個數組元素(元素的下標不一定就是進程的pid),task[0]必須指向init_task(0號進程)。可以通過 task[]數組遍歷所有進程的PCB。但Linux也提供一個宏定義for_each_task(),它通過next_task遍歷所有進程的PCB。

(4) unsigned long volatile jiffies;  //Linux的基準時間。系統初始化時清0,以後每隔10ms由時鐘中斷服務程序do_timer()增1。

(5) int need_resched;  //重新調度標誌位。當需要Linux調度時置位。在系統調用返回前(或者其它情形下),判斷該標誌是否置位。置位的話,馬上調用schedule進行CPU調度。

(6) unsigned long intr_count;  //記錄中斷服務程序的嵌套層數。正常運行時,intr_count爲0。當處理硬件中斷、執行任務隊列中的任務或者執 行bottom half隊列中的任務時,intr_count非0。這時,內核禁止某些操作,例如不允許重新調度。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章