1. 程式人生 > >linux驅動current,引用當前程序,及task_struct

linux驅動current,引用當前程序,及task_struct

1. 排程資料成員
(1) volatile long states;
表示程序的當前狀態:
? TASK_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計)。實時程序的優先順序可通過系統 呼叫sys_sched_setscheduler()改變(見kernel/sched.c)。
(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 實時程序,用基於優先權的輪轉法。
2. 訊號處理

(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中。對訊號的檢查安排在系統呼叫結束後,以 及“慢速型”中斷服務程式結束後(IRQ#_interrupt(),參見9。5節“啟動核心”)。
3. 程序佇列指標

(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)的指標。

4. 程序標識

(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的主管,布林量。
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;
以上分別為程序在使用者態的執行時間、程序在核心態的執行時間、所有層次子程序在使用者態的執行時間總和、所有層次子程序在核心態的執行時間總和,以及建立該程序的時間。
6. 訊號量資料成員
(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。
7. 程序上下文環境
(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中。
8. 檔案系統資料成員
(1) struct fs_struct *fs;
fs 儲存了程序本身與VFS的關係訊息,其中root指向根目錄結點,pwd指向當前目錄結點,umask給出新建檔案的訪問模式(可由系統呼叫umask更 改),count是Linux保留的屬性,如下頁圖所示。結構定義在include/linux/sched.h中。
(2) struct files_struct *files;
files包含了程序當前所開啟的檔案(struct file *fd[NR_OPEN])。在Linux中,一個程序最多隻能同時開啟NR_OPEN個檔案。而且,前三項分別預先設定為標準輸入、標準輸出和出錯訊息輸出檔案。 
(3) int link_count;
檔案鏈(link)的數目。
9. 記憶體資料成員
(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中。
10. 頁面管理
(1) int swappable:1;
程序佔用的記憶體頁面是否可換出。swappable為1表示可換出。對該標誌的復位和置位均在do_fork()函式中執行(見kerenl/fork.c)。
(2) unsigned long swap_address;
虛存地址比swap_address低的程序頁面,以前已經換出或已換出過,程序下一次可換出的頁面自swap_address開始。參見swap_out_process()和swap_out_pmd()(見mm/vmscan.c)。
(3) unsigned long min_flt,maj_flt;
該 程序累計的minor缺頁次數和major缺頁次數。maj_flt基本與min_flt相同,但計數的範圍比後者廣(參見fs/buffer.c和 mm/page_alloc.c)。min_flt只在do_no_page()、do_wp_page()裡(見mm/memory.c)計數新增的可 以寫操作的頁面。
(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;
下一次訊號最多可換出的頁數。
11. 支援對稱多處理器方式(SMP)時的資料成員
(1) int processor;
程序正在使用的CPU。
(2) int last_processor;
程序最後一次使用的CPU。
(3) int lock_depth;
上下文切換時系統核心鎖的深度。
12. 其它資料成員
(1) unsigned short used_math;
是否使用FPU。
(2) char comm[16];
程序正在執行的可執行檔案的檔名。
(3) struct rlimit rlim[RLIM_NLIMITS];
結 構rlimit用於資源管理,定義在linux/include/linux/resource.h中,成員共有兩項:rlim_cur是資源的當前最大 數目;rlim_max是資源可有的最大數目。在i386環境中,受控資源共有RLIM_NLIMITS項,即10項,定義在 linux/include/asm/resource.h中,見下表:
(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等,參見include/linux/personality.h。
(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中。
13. 程序佇列的全域性變數
(1) current;
當前正在執行的程序的指標,在SMP中則指向CPU組中正被排程的CPU的當前程序:
#define current(0+current_set[smp_processor_id()])/*sched.h*/
struct task_struct *current_set[NR_CPUS];
(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()(見 include/linux/sched.h),它通過next_task遍歷所有程序的PCB:
#define for_each_task(p) \
for(p=&init_task;(p=p->next_task)!=&init_task;)
(4) unsigned long volatile jiffies;
Linux的基準時間(見kernal/sched.c)。系統初始化時清0,以後每隔10ms由時鐘中斷服務程式do_timer()增1。
(5) int need_resched;
重新排程標誌位(見kernal/sched.c)。當需要Linux排程時置位。在系統呼叫返回前(或者其它情形下),判斷該標誌是否置位。置位的話,馬上呼叫schedule進行CPU排程。
(6) unsigned long intr_count;
記 錄中斷服務程式的巢狀層數(見kernal/softirq.c)。正常執行時,intr_count為0。當處理硬體中斷、執行任務佇列中的任務或者執 行bottom half佇列中的任務時,intr_count非0。這時,核心禁止某些操作,例如不允許重新排程。