fork()的底層實現

當進程調用fork後,當控制轉移到內核中的fork代碼後,內核會做4件事情:

1.分配新的內存塊和內核數據結構給子進程

2.將父進程部分數據結構內容(數據空間,堆棧等)拷貝至子進程

3.添加子進程到系統進程列表當中

4.fork返回,開始調度器調度

fork()函數的底層實現:

Linux通過clone()系統調用實現fork()。這個調用通過一系列的參數標誌來指明父、子進程需要共享的資源。fork()、vfork()和_clone()庫函數都根據各自需要的參數標誌去調用clone()。然後由clone()去調用do_fork()do_fork完成了創建中的大部分工作,它的定義在kernel/fork.c文件中。該函數調用copy_process()函數,然後讓進程開始運行。copy_process()函數做的具體事情:

  調用dup_task_struct()爲新進程創建一個內核棧、thread_info結構和task_stuct,這些值與當前進程的值相同。此時,子進程和父進程的描述符是完全相同的。

  檢查新創建的這個子進程後,當前用戶所擁有的進程數目沒有超出給他分配的資源的限制。

現在,子進程着手使自已與父進程區別開來。進程描述符內的許多成員都要被清0或設爲初始值。進程描述符的成員值並不是繼承而來的,而主要是統計信息。進程描述符中的大多數數據都是共享的。

  接下來,子進程的狀態被設置爲TASK_UNINTERRUPTIBLE以保證它不會投入運行。

  copy_process()調用copy_flags()以更新task_struct的flags成員。表明進程是否擁有超級用戶權限的PF_SUPERPRIV標誌被清0。表明進程還沒有調用excc()函數的PF_FORKNOEXEC標誌被設置。

  調用get_pid()爲新進程獲取一個有效的PID。

  根據傳遞給clone()的參數標誌,copy_process()拷貝共享打開的文件、文件系統信息、信號處理函數、進程地址空間和命名空間等。在一般情況下,這些資源會被給定進程的所有線程共享;否則,這些資源對每個進程是不同的,因此被拷貝到這裏。

讓父進程和子進程平分剩餘的時間片。最後,copy_process()作掃尾工作並返回一個指向子進程的指針。

  再回到do_fork()函數,如果copy_pocess函數成功返回,新創建的子進程被喚醒並讓其投入運行。內核有意選擇子進程首先執行。因爲一般子進程都會馬上調用excc()函數,這樣可以避免寫時拷貝的額外開銷,如果父進程首先執行的話,有可能會開始向地址空間寫入。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章