以下是基于 linux 0.11 核心的說明。
在init/main.c第138行,
在move_to_user_mode()之後,程序0通過fork()産生子程序,實際就是程序1(init程序)。
在main.c第23行:
通過 _syscall0 調用 fork 。_syscall0 即不帶參數的系統調用:type name(void),_syscall0 的定義在unistd.h中第133行:
在 kernel\sched.c 中的 sched_init 調用 system_call
system_call 位于 kernel\system_call.s 中。在該檔案第94行:
1
調用位址為:_sys_call_table + %eax * 4,此時 exa 的值為2(根據__NR_fork的定義),由于是32位機,指針占4個位元組。
sys_call_table 的定義在 include\linux\sys.h 中第74行:
即調用的是 sys_fork 。
sys_fork 的定義是一段彙編代碼,位于 kernel\system_call.s 第208行:
在 sys_fork 中,有兩個主要的函數調用:_find_empty_process 和 _copy_process 。
_find_empty_process 位于 kernel\fork.c 中第135行,其作用是找到一個空的程序号(對應于一個程序控制塊PCB),在linux 0.11版本中最多支援64個程序(全局數組task定義在sched.h中,數組大小為64):
全局變量last_pid用來記錄上次使用的程序号,其定義在 kernel\fork.c 第22行:
在find_empty_process中,不斷遞增last_pid,尋找第一個未被其它程序使用的程序号作為新程序的程序号。如果遞增後的值超出正數表示範圍,則重新從1開始,并将其傳回值存放在 %eax 中。若沒能找到可用程序号,則跳轉。若找到可用程序号則進行相關壓棧操作,然後調用_copy_process 開始複制程序内容。
_copy_process 的定義位于 kernel\fork.c 第63行:
程序控制塊中還儲存有程序的任務狀态段資料結構tss,用于存儲處理器管理程序的所有資訊。也就是說,在任務切換過程中,首先将處理器中各寄存器的目前值被自動儲存目前程序的tss中;然後,下一程序的tss被加載并從中提取出各個值送到處理器的寄存器中。由此可見,通過在tss中儲存任務現場各寄存器狀态的完整映象,實作任務的切換。
是以,一旦在task[]數組中找到空閑項和程序号,我們就可以為該程序的程序控制塊結構申請一個頁面的記憶體。這個工作是在copy_process() 函數中完成的。
當然copy_process()函數的最主要的任務是為子程序複制父程序資訊,并設定子程序的任務狀态段,其中最關鍵的兩步是:
把子程序tss中的eip設定為父程序系統調用傳回位址,這樣當子程序被排程程式選中後,将從父程序的fork()傳回處開始執行。
把子程序tss中的eax設定為0,而eax是存放函數傳回值的地方,這樣子程序中傳回的是0。注意子程序并沒有執行fork()函數,子程序的系統堆棧沒有進行過操作,當然不會有像父程序那樣的fork函數調用。但是當子程序開始運作時,就好像它從 fork 中傳回一樣。
<code>p->tss.eax = 0;</code>
本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sky-heaven/p/8080501.html,如需轉載請自行聯系原作者