自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux內(nèi)核源碼do_fork分析

系統(tǒng) Linux 系統(tǒng)運(yùn)維
我們都知道進(jìn)程是Linux內(nèi)核中最為重要的一個(gè)抽象概念,那么我們平時(shí)在fork一個(gè)進(jìn)程時(shí),該進(jìn)程究竟是怎么產(chǎn)生的呢? 本篇推送會淺談一下在進(jìn)程創(chuàng)建過程中扮演著重要角色的do_fork函數(shù)。

我們都知道進(jìn)程是Linux內(nèi)核中最為重要的一個(gè)抽象概念,那么我們平時(shí)在fork一個(gè)進(jìn)程時(shí),該進(jìn)程究竟是怎么產(chǎn)生的呢?

本篇推送會淺談一下在進(jìn)程創(chuàng)建過程中扮演著重要角色的do_fork函數(shù)。

內(nèi)核如何來抽象一個(gè)進(jìn)程

 

內(nèi)核通過一個(gè)叫做task_struct的結(jié)構(gòu)體來抽象一個(gè)進(jìn)程,該結(jié)構(gòu)體的定義(以內(nèi)核2.6為例)在include/linux.sched.h中。

截取部分task_struct如下: 

截取部分task_struct 

上述task_struct屬性是我節(jié)選出的部分其結(jié)構(gòu)體中的屬性,我們從中可以大致了解到標(biāo)識一個(gè)進(jìn)程的屬性大致會有該用以表示該進(jìn)程所處的狀態(tài),進(jìn)程的標(biāo)志,以及進(jìn)程是否被其他進(jìn)程跟蹤,進(jìn)程鎖的深度,進(jìn)程的優(yōu)先級,進(jìn)程的pid,進(jìn)程的父母,進(jìn)程的孩子鏈表,進(jìn)程所打開的文件描述符表,進(jìn)程所處的文件系統(tǒng),進(jìn)程的信號。。。。等等一堆我們平時(shí)可能遇到的和進(jìn)程相關(guān)的東西。

do_fork簡單分析 

接觸linuxC編程的人都知道,創(chuàng)建一個(gè)進(jìn)程我們需要調(diào)用fork函數(shù),fork其實(shí)又是調(diào)用了clone函數(shù)來實(shí)現(xiàn)的,而clone函數(shù)中最關(guān)鍵的函數(shù)就是do_fork函數(shù)。

在分析do_fork前我們腦海中可以大致想象一下,進(jìn)程究竟是如何被創(chuàng)建出來的,假如讓你來創(chuàng)建一個(gè)進(jìn)程你會咋么做?

我們可以這樣去分析,既然原來的進(jìn)程被抽象成一個(gè)task_struct,那么新進(jìn)程也是一個(gè)task_struct只不過它里面的一些屬性會不同與原來的task_struct,那么創(chuàng)建一個(gè)新進(jìn)程所要做的工作就是賦值一個(gè)與原來進(jìn)程一樣都的task_struct結(jié)構(gòu),然后然后將新進(jìn)程的task_struct不同于原來task_struct的屬性進(jìn)行修改即可。

do_fork定義在kernel/fork.c文件中。

在分析該函數(shù)之前我們先來分析一下它的函數(shù)的各個(gè)參數(shù)。

參數(shù)如下:  

參數(shù) 

1.clone_flags:該參數(shù)是此函數(shù)中最重要的一個(gè)參數(shù),該值中的每個(gè)位都代表對子進(jìn)程task_struct中的每種屬性的設(shè)置;

2.stack_start:子進(jìn)程用戶態(tài)堆棧的開始地址;

3.regs:當(dāng)系統(tǒng)發(fā)生系統(tǒng)調(diào)用時(shí),需從用戶態(tài)切換到內(nèi)核態(tài),此結(jié)構(gòu)體用來保存此時(shí)用戶態(tài)進(jìn)程中的通用寄存器中的值,并被存放在內(nèi)核態(tài)堆棧中;

4.stack_size:目前未被使用,通常設(shè)為0;

5.parent_tidptr:父進(jìn)程在用戶態(tài)下pid的地址;

6.child_tidptr:子進(jìn)程在用戶態(tài)下pid的地址;

