Linux下的進程描述

進程
OS:程序的一個執行實例。
正在執重點內容行的程序。
能分配處理器並由處理器執行的實體。
內核觀點:擔當分配系統資源(CPU時間,內存)的實體。
進程的兩個基本元素是程序代碼(可能被執行相同程序的其他進程共享)和代碼相關聯的數據集。進程是一種動態描述,但是並不代表所有的進程都在運⾏行。(進程在內存中因策略或調度需求,會處於各種狀態)

進程控制塊(PCB)
每個進程在內核中都有一個進程控制塊(PCB)來維護進程相關的信息,Linux內核的進程控制塊是task_struct結構體。
Linux內核通過一個被稱爲進程描述符的task_struct結構體來管理進程,這個結構體包含了一個進程所需的所有信息。它定義在linux-2.6.38.8/include/linux/sched.h文件中。

task_struct中包含:
標示符 : 描述本進程的唯⼀一標⽰示符,⽤用來區別其他進程。
狀態 :任務狀態,退出代碼,退出信號等。
優先級 :相對於其他進程的優先級。
程序計數器:程序中即將被執⾏行的下⼀一條指令的地址。
內存指針:包括程序代碼和進程相關數據的指針,還有和其他進程共享的內存塊的指針
上下⽂文數據:進程執⾏行時處理器的寄存器中的數據。
I/O狀態信息:包括顯⽰示的I/O請求,分配給進程的I/O設備和被進程使⽤用的⽂文件列表。
記賬信息:可能包括處理器時間總和,使⽤用的時鐘數總和,時間限制,記賬號等。

task_struct結構註釋:

==========================

  long state 任務的運行狀態(-1 不可運行,0 可運行(就緒),>0 已停止)。

  long counter 任務運行時間計數(遞減)(滴答數),運行時間片。

  long priority 運行優先數。任務開始運行時counter = priority,越大運行越長。

  long signal 信號。是位圖,每個比特位代表一種信號,信號值=位偏移值+1。

  struct sigaction sigaction[32] 信號執行屬性結構,對應信號將要執行的操作和標誌信息。

  long blocked 進程信號屏蔽碼(對應信號位圖)。

  --------------------------

  int exit_code 任務執行停止的退出碼,其父進程會取。

  unsigned long start_code 代碼段地址。

  unsigned long end_code 代碼長度(字節數)。

  unsigned long end_data 代碼長度 + 數據長度(字節數)。

  unsigned long brk 總長度(字節數)。

  unsigned long start_stack 堆棧段地址。

  long pid 進程標識號(進程號)。

  long father 父進程號。

  long pgrp 父進程組號。

  long session 會話號。

  long leader 會話首領。

  unsigned short uid 用戶標識號(用戶id)。

  unsigned short euid 有效用戶id。

  unsigned short suid 保存的用戶id。

  unsigned short gid 組標識號(組id)。


  unsigned short egid 有效組id。

  unsigned short sgid 保存的組id。

  long alarm 報警定時值(滴答數)。

  long utime 用戶態運行時間(滴答數)。

  long stime 系統態運行時間(滴答數)。

  long cutime 子進程用戶態運行時間。

  long cstime 子進程系統態運行時間。

  long start_time 進程開始運行時刻。

  unsigned short used_math 標誌:是否使用了協處理器。

  --------------------------

  int tty 進程使用tty 的子設備號。-1 表示沒有使用。

  unsigned short umask 文件創建屬性屏蔽位。

  struct m_inode * pwd 當前工作目錄i 節點結構。

  struct m_inode * root 根目錄i 節點結構。

  struct m_inode * executable 執行文件i 節點結構。

  unsigned long close_on_exec 執行時關閉文件句柄位圖標誌。(參見include/fcntl.h)

  struct file * filp[NR_OPEN] 進程使用的文件表結構。

  --------------------------

  struct desc_struct ldt[3] 本任務的局部表描述符。0-空,1-代碼段cs,2-數據和堆棧段ds&ss。

  --------------------------

  struct tss_struct tss 本進程的任務狀態段信息結構。

  ==========================

task_struct所有成員及用法
1、進程標識符(PID):
描述本進程的唯一標示符,用來區別其他進程。

 pid_t pid;
 pid_t tgid;

在CONFIG_BASE_SMALL配置爲0的情況下,PID的取值範圍是0到32767,即系統中的進程數最大爲32768個。

/* linux-2.6.38.8/include/linux/threads.h */
   #define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)

在Linux系統中,一個線程組中的所有線程使用和該線程組的領頭線程(該組中的第一個輕量級進程)相同的PID,並被存放在tgid成員中。只有線程組的領頭線程的pid成員纔會被設置爲與tgid相同的值。注意,getpid()系統調用返回的是當前進程的tgid值而不是pid值。

2、進程狀態
任務狀態,退出代碼,退出信號等。

volatile long state;      //表示進程的當前狀態
int exit_state;

state成員的可能取值如下:

#define TASK_RUNNING        0
#define TASK_INTERRUPTIBLE  1
#define TASK_UNINTERRUPTIBLE    2
#define __TASK_STOPPED      4
#define __TASK_TRACED       8
/* in tsk->exit_state */
#define EXIT_ZOMBIE     16
#define EXIT_DEAD       32
/* in tsk->state again */
#define TASK_DEAD       64
#define TASK_WAKEKILL       128
#define TASK_WAKING     256

系統中的每個進程都必然處於以上所列進程狀態中的一種。

 TASK_RUNNING          //表示進程要麼正在執行,要麼正要準備執行。

 TASK_INTERRUPTIBLE   //表示進程被阻塞(睡眠),直到某個條件變爲真。條件一旦達成,進程的狀態就被設                                                   置爲TASK_RUNNING。

