粉絲不過W
在 linux 中每一個進程都由 task_struct 數據結構來定義
task_struct 就是 PCB。是對進程控制的唯一手段也是最有效的手段
當我們調用 fork() 時, 系統會爲我們產生一個 task_struct 結構,然後從父進程那裏繼承一些數據, 並把新的進程插入到進程樹中, 以待進行進程管理
因此瞭解 task_struct 的結構對於我們理解任務調度( 在 linux 中任務和進程是同一概念 )的關鍵
進行剖析 task_struct 的定義之前,我們先按照我們的理論推一下它的結構
進程狀態 ,將紀錄進程在等待,運行,死鎖
調度信息,由哪個調度函數調度,怎樣調度
進程的通訊狀況
因爲要插入進程樹,所以有聯繫父子兄弟的指針, 必須是 task_struct 型
時間信息,如 計算好執行的時間, 以便 cpu 分配
標號,決定改進程歸屬
可 讀寫打開的一些文件信息
進程上下文和內核上下文
處理器上下文
內存信息
因爲每一個 PCB 都是這樣的, 只有這些結構, 才能滿足一個進程的所有要求
struct task_struct
{
/* -1 unrunnable, 0 runnable, >0 stopped:
* 該進程是否可以執行,還是可中斷等信息
*/
volatile long state;
//每個任務標誌(PF_*),定義如下
unsigned long flags; //進程號,在調用 fork()時給出
int sigpending; //進程上是否有待處理的信號
mm_segment_t addr_limit;/*進程地址空間,區分內核進程與普通進程在內存存放的位置不同
*0 - 0xBFFFFFFF for user-thead
*0 - 0xFFFFFFFF for kernel-thread
*/
//調度標誌,表示該進程是否需要重新調度,若非 0,則當從內核態返回到用戶態,會發生調度
volatile long need_resched;
int lock_depth; //鎖深度
long nice; //進程的基本時間片
//進程的調度策略,有三種,實時進程:SCHED_FIFO,SCHED_RR, 分時進程:SCHED_OTHER
unsigned long policy;
struct mm_struct *mm; //進程內存管理信息
int processor;
//若進程未運行, cpus_runnable 的值是 0,否則是 1 這個值在運行隊列被鎖時更新
unsigned long cpus_runnable, cpus_allowed;
struct list_head run_list; //指向運行隊列的指針
unsigned long sleep_time; //進程的睡眠時間
//用於將系統中所有的進程連成一個雙向循環鏈表, 其根是 init_task
struct task_struct *next_task, *prev_task;
struct mm_struct *artive_mm;
struct list_head local_pages; //指向本地頁面
unsigned int allocation_order, nr_local_pages;
struct linx_binfmt *binfmt; //進程所運行的可執行文件的格式
int exit_code,exit_signal;
int pdeath_signal; //父進程終止是向子進程發送的信號
unsignal long personality;
//Linux 可以運行由其他 UNIX 操作系統生成的符合 iBCS2 標準的程序
int did_exec;
pid_t pid; //進程標識符,用來代表一個進程
pid_t pgrp; //進程組標識,表示進程所屬的進程組
pid_t tty_old_pgrp; //進程控制終端所在的組標識
pid_t session; //進程的會話標識
pid_t tgid;
int leader; //進程是否爲會話主管
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
struct list_head thread_group; //線程鏈表
struct task_struct *pidhash_next; //用於將進程鏈入 HASH 表
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit; //供wait4()使用
struct completion *vfork_done; //供fork()使用
unsigned long rt_priority; //實時優先級,用它計算實時進程調度時的weight值
/*
* it_real_value, it_real_incr 用於 REAL 定時器,單位爲 jiffies,
*系統根據 it_real_value設置定時器的第一個終止時間. 在定時器到期時,
*向進程發送 SIGALRM 信號,同時根據it_real_incr 重置終止時間.
* it_prof_value, it_prof_incr 用於 Profile 定時器,單位爲 jiffies,
*當進程運行時,不管在何種狀態下,每個 tick 都使 it_prof_value 值減一,
*當減到 0 時,向進程發送信號 SIGPROF,並根據 it_prof_incr 重置時間.
* it_virt_value, it_virt_value 用於 Virtual 定時器,單位爲 jiffies。
*當進程運行時,不管在何種狀態下,每個 tick 都使 it_virt_value 值減一當減到 0 時,
*向進程發送信號 SIGVTALRM,根據it_virt_incr 重置初值。
*/
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer; //指向實時定時器的指針
struct tms times; //記錄進程的消耗的時間
unsigned long start_time; //進程創建的時間
//記錄進程在每個 CPU 上所消耗的用戶態時間和核心態時間
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
//內存缺頁和交換信息:
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
//表示進程的虛擬地址空間是否允許換出
int swappable:1;
/*
* 進程認證信息:
* uid,gid 爲運行該進程的用戶的用戶標識符和組標識符,通常是進程創建者的 uid,gid
* euid, egid 爲有效 uid,gid
* fsuid, fsgid 爲文件系統 uid,gid,這兩個 ID 號通常與有效 uid,gid 相等,
*在檢查對於文件系統的訪問權限時使用他們
* suid, sgid 爲備份 uid,gid
*/
uid_t uid, euid, fsuid;
gid_t gid, egid, fsgid;
//記錄進程在多少個用戶組中
int nproups;
//記錄進程所在的組
gid_t groups[NGROUPS];
//進程的權能,分別是有效位集合,繼承位集合,允許位集合
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:1;
struct user_struct *user;
//與進程相關的資源限制信息
struct rlimit rlim[RLIM_NLIMITS];
//是否使用 FPU
unsigned short used_math;
//進程正在運行的可執行文件名
char comm[16];
//文件系統信息
int link_count, total_link_count;
//NULL if no tty 進程所在的控制終端,如果不需要控制終端,則該指針爲空
struct tty_struct *tty;
unsigned int locks;
//進程間通信信息
//進程在信號燈上的所有 undo 操作
struct sem_undo *semundo;
//當進程因爲信號燈操作而掛起時,他在該隊列中記錄等待的操作
struct sem_queue *semsleeping;
//進程的 CPU 狀態,切換時,要保存到停止進程的 task_struct 中
struct thread_struct thread;
//文件系統信息
struct fs_struct *fs;
//打開文件信息
struct files_struct *files;
//信號處理函數
spinlock_t sigmask_lock;
struct signal_struct *sig;
//進程當前要阻塞的信號,每個信號對應一位
sigset_t blocked;
//進程上是否有待處理的信號
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
int(*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
u32 parent_exec_id;
u32 self_exec_id;
spinlock_t alloc_lock
void *journal_info;
};