陳鐵 + 原創作品轉載請註明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000
Linux內核對進程管理是操作系統的重要任務之一。此次實驗就是了解內核創建一個新進程的大致過程。爲了簡單,使用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"); } }
在虛擬機環境中運行情況如下圖:
以下使用gdb調試一下,在進程創建過程中的幾個關鍵函數出設置斷點。
在系統啓動過程走了些彎路,設置斷點的這幾個函數都是系統創建進程所必須的關鍵部分,所以啓動過程中do_fork,copy_process,copy_thread不斷的多次出現,我只好暫時使斷點失效,才讓menuos順利啓動到命令提示符。disable breakpoints 1 2 3 4 5 6.
執行fork命令,停在了斷點SyS_clone處,單步執行,定在了斷點do_fork處。經過幾行代碼,
p = copy_process(clone_flags, stack_start,stack_size,chile_tidptr, NULL,trace);
停在斷點copy_process.在執行幾行代碼,如下:
p = dup_task_struct(current);
繼續執行,斷點arch_dup_task_struct停住。
連續n命令後可以看到子進程的初始化過程:
程序執行斷在copy_thread後如下:
執行finish,及continue命令,進入了子進程執行的起點ret_from_fork.
執行c命令,主要過程基本結束。
總結,創建一個新進程在內核中的執行過程大致如下
1.使用系統調用SyS_clone(或fork,vfork)系統調用創建一個新進程,而且都是通過調用do_fork來實現進程的創建;
2.Linux通過複製父進程PCB--task_struct來創建一個新進程,要給新進程分配一個新的內核堆棧;
3.要修改複製過來的進程數據,比如pid、進程鏈表等等執行copy_process和copy_thread
4.p->thread.sp = (unsigned long) childregs; //調度到子進程時的內核棧頂
p->thread.ip = (unsigned long) ret_from_fork; //調度到子進程時的第一條指令地址