TASK_UNINTERRUPTIBLE  //與TASK_INTERRUPTIBLE類似,除了不能通過接受一個信號來喚醒以外。

__TASK_STOPPED        //表示進程被停止執行。

__TASK_TRACED         //表示進程被debugger等進程監視。

EXIT_ZOMBIE      //表示進程的執行被終止,但是其父進程還沒有使用wait()等系統調用來獲知它的終止信息。

EXIT_DEAD        //表示進程的最終狀態。

EXIT_ZOMBIE和EXIT_DEAD   //也可以存放在exit_state成員中。

進程狀態的切換過程:
這裏寫圖片描述

3、優先級:
相對於其他進程的優先級。

int prio, static_prio, normal_prio;
    unsigned int rt_priority;
    const struct sched_class *sched_class;
    struct sched_entity se;
    struct sched_rt_entity rt;
    unsigned int policy;
    cpumask_t cpus_allowed;

實時優先級範圍是0到MAX_RT_PRIO-1(即99),而普通進程的靜態優先級範圍是從MAX_RT_PRIO到MAX_PRIO-1(即100到139)。值越大靜態優先級越低。

/* linux-2.6.38.8/include/linux/sched.h */
#define MAX_USER_RT_PRIO    100
#define MAX_RT_PRIO     MAX_USER_RT_PRIO

#define MAX_PRIO        (MAX_RT_PRIO + 40)
#define DEFAULT_PRIO        (MAX_RT_PRIO + 20)
static_prio用於保存靜態優先級,可以通過nice系統調用來進行修改。

rt_priority用於保存實時優先級。

normal_prio的值取決於靜態優先級和調度策略。

prio用於保存動態優先級。

policy表示進程的調度策略,目前主要有以下五種:

#define SCHED_NORMAL        0
#define SCHED_FIFO      1
#define SCHED_RR        2
#define SCHED_BATCH     3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE      5
SCHED_NORMAL用於普通進程,通過CFS調度器實現。SCHED_BATCH用於非交互的處理器消耗型進程。     

SCHED_IDLE是在系統負載很低時使用。

SCHED_FIFO(先入先出調度算法)和SCHED_RR(輪流調度算法)都是實時調度策略。

sched_class結構體表示調度類,目前內核中有實現以下四種:

/* linux-2.6.38.8/kernel/sched_fair.c */ 
static const struct sched_class fair_sched_class;
/* linux-2.6.38.8/kernel/sched_rt.c */
static const struct sched_class rt_sched_class;
/* linux-2.6.38.8/kernel/sched_idletask.c */
static const struct sched_class idle_sched_class;
/* linux-2.6.38.8/kernel/sched_stoptask.c */
static const struct sched_class stop_sched_class;
se和rt都是調用實體,一個用於普通進程,一個用於實時進程,每個進程都有其中之一的實體。

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

(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中。

5、記賬信息
可能包括處理器時間總和,使⽤用的時鐘數總和,時間限制,記賬號等。

(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;

  以上分別爲進程在用戶態的運行時間、進程在內核態的運行時間、所有層次子進程在用戶態的運行時間總和、所有層次子進程在覈心態的運行時間總和,以及創建該進程的時間。

5、內存指針
包括程序代碼和進程相關數據的指針,還有和其他進程共享的內存塊的指針。

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中。

task_struct的定義:

struct task_struct {
volatile long state;  //說明了該進程是否可以執行,還是可中斷等信息
unsigned long flags;  //Flage 是進程號,在調用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;
//若進程不在任何CPU上運行, 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 *active_mm;
struct list_head local_pages;       //指向本地頁面      
unsigned int allocation_order, nr_local_pages;
struct linux_binfmt *binfmt;  //進程所運行的可執行文件的格式
int exit_code, exit_signal;
int pdeath_signal;     //父進程終止時向子進程發送的信號
unsigned long personality;
//Linux可以運行由其他UNIX操作系統生成的符合iBCS2標準的程序
int did_exec:1; 
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;  //供vfork() 使用
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_value;
struct timer_list real_timer;   //指向實時定時器的指針
struct tms times;      //記錄進程消耗的時間
unsigned long start_time;  //進程創建的時間
//記錄進程在每個CPU上所消耗的用戶態時間和核心態時間
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; 
//內存缺頁和交換信息:
//min_flt, maj_flt累計進程的次缺頁數(Copy on Write頁和匿名頁)和主缺頁數(從映射文件或交換
//設備讀入的頁面數); nswap記錄進程累計換出的頁面數,即寫到交換設備上的頁面數。
//cmin_flt, cmaj_flt, cnswap記錄本進程爲祖先的所有子孫進程的累計次缺頁數,主缺頁數和換出頁面數。
//在父進程回收終止的子進程時,父進程會將子進程的這些信息累計到自己結構的這些域中
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,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
int ngroups; //記錄進程在多少個用戶組中
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];  //與進程相關的資源限制信息
unsigned short used_math;   //是否使用FPU
char comm[16];   //進程正在運行的可執行文件名
 //文件系統信息
int link_count, total_link_count;
//NULL if no tty 進程所在的控制終端,如果不需要控制終端,則該指針爲空
struct tty_struct *tty;
unsigned int locks;
//進程間通信信息
struct sem_undo *semundo;  //進程在信號燈上的所有undo操作
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;
};
發佈了122 篇原創文章 · 獲贊 269 · 訪問量 35萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章