第六週 linux內核進程的建立

1.task_struct數據結構分析html

  對於linux而言,每一個進程都有一個進程控制PCB(process control block)來保存每一個進程的相關信息。其中task_struct則是PCB的具體的數據結構經過內核代碼能夠發現,內核當中定義一個task_struct的結構體用來保存進程的相關信息。這裏先來分析下task_struct的結構體。task_struct的代碼以下:linux

  http://codelab.shiyanlou.com/xref/linux-3.18.6/include/linux/sched.h#1235數據結構

 1 #define  TASK_RUNNING       0
 2 #define TASK_INTERRUPTIBLE  1   
 3 #define TASK_UNINTERRUPTIBLE    2
 4 #define __TASK_STOPPED      4
 5 #define __TASK_TRACED       8
 6 /* in tsk->exit_state */
 7 #define EXIT_DEAD       16
 8 #define EXIT_ZOMBIE     32      
 9 #define EXIT_TRACE      (EXIT_ZOMBIE | EXIT_DEAD)
10 /* in tsk->state again */
11 #define TASK_DEAD       64
12 #define TASK_WAKEKILL       128
13 #define TASK_WAKING     256
14 #define TASK_PARKED     512
15 #define TASK_STATE_MAX      1024

這裏能夠看到定義了進程的相關運行狀態,這裏特殊的地方在於TASK_RUNNING這裏將運行態和就緒態的進程都用TASK_RUNNING表示。學習

進程狀態之間切換以下ui

1 pid_t pid;
2 pid_t tgid;

pid以及tpid的區別以下this

http://blog.chinaunix.net/uid-26849197-id-3201487.htmlspa

簡單說來,就是對於同一進程的不一樣線程而言pid不一樣,可是tgid相同.net

1 struct list {
2     struct list *next, *prev;
3 };

這裏顯示的內核進程鏈表的實現,內核經過這個鏈表實現進程間調度等等的功能。線程

1 struct task_struct __rcu *real_parent; /* real parent process */
2 struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
3 /*
4  * children/sibling forms the list of my natural children
5  */
6 struct list_head children;    /* list of my children */
7 struct list_head sibling;    /* linkage in my parent's children list */
8 struct task_struct *group_leader;    /* threadgroup leader */

以上是進程之間父子關係的代碼,經過這些代碼,能夠用來訪問父進程以及子進程,這樣在fork新進程時能夠用來複制相關的數據。unix

1 union thread_union {
2     struct thread_info thread_info;
3     unsigned long stack[THREAD_SIZE/sizeof(long)];
4 };

每一個進程都有8kb的內存用來存放 thread_info以及進程的內核堆棧

 1 * CPU-specific state of this task */
 2     struct thread_struct thread;
 3 /* filesystem information */
 4     struct fs_struct *fs;
 5 /* open file information */
 6     struct files_struct *files;
 7 /* namespaces */
 8     struct nsproxy *nsproxy;
 9 /* signal handlers */
10     struct signal_struct *signal;
11     struct sighand_struct *sighand;

這段這是表示CPU的工做狀態,以及文件系統和文件描述符的管理

1 struct mm_struct *mm, *active_mm;

這裏則是進程的內存管理

2 .實驗以及進程建立過程的分析 

  咱們知道子進程用於父進程相同的堆棧數據,卻擁有不一樣的堆棧空間,因此咱們能夠猜測到內核建立進程的過程當中須要將父進程的數據複製到子進程當中。實際上內核也是這麼處理進程複製的。進程的複製主要分爲如下幾步

  1. 複製PCB數據
  2. 給子進程分配內核堆棧
  3. 修改子進程的數據(如pid等)
  4. 設置返回地址(ret_from_fork)

其程序流程圖以下:

爲了證明以上的流程圖,現利用gdb對進程進行調試,實驗以下:

能夠看到程序之間的相互調用正如以前程序圖所描述的那樣。

3 .總結

這章主要學習了子進程在內核中具體是如何建立的,能夠看到子進程建立主要思想是將父進程的堆棧數據複製過來,而後進行相關的修改,從而是實現新進程的建立。這裏的返回地址須要咱們額外的關心,能夠看到返回地址在copy_thread中被設置成ret_from_fork,跟蹤ret_from_fork能夠看到子進程的開始執行的地址正是系統調用的返回地址。這也解釋了爲何fork能夠同時返回兩個值而且同時能夠進行判斷的緣由。

相關文章
相關標籤/搜索