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

來源:互聯網
上載者:User

http://www.cnblogs.com/chingliu/archive/2011/08/29/2223803.html

 儘管核心模組不象應用程式一樣順序執行, 核心做的大部分動作是代表一個特定進程的. 核心代碼可以引用當前進程, 通過存取全域項 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 中的某些欄位.

printk(KERN_INFO "The process is \"%s\" (pid %i)\n", current->comm, current->pid);存於 current->comm的命令名稱是由當前進程執行的程式檔案的基本名稱( 截短到 15 個字元, 如果需要 ).

task_struct在linux的定義如下:

struct task_struct {
    volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    struct thread_info *thread_info;
    atomic_t usage;
    unsigned long flags;    /* per process flags, defined below */
    unsigned long ptrace;

    int lock_depth;     /* Lock depth */

    int prio, static_prio;
    struct list_head run_list;
    prio_array_t *array;

    unsigned long sleep_avg;
    long interactive_credit;
    unsigned long long timestamp;
    int activated;

    unsigned long policy;
    cpumask_t cpus_allowed;
    unsigned int time_slice, first_time_slice;

    struct list_head tasks;
    /*
    * ptrace_list/ptrace_children forms the list of my children
    * that were stolen by a ptracer.
    */
    struct list_head ptrace_children;
    struct list_head ptrace_list;

    struct mm_struct *mm, *active_mm;

/* task state */
    struct linux_binfmt *binfmt;
    int exit_code, exit_signal;
    int pdeath_signal; /* The signal sent when the parent dies */
    /* ??? */
    unsigned long personality;
    int did_exec:1;
    pid_t pid;
    pid_t tgid;
    /* 
    * pointers to (original) parent process, youngest child, younger sibling,
    * older sibling, respectively. (p->father can be replaced with 
    * p->parent->pid)
    */
    struct task_struct *real_parent; /* real parent process (when being debugged) */
    struct task_struct *parent; /* parent process */
    /*
    * children/sibling forms the list of my children plus the
    * tasks I'm ptracing.
    */
    struct list_head children; /* list of my children */
    struct list_head sibling;   /* linkage in my parent's children list */
    struct task_struct *group_leader;   /* threadgroup leader */

    /* PID/PID hash table linkage. */
    struct pid_link pids[PIDTYPE_MAX];

    wait_queue_head_t wait_chldexit;    /* for wait4() */
    struct completion *vfork_done;      /* for vfork() */
    int __user *set_child_tid;      /* CLONE_CHILD_SETTID */
    int __user *clear_child_tid;        /* CLONE_CHILD_CLEARTID */

    unsigned long rt_priority;
    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;
    unsigned long utime, stime, cutime, cstime;
    unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; /* context switch counts */
    u64 start_time;
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
    unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
/* process credentials */
    uid_t uid,euid,suid,fsuid;
    gid_t gid,egid,sgid,fsgid;
    struct group_info *group_info;
    kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
    int keep_capabilities:1;
    struct user_struct *user;
/* limits */
    struct rlimit rlim[RLIM_NLIMITS];
    unsigned short used_math;
    char comm[16];
/* file system info */
    int link_count, total_link_count;
/* ipc stuff */
    struct sysv_sem sysvsem;
/* CPU-specific state of this task */
    struct thread_struct thread;
/* filesystem information */
    struct fs_struct *fs;
/* open file information */
    struct files_struct *files;
/* namespace */
    struct namespace *namespace;
/* signal handlers */
    struct signal_struct *signal;
    struct sighand_struct *sighand;

    sigset_t blocked, real_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;
    
    void *security;
    struct audit_context *audit_context;

/* Thread group tracking */
   u32 parent_exec_id;
   u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty */
    spinlock_t alloc_lock;
/* Protection of proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */
    spinlock_t proc_lock;
/* context-switch lock */
    spinlock_t switch_lock;

/* journalling filesystem info */
    void *journal_info;

/* VM state */
    struct reclaim_state *reclaim_state;

    struct dentry *proc_dentry;
    struct backing_dev_info *backing_dev_info;

    struct io_context *io_context;

    unsigned long ptrace_message;
    siginfo_t *last_siginfo; /* For ptrace use. */

#ifdef CONFIG_NUMA
struct mempolicy *mempolicy;
short il_next;      /* could be shared with used_math */
#endif
};

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.