20135103王海甯
《Linux核心分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000
這周的實驗是通過gdb跟蹤調試Linux核心是如何fock産生一個程序并從哪開始執行這個子程序的。
下面就進入實驗樓的環境開始實驗,輸入以下指令重新下載下傳編譯,如圖:
[plain] view plain copy
- rm menu -rf
- git clone https://github.com/mengning/menu.git
- cd menu
- mv test_fork.c test.c
- make rootfs
檢視test.c裡面的代碼如下:
啟動menuOS後停止等待,開啟gdb調試:
打好斷點:
接着在menuOS界面輸入fork運作:
切換回shell指令行界面,輸入continue指令,走起:
fork執行完成後,運作結果如下圖:
分析
1.程序間的狀态轉換
2.新程序的産生
話說,道生一(start_kernel、cpu_idle)、一生二(kernel_init和kthreadd)、二生三(即前面0,1和2三個程序)
1号程序是所有使用者态程序祖先、0号程序是所有核心線程的祖先。
程序描述符PCB的資料結構是task_struct類型,它包括了程序相關的所有資訊,task_struct結構中主要有:
-程序狀态(記錄程序等待、運作或死鎖三種狀态)
-排程資訊
-辨別符
-程序間的通訊情況
-程序連結資訊(程序連結清單的插入等操作資訊)
-時間和定時器資訊
-檔案系統資訊
-頁面管理資訊
-和處理器相關的環境上下文資訊
-...
其中:
1)state字段。用于描述程序目前的狀态,由一組标志組成,每個标志描述一種程序可能的狀态,這些狀态的是互斥的。
2)thread_info字段。Linux核心用共用體結構将一個程序的線程描述符和核心堆棧
union thread_union{
struct thread_info thread_info;
unsigned long stack[2048];
}
3)task字段。所有的程序的描述符組成了一個雙向連結清單,task字段的類型為list_head。
struct list_head{
struct list_head *next,*prev;
start_kernel中建立0号程序,由0号程序建立1号程序,1号程序是所有使用者态程序的祖先,0号程序是所有核心程序的祖先。使用者态程式通過調用 fork建立一個有父子關系的新程序。 通過copy_thread複制現有程序實作建立新程序,先複制task_struct,再為其配置設定一個核心棧,接着copy_process進行修改,如程序pid、程序連結清單等。fork、vfork和clone三個系統調用都可建立一個新程序,但都是通過do_fork實作的。
複制過程為:
1)err = arch_dup_task_struct(tsk, orig); // 複制一個task_struct資料結構的PCB
2)ti = alloc_thread_info_node(tsk, node); tsk->stack = ti; // 給新程序配置設定一個核心堆棧
3)setup_thread_stack(tsk, orig); // 這裡隻是複制thread_info,而非複制核心堆棧
4)*childregs = *current_pt_regs(); // 複制核心堆棧
5)childregs->ax = 0; // 子程序的fork傳回0的原因
建立好後執行到ret_from_fork,在ret_from_fork中會跳到syscall_exit,此時父程序的核心棧中儲存了執行fork前的上下文,子程序的核心棧中也從父程序那裡複制到的自己的上下文,是以現在父子程序可以等待被排程後正常執行啦。
總結:
在Linux中建立新程序中,用fork得到的子程序是父程序的複制,它從父程序處複制了整個程序的位址空間,包括進
程上下文、程序堆棧、記憶體資訊、打開的檔案描述符、信号控制設定、程序優先級、程序組号、目前工作目錄、根目錄、資源限制、控制終端等。子程序所獨有的隻是它的程序号、資源使用和計時器等。
1.無論用三種系統調用clone、fork、vfork中的哪種來建立一個新程序,都是通過調用do_fork來實作的
2.通過複制父程序PCB的task_struct建立一個新程序
3.子程序修改複制後的PCB,如pid、程序連結清單等
4.fork()系統調用産生的子程序從ret_from_fork處開始執行,p->thread.ip = (unsigned long)ret_from_fork
5.可通過傳回值判斷目前程序是父程序還是子程序,父程序處傳回程序号,子程序自己傳回0