linux驅動current,引用當前進程,及task_struct(轉)


盡管內核模塊不象應用程序一樣順序執行, 內核做的大部分動作是代表一個特定進程的. 內核代碼可以引用當前進程, 通過存取全局項 current, 它在 <asm/current.h> 中定義, 它產生一個指針指向結構 task_struct, 在 <Linux/sched.h> 定義. current 指針指向當前在運行的進程. 在一個系統調用執行期間, 例如 open 或者 read, 當前進程是發出調用的進程. 內核代碼可以通過使用 current 來使用進程特定的信息, 如果它需要這樣.

實際上, current 不真正地是一個全局變量. 支持 SMP 系統的需要強迫內核開發者去開發一種機制, 在相關的 CPU 上來找到當前進程. 這種機制也必須快速, 因為對 current 的引用非常頻繁地發生. 結果就是一個依賴體系的機制, 常常, 隱藏了一個指向 task_struct 的指針在內核堆棧內. 實現的細節對別的內核子系統保持隱藏, 一個設備驅動可以只包含 <linux/sched.h> 並且引用當前進程. 例如, 下面的語句打印了當前進程的進程 ID 和命令名稱, 通過存取結構 task_struct 中的某些字段.

task_struct在linux的定義如下:

  1 struct task_struct {
  2     volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
  3     struct thread_info *thread_info;
  4     atomic_t usage;
  5     unsigned long flags;    /* per process flags, defined below */
  6     unsigned long ptrace;
  7 
  8     int lock_depth;     /* Lock depth */
  9 
 10     int prio, static_prio;
 11     struct list_head run_list;
 12     prio_array_t *array;
 13 
 14     unsigned long sleep_avg;
 15     long interactive_credit;
 16     unsigned long long timestamp;
 17     int activated;
 18 
 19     unsigned long policy;
 20     cpumask_t cpus_allowed;
 21     unsigned int time_slice, first_time_slice;
 22 
 23     struct list_head tasks;
 24     /*
 25     * ptrace_list/ptrace_children forms the list of my children
 26     * that were stolen by a ptracer.
 27     */
 28     struct list_head ptrace_children;
 29     struct list_head ptrace_list;
 30 
 31     struct mm_struct *mm, *active_mm;
 32 
 33 /* task state */
 34     struct linux_binfmt *binfmt;
 35     int exit_code, exit_signal;
 36     int pdeath_signal; /* The signal sent when the parent dies */
 37     /* ??? */
 38     unsigned long personality;
 39     int did_exec:1;
 40     pid_t pid;
 41     pid_t tgid;
 42     /* 
 43     * pointers to (original) parent process, youngest child, younger sibling,
 44     * older sibling, respectively. (p->father can be replaced with 
 45     * p->parent->pid)
 46     */
 47     struct task_struct *real_parent; /* real parent process (when being debugged) */
 48     struct task_struct *parent; /* parent process */
 49     /*
 50     * children/sibling forms the list of my children plus the
 51     * tasks I'm ptracing.
 52     */
 53     struct list_head children; /* list of my children */
 54     struct list_head sibling;   /* linkage in my parent's children list */
 55     struct task_struct *group_leader;   /* threadgroup leader */
 56 
 57     /* PID/PID hash table linkage. */
 58     struct pid_link pids[PIDTYPE_MAX];
 59 
 60     wait_queue_head_t wait_chldexit;    /* for wait4() */
 61     struct completion *vfork_done;      /* for vfork() */
 62     int __user *set_child_tid;      /* CLONE_CHILD_SETTID */
 63     int __user *clear_child_tid;        /* CLONE_CHILD_CLEARTID */
 64 
 65     unsigned long rt_priority;
 66     unsigned long it_real_value, it_prof_value, it_virt_value;
 67     unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 68     struct timer_list real_timer;
 69     unsigned long utime, stime, cutime, cstime;
 70     unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; /* context switch counts */
 71     u64 start_time;
 72 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
 73     unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
 74 /* process credentials */
 75     uid_t uid,euid,suid,fsuid;
 76     gid_t gid,egid,sgid,fsgid;
 77     struct group_info *group_info;
 78     kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 79     int keep_capabilities:1;
 80     struct user_struct *user;
 81 /* limits */
 82     struct rlimit rlim[RLIM_NLIMITS];
 83     unsigned short used_math;
 84     char comm[16];
 85 /* file system info */
 86     int link_count, total_link_count;
 87 /* ipc stuff */
 88     struct sysv_sem sysvsem;
 89 /* CPU-specific state of this task */
 90     struct thread_struct thread;
 91 /* filesystem information */
 92     struct fs_struct *fs;
 93 /* open file information */
 94     struct files_struct *files;
 95 /* namespace */
 96     struct namespace *namespace;
 97 /* signal handlers */
 98     struct signal_struct *signal;
 99     struct sighand_struct *sighand;
100 
101     sigset_t blocked, real_blocked;
102     struct sigpending pending;
103 
104     unsigned long sas_ss_sp;
105     size_t sas_ss_size;
106     int (*notifier)(void *priv);
107     void *notifier_data;
108     sigset_t *notifier_mask;
109     
110     void *security;
111     struct audit_context *audit_context;
112 
113 /* Thread group tracking */
114    u32 parent_exec_id;
115    u32 self_exec_id;
116 /* Protection of (de-)allocation: mm, files, fs, tty */
117     spinlock_t alloc_lock;
118 /* Protection of proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */
119     spinlock_t proc_lock;
120 /* context-switch lock */
121     spinlock_t switch_lock;
122 
123 /* journalling filesystem info */
124     void *journal_info;
125 
126 /* VM state */
127     struct reclaim_state *reclaim_state;
128 
129     struct dentry *proc_dentry;
130     struct backing_dev_info *backing_dev_info;
131 
132     struct io_context *io_context;
133 
134     unsigned long ptrace_message;
135     siginfo_t *last_siginfo; /* For ptrace use. */
136 
137 #ifdef CONFIG_NUMA
138 struct mempolicy *mempolicy;
139 short il_next;      /* could be shared with used_math */
140 #endif
141 };

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。這時,內核禁止某些操作,例如不允許重新調度。

 

 

轉自:http://blog.csdn.net/echoisland/article/details/6729061


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM