.
ret_from_fork
分析fork函數(shù)對應(yīng)的系統(tǒng)調(diào)用處理過程
啟動保護fork命令的menuOS
設(shè)置斷點進行調(diào)試
進程的創(chuàng)建
從了解進程的創(chuàng)建,進程間調(diào)度切換蹬挺,來從總體把握進程工作
當(dāng)前進程復(fù)制一個子進程肄梨,然后進行修改
fork一個子進程的代碼
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc , char * argv[])
{
int pid;
pid = fork();
if(pid<0)
{
fprintf(stderr,"Fork Failed !");
exit(-1);
}
else if (pid==0)
{
printf("This is Child Process!\n");
}
else
{
printf("This is Parent Process !\n");
wait(NULL);
printf("Child Complete!\n:);
}
}
-fork()是用戶態(tài)用于創(chuàng)建子進程的系統(tǒng)調(diào)用
-pid<0時打印出錯信息
-子進程中fork()返回值為0奥邮,父進程中fork()返回值為進程pid值
-所以else if和else都將被執(zhí)行
理解進程創(chuàng)建過程復(fù)雜代碼的方法
創(chuàng)建一個新進程在內(nèi)核中的執(zhí)行過程
-fork、vfork和clone三個系統(tǒng)調(diào)用都可以創(chuàng)建一個新進程关顷,而且都是通過調(diào)用do_fork來實現(xiàn)進程的創(chuàng)建
-創(chuàng)建新進程是通過復(fù)制當(dāng)前進程來實現(xiàn)
-復(fù)制一個PCB task_struct
-給新進程分配一個新內(nèi)核堆棧
-修改進程數(shù)據(jù)如pid、進程鏈表等
-從用戶態(tài)代碼中可以看到fork()函數(shù)返回兩次武福,在父進程和子進程中各返回一次议双,父進程從系統(tǒng)調(diào)用中返回,子進程從系統(tǒng)調(diào)用中返回涉及了子進程的內(nèi)核堆棧數(shù)據(jù)狀態(tài)和task_struct中thread記錄的sp和ip的一致性問題捉片,在copy_thread in copy_process里設(shè)定
do_fork
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
{
struct task_struct *p;
int trace = 0;
long nr;
/*
* Determine whether and which event to report to ptracer. When
* called from kernel_thread or CLONE_UNTRACED is explicitly
* requested, no event is reported; otherwise, report if the event
* for the type of forking is enabled.
*/
if (!(clone_flags & CLONE_UNTRACED)) {
if (clone_flags & CLONE_VFORK)
trace = PTRACE_EVENT_VFORK;
else if ((clone_flags & CSIGNAL) != SIGCHLD)
trace = PTRACE_EVENT_CLONE;
else
trace = PTRACE_EVENT_FORK;
if (likely(!ptrace_event_enabled(current, trace)))
trace = 0;
}
p = copy_process(clone_flags, stack_start, stack_size,
child_tidptr, NULL, trace);
/*
* Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly.
*/
if (!IS_ERR(p)) {
struct completion vfork;
struct pid *pid;
trace_sched_process_fork(current, p);
pid = get_task_pid(p, PIDTYPE_PID);
nr = pid_vnr(pid);
if (clone_flags & CLONE_PARENT_SETTID)
put_user(nr, parent_tidptr);
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
get_task_struct(p);
}
wake_up_new_task(p);
/* forking complete and child started to run, tell ptracer */
if (unlikely(trace))
ptrace_event_pid(trace, pid);
if (clone_flags & CLONE_VFORK) {
if (!wait_for_vfork_done(p, &vfork))
ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
}
put_pid(pid);
} else {
nr = PTR_ERR(p);
}
return nr;
}
copy process創(chuàng)建進程內(nèi)容
-dup_task_struct復(fù)制pcb平痰,分配新空間
-然后初始化賦值子進程信息
-copy thread從子進程pid內(nèi)核堆棧位置棧底汞舱,拷貝內(nèi)核堆棧數(shù)據(jù)和指定新進程的第一條指令地址
創(chuàng)建的新進程從哪里開始執(zhí)行
·p->thread.ip = (unsigned long) ret_from_fork;·
ret_from_fork返回了子進程調(diào)度的第一條指令
在復(fù)制內(nèi)核堆棧時只復(fù)制了其中一部分SAVE_ALLL相關(guān)的部分,int指令和cpu壓棧內(nèi)容宗雇,即最棧底的部分
ret_from_fork會跳轉(zhuǎn)syscall exit兵拢,最終返回用戶態(tài),此時返回到子進程用戶空間
所以創(chuàng)建的新進程從ret_from_fork開始執(zhí)行
王瀟洋
原創(chuàng)作品轉(zhuǎn)載請注明出處
《Linux內(nèi)核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000