其中clone_flags的標(biāo)志位宏定義如下:  

clone_flags的標(biāo)志位宏定義 

舉個(gè)簡單的例子當(dāng)我們的參數(shù)中設(shè)置了CLONE_VM這個(gè)宏,那么就以為這我們新創(chuàng)建的進(jìn)程和其父進(jìn)程要共享VM,當(dāng)我們設(shè)置了CLONE_FILES時(shí)意味這父子進(jìn)程之間共享打開的文件描述符。

do_fork開始執(zhí)行后首先做的就是為子進(jìn)程定義一個(gè)新的task_struct指針:

struct task_struct *p;

在下來會檢查一些clone_flags所不允許的位組合,例如:

  1. if (clone_flags & CLONE_NEWUSER) {  if (clone_flags & CLONE_THREAD)  return -EINVAL; 
  2.  
  3. }  

上述中不允許同時(shí)既設(shè)置了CLONE_NEWUSER標(biāo)志,還設(shè)置CLONE_THREAD標(biāo)志,這樣就會產(chǎn)生錯(cuò)誤。

類似上面當(dāng)一系列的安全檢查完畢之后,copy_process函數(shù)就登場了,copy_process函數(shù)工作流程具體如下:

1)調(diào)用dup_task_struct函數(shù)為新的進(jìn)程創(chuàng)建一個(gè)內(nèi)核棧,thread_info結(jié)構(gòu)和task_struct等,當(dāng)然此時(shí)的值都是和父進(jìn)程完全一樣的

dup_task_struct函數(shù)定義如下: 

dup_task_struct函數(shù)定義

 

2)檢查并確保新創(chuàng)建該子進(jìn)程后,當(dāng)前用戶所擁有的進(jìn)程數(shù)沒有超出給它分配的資源限制,代碼如下:  

 

3)子進(jìn)程著手使自己與父進(jìn)程區(qū)別開來,從父進(jìn)程那繼承過來的許多屬性都要被清0或設(shè)置一個(gè)初始值,但task_struct中的大多數(shù)數(shù)據(jù)還是未被修改,部分代碼如下:

 

  

 

4)給子進(jìn)程分配一個(gè)CPU,代碼如下:

  1. sched_fork(p, clone_flags); 

5) 接著就是子進(jìn)程拷貝父進(jìn)程的一些資源,具體如下,調(diào)用copy_files函數(shù)拷貝父進(jìn)程打開的文件描述符:   

 

調(diào)用copy_fs繼承父進(jìn)程所屬的文件系統(tǒng)。  

 

調(diào)用copy_signal函數(shù)拷貝并設(shè)置新的signal_struct,signal_struct包含了大量的進(jìn)程運(yùn)行的信息,調(diào)用copy_mm函數(shù)處理與新進(jìn)程的內(nèi)存問題。  

 

調(diào)用copy_io函數(shù)拷貝父進(jìn)程的I/O情況: 

 

還有調(diào)用copy_namespaces 和 copy_thread等,這里就不在贅述。

6)調(diào)用alloc_pid為新進(jìn)程分配一個(gè)pid。

pid = alloc_pid(p->nsproxy->pid_ns);

7)copy_process做一些收尾工作,并返回新進(jìn)程的task_struct指針,此時(shí)再次回到了do_fork,新創(chuàng)建的子進(jìn)程被喚醒,并讓其先投入運(yùn)行。 

 

總結(jié) 

關(guān)于進(jìn)程創(chuàng)建的源碼理解,我感覺主要抓住倆點(diǎn)即可。***進(jìn)程被內(nèi)核抽象成了啥?它的數(shù)據(jù)結(jié)構(gòu)是咋樣的(task_struct)這點(diǎn)我們必須有所認(rèn)識,第二創(chuàng)建進(jìn)程最主要的其實(shí)就是拷貝父進(jìn)程的task_struct里的屬性,但是關(guān)鍵點(diǎn)是拷貝哪些,哪些又是子進(jìn)程和父進(jìn)程所不同的,很簡單我們只需要把握住進(jìn)程創(chuàng)建函數(shù)里的clone_flags參數(shù)就可以知道怎么拷貝了。

責(zé)任編輯:龐桂玉 來源: 西郵Linux興趣小組
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號