本文共 2112 字,大约阅读时间需要 7 分钟。
asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, struct pt_regs regs){#ifdef CONFIG_MMU return do_fork(SIGCHLD, regs.spu, ®s, 0, NULL, NULL);#else return -EINVAL;#endif /* CONFIG_MMU */}
/* * This is trivial, and on the face of it looks like it * could equally well be done in user mode. * * Not so, for quite unobvious reasons - register pressure. * In user mode vfork() cannot have a stack frame, and if * done by calling the "clone()" system call directly, you * do not have enough call-clobbered registers to hold all * the information you need. */asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, struct pt_regs regs){ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, ®s, 0, NULL, NULL);}
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, unsigned long parent_tidptr, unsigned long child_tidptr, unsigned long r4, unsigned long r5, unsigned long r6, struct pt_regs regs){ if (!newsp) newsp = regs.spu; return do_fork(clone_flags, newsp, ®s, 0, (int __user *)parent_tidptr, (int __user *)child_tidptr);}
fork 、 vfork 、clone函数最终都是调用do_fork,只是传递的参数不同,重点在于clone_flags参数的不同。fork传递的只有SIGCHLD, vfork传递的是CLONE_VFORK | CLONE_VM | SIGLCHLD。而clone函数可操作性比较大,可以自主设置clone_flags。
1.vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
2.fork要拷贝父进程的进程环境;而vfork则不需要完全拷贝父进程的进程环境,在子进程没有调用exec和exit之前,子进程与父进程共享进程环境(观察源码发现主要是CLONE_VM,共享用户虚拟地址空间),此时父进程阻塞等待。
为什么会有vfork呢?
因为以前的fork当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,然后将会有两种行为:
1.执行从父进程那里拷贝过来的代码段
2.调用一个exec执行一个新的代码段
当进程调用exec函数时,一个新程序替换了当前进程的正文,数据,堆和栈段。这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork。vfork并不复制父进程的进程环境,子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。
因此,如果创建子进程是为了调用exec执行一个新的程序的时候,就应该使用vfork
转载地址:http://ciumi.baihongyu.com/