操做系統三大功能:數據結構
進程描述符task_struct數據結構atom
task _ struct:爲了管理進程,內核必須對每一個進程進行清晰的描述,進程描述符提供了內核所需瞭解的進程信息。spa
進程的狀態:Linux進程的狀態(就緒態、運行態、阻塞態)操作系統
進程的標示pid:用來標示進程線程
進程描述符task_struct數據結構(重要部分):3d
1 struct task_struct { 2 volatile long state; /* 進程的運行狀態-1 unrunnable, 0 runnable, >0 stopped */ 3 void *stack; /*指定了進程的內核堆棧*/ 4 atomic_t usage; 5 unsigned int flags; /* 每個進程的標識符 */ 6 7 int on_rq; /*運行隊列*/ 8 9 pid_t pid; /*進程標識符*/ 10 11 struck list_head task; /*進程鏈表*/ 12 13 /*父子進程*/ 14 struct task_struct __rcu *real_parent; /* real parent process */ 15 struct task_struct __rcu *parent; 16 17 struct list_head children; /* list of my children */
start _ kernel代碼中的rest _ init建立兩個內核線程,kernel _ init和kthreadd。調試
kernel _ init將用戶態進程init啓動,是全部用戶態進程的祖先。rest
kthreadd是全部內核線程的祖先。code
0號進程是全部線程的祖先。(0號進程時手工寫的)orm
fork一個子進程的代碼:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 int main(int argc, char * argv[]) 5 { 6 int pid; 7 /* fork another process */ 8 pid = fork(); 9 if (pid < 0) 10 { 11 /* error occurred */ 12 fprintf(stderr,"Fork Failed!"); 13 exit(-1); 14 } 15 else if (pid == 0) 16 { 17 /* child process */ 18 printf("This is Child Process!\n"); 19 } 20 else 21 { 22 /* parent process */ 23 printf("This is Parent Process!\n"); 24 /* parent will wait for the child to complete*/ 25 wait(NULL); 26 printf("Child Complete!\n"); 27 } 28 }
這裏特別說明一下:else if和if兩個模塊的代碼都會被執行,子進程和父進程都會返回,子進程返回0,父進程返回子進程pid。
1. 刪除menu,克隆新的menu。
2.查看help
3.gdb調試
4.設置斷點
5.單步追蹤
總結:
新的進程從哪裏開始?
1 *childregs = *current_pt_regs(); //複製內核堆棧 2 childregs->ax = 0; //爲何子進程的fork返回0,這裏就是緣由! 3 4 p->thread.sp = (unsigned long) childregs; //調度到子進程時的內核棧頂 5 p->thread.ip = (unsigned long) ret_from_fork; //調度到子進程時的第一條指令地址
Linux經過複製父進程來建立一個新進程:複製父進程PCB--task_struct來建立一個新進程,要給新進程分配一個新的內核堆棧。
修改複製過來的進程數據,好比pid、進程鏈表等等執行copy_process和copy_thread。
設置sp調度到子進程時的內核棧頂,ip轉到子進程時的第一條指令地址
以後,當子進程得到CPU的控制權開始運行的時候,ret _ form _ fork能夠將後面的堆棧出棧,從iret返回到用戶態,從而切換到子進程的用戶空間,完成新進程的建立。