Linux fork()一個進程內核態的變化
阿新 • • 發佈:2018-10-14
roc arch thread tdi 數據 我們 stderr 比較 哪裏
【前言】用戶態的變化,耳熟能詳不在贅述。現在支持讀時共享,寫時復制。
一、內核態的變化
1、fork一個子進程代碼
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char * argv[]) { int pid; /* fork another process */ pid = fork(); if (pid < 0) { /* error occurred */ fprintf(stderr,"Fork Failed!"); exit(-1); } else if (pid == 0) { /* child process */ printf("This is Child Process!\n"); } else { /* parent process */ printf("This is Parent Process!\n"); /* parent will wait for the child to complete*/ wait(NULL); printf("Child Complete!\n"); } }
2、創建一個新進程在內核中的執行過程
fork、vfork和clone三個系統調用都可以創建一個新進程,而且都是通過調用do_fork來實現進程的創建;
3、Linux通過復制父進程來創建一個新進程,那麽這就給我們理解這一個過程提供一個想象的框架:
(1)復制一個PCB——task_struct
err = arch_dup_task_struct(tsk, orig);
(2)要給新進程分配一個新的內核堆棧
(註意,是內核棧,不是用戶堆棧,用戶態的是復制的)
ti = alloc_thread_info_node(tsk, node); tsk->stack = ti; setup_thread_stack(tsk, orig); //這裏只是復制thread_info,而非復制內核堆棧
(3)要修改復制過來的進程數據,比如pid、進程鏈表等等都要改改吧,見copy_process內部。
4、從用戶態的代碼看fork()----子進程從哪裏開始執行?
函數返回了兩次,即在父子進程中各返回一次,父進程從系統調用中返回比較容易理解,子進程從系統調用中返回,那它在系統調用處理過程中的哪裏開始執行的呢?這就涉及子進程的內核堆棧數據狀態和task_struct中thread記錄的sp和ip的一致性問題,這是在哪裏設定的?copy_thread in copy_process
*childregs = *current_pt_regs(); //復制內核堆棧 childregs->ax = 0; //為什麽子進程的fork返回0,這裏就是原因! p->thread.sp = (unsigned long) childregs; //調度到子進程時的內核棧頂 p->thread.ip = (unsigned long) ret_from_fork; //調度到子進程時的第一條指令地址
Linux fork()一個進程內核態的變化