Linux核心學習筆記二——進程

來源:互聯網
上載者:User

一 進程與線程

       進程就是處於執行期的程式,包含了獨立地址空間,多個執行線程等資源。

       線程是進程中活動的對象,每個線程都擁有獨立的程式計數器、進程棧和一組進程寄存器。

       核心調度的對象是線程而不是進程。對Linux而言,線程是特殊的進程。

二 進程描述符及任務結構

       核心使用雙向迴圈鏈表的任務隊列來存放進程,使用結構體task_struct來描述進程所有資訊。

1 進程描述符task_struct

       struct task_struct {}結構體相當大,大約1.7K位元組。大概列出一些看看:

    

 

2 分配進程描述符

  當進程由於中斷或系統調用從使用者態轉換到核心態時,進程所使用的棧也要從使用者棧切換到核心棧。

通過核心棧擷取棧尾thread_info,就可以擷取當前進程描述符task_struct。

每個進程的thread_info結構在他的核心棧的尾端分配。結構中task域中存放是指向該任務實際的task_struct。

    

 

       核心處理進程就是通過進程描述符task_struct結構體對象來操作。所以操作進程要擷取當前正在啟動並執行進程描述符。

通過thread_info的地址就可以找到task_struct地址;在不同的體繫結構上計算thread_info的位移地址不同。

/* linux-2.6.38.8/arch/arm/include/asm/current.h */ static inline struct task_struct *get_current(void) {     return current_thread_info()->task; } #define current (get_current()) /* linux-2.6.38.8/arch/arm/include/asm/thread_info.h */  static inline struct thread_info *current_thread_info(void) {   //棧指標    register unsigned long sp asm ("sp");     return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); }

 

 

3 進程的狀態

       系統中的每個進程都必然處於五種進程狀態中的一種或進行切換。該域的值也必為下列五種狀態標誌之一:

TASK_RUNNING(運行)—進程是可執行檔;它或者正在執行,或者在運行隊列中等待執行(運行隊列將會在第4章中討論)。

這是進程在使用者空間中執行的唯一可能的狀態;這種狀態也可以應用到核心空間中正在執行的進程。

 

TASK_INTERRUPTIBLE(可中斷)—進程正在睡眠(也就是說它被阻塞),等待某些條件的達成。一旦這些條件達成,

核心就會把進程狀態設定為運行。處於此狀態的進程也會因為接收到訊號而提前被喚醒並隨時準備投入運行。

 

TASK_UNINTERRUPTIBLE(不可中斷)—除了就算是接收到訊號也不會被喚醒或準備投入運行外,這個狀態與可打斷狀態相同。

這個狀態通常在進程必須在等待時不受幹擾或等待事件很快就會發生時出現。由於處於此狀態的任務對訊號不做響應,

所以較之可中斷狀態,使用得較少。

 

__TASK_TRACED—被其他進程跟蹤的進程,例如通過ptrace對偵錯工具進行跟蹤。

 

__TASK_STOPPED(停止)—進程停止執行;進程沒有投入運行也不能投入運行。通常這種狀態發生在接收到SIGSTOP、

SIGTSTP、SIGTTIN、SIGTTOU等訊號的時候。此外,在調試期間接收到任何訊號,都會使進程進入這種狀態。 

 

三 進程建立

       fork:copy當前進程建立一個新的進程;     

exec:讀取可執行檔並將其載入地址空間開始運行。

1 fork過程

       建立進程都是通過調用do_fork函數完成,其中提供了很多參數標誌來表明進程建立的方式。

long do_fork(unsigned long clone_flags,             unsigned long stack_start,             struct pt_regs *regs,             unsigned long stack_size,             int __user *parent_tidptr,             int __user *child_tidptr){    struct task_struct *p;    ……    //建立進程    p = copy_process(clone_flags, stack_start, regs, stack_size,                   child_tidptr, NULL, trace);    ……    //將進程加入到運行隊列中    wake_up_new_task(p);}

 

 

copy_process裡面通過父進程建立子進程,並未執行:

task_struct *copy_process(unsigned long clone_flags,                                   unsigned long stack_start,                                   struct pt_regs *regs,                                   unsigned long stack_size,                                   int __user *child_tidptr,                                   struct pid *pid,                                   int trace){       struct task_struct *p;       //建立進程核心棧和進程描述符       p = dup_task_struct(current);       //得到的進程與父進程內容完全一致,初始化新建立進程       ……       return p;}

 

 

dup_task_struct根據父進程建立子進程核心棧和進程描述符:

static struct task_struct *dup_task_struct(struct task_struct *orig){       struct task_struct *tsk;       struct thread_info *ti;       int node = tsk_fork_get_node(orig);       //建立進程描述符對象       tsk = alloc_task_struct_node(node);
//建立進程核心棧 thread_info ti = alloc_thread_info_node(tsk, node); //使子進程描述符和父進程一致 err = arch_dup_task_struct(tsk, orig); //進程描述符stack指向thread_info tsk->stack = ti; //使子進程thread_info內容與父進程一致但task指向子進程task_struct setup_thread_stack(tsk, orig); return tsk;}

建立進程copy_process之後並未執行,返回到do_fork中,將新建立進程加入到運行隊列中等待被執行。

 

四 線程在Linux中的實現與核心線程

       線程機制提供了在同一個程式共用記憶體位址空間,檔案等資源的一組線程。在Linux核心中把所有線程都當做進程來實現。

核心並沒有提供調度演算法,或者資料結構來表徵線程,而是作為與其他進程共用資源的進程;與其他系統不同。

       核心線程與普通進程間的區別是:

              核心線程沒有獨立的地址空間

              只在核心空間運行,不會切換到使用者空間

五 進程終結

       進程終結時核心釋放其所佔有的資源,並告訴父進程,更新父子關係。調用exit終結進程,進程被終結時通常最後都要調用do_exit來處理。

     

void do_exit(long code){       //擷取當前運行進程       struct task_struct *tsk = current;       ……        //sets PF_EXITING       exit_signals(tsk);       //釋放task_struct的mm_struct記憶體       exit_mm(tsk);       //退出接收IPC訊號隊列       exit_sem(tsk);       //進程名字空間       exit_shm(tsk);       //檔案描述符       exit_files(tsk);       //檔案系統       exit_fs(tsk);       //資源釋放       exit_thread();       //向父進程發送訊號       exit_notify(tsk, group_dead);       ……       //切換到其他進程       tsk->state = TASK_DEAD;       tsk->flags |= PF_NOFREEZE;       schedule();       ……}

 

相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

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

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