1. 程式人生 > >Linux fork()一個進程內核態的變化

Linux fork()一個進程內核態的變化

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()一個進程內核態的變化