gdb調試執行流程,首先設置斷點b sys_clone,當在shell下輸入fork命令後,系統執行至斷點,接下來按步執行:
- 判斷是否被跟蹤
- 判斷是否被建立爲輕量級進程(vfork)
- 判斷父進程是否被跟蹤,
- 判斷是否子進程獲取新的PID或命名空間,若是是,則不容許其共享進程組、信號handler或父進程
- task_create在複製以前確認共享的權限
- 調用dup_task_struct複製task_struct(進程描述符)
- alloc_task_struct_node爲task_struct分配內存
- alloc_thread_info_node爲thread_info分配內存
- setup_thread_stack爲進程新建一個內核棧
- copy_semundo
- copy_files
- copy_fs
- copy_sighand
- copy_signal
- copy_mm
- copy_namespaces
- copy_io
- 進入copy_thread
- struct pt_regs *childregs = task_pt_regs(p);給指針賦值,指向.thread.regs
- *childregs = *current_pt_regs();複製寄存器內容
- childregs->ax = 0; 給子進程pid返回值0;
- p->thread.ip = (unsigned long)ret_from_fork;子進程從ret_from_fork開始執行。
- ret_from_fork位於entry.S。子進程執行ret_from_fork後轉到syscall_exit
- 父進程copy_thread完成,返回copy_process
- 給新進程分配新pid
- 設置子進程pid
- 子進程接下來進行關中斷,檢查信號(信號量不共享則不復制),繼續restore_all最後恢復上下文,從內核態返回,繼續執行程序中的代碼。
- 父進程返回sys_clone,父進程執行fork()以後的代碼。最後程序結束。
總結:
- 進程(task)是處於執行期的程序,一般還包括打開的文件,掛起的信號,內核內部數據,處理器狀態,一個或多個具備內存映射的內存地址空間及一個或多個執行線程,還有存放全局變量的數據段等。
- 線程是在進程中活動的對象。linux:不特別區分進程線程,線程是特殊的進程。
- 在現代Linux內核中,fork其實是由clone系統調用實現的。
- fork從內核返回兩次,一個回到父進程,一次回到產生的新的子進程。
- 程序經過exit()系統調用退出執行。此函數會終結進程並將其佔用的資源釋放掉。父進程能夠經過wait4()系統調用查詢子進程是否終結,這使進程擁有了等待特定進程執行完畢的能力。進程退出執行後被設置僵死狀態。
- Linux系統經過c庫提供wait(),waitpid(),wait3(),wait4()等函數。
- 內核把進程的列表存放在任務隊列(task list)雙向列表中,表中每項都是task_struct,被稱爲進程描述符,定義在<linux/sched.h>中。內核經過一個惟一的進程標示值PID來標記進程。PID爲pid_t類型,實際爲int。
- 進程狀態:
-
- TASK_RUNNING表示進程可執行。
- TASK_INTERRUPTIBLE可中斷。進程正在睡眠(阻塞),等待信號。
- TASK_UNINTERRUPTIBLE不可中斷。處於此狀態不受信號喚醒。其它同上。
- _TASK_TRACED被其餘進程跟蹤的進程。
- _TASK_STOPPED進程沒有投入運行也不能投入運行。
- Unix將產生機制分解爲fork和exec。fork複製exec負責讀取可執行文件並將其載入地址空間開始運行。
- fork採用寫時拷貝頁實現。頁的拷貝推遲到實際發生寫入時。
- 內核有意選擇子進程先執行,由於通常子進程立刻會調用exec()。以免寫時拷貝的開銷。
- 完成fork調用後存在兩個進程,每一個進程都會從fork()返回處繼續執行。
- fork,vfork,clone都調用do_fork,vfork不拷貝父進程的頁表。clone帶參數。
參考文獻:node
《Linux內核設計與實現》linux
By:崑崙雪狐shell
原創做品轉載請註明出處函數
《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000spa