- 论坛徽章:
- 0
|
>>如果此时返回值为零,意味着CPU已经在执行子程序。那是不是说在fork()函数在其创建子进程之后,函数返回一个返回值之前,调度算法已经完成了一次从父进程到子进程的调度?
对于子进程,返回值为0,而和调度无关
>>我猜想在fork()中会不会出现这样的情况:
fork()
{
//此处为创建子进程的代码;
//可能发生进程切换;
if(...)//当前为父进程;
return child_pid;
else //当前为子进程;
return 0;
}
fork是系统调用,不会发生进程切换
如果你看内核代码就知道秘密全在copy_thread函数中
fork为子进程创建一新的PCB(task_struct),该PCB中还有内核栈.fork通过对子进程的内核栈的一点改动来让子进程知道自己是子进程。
即childregs->eax = 0;//子进程的fork返回值为0
这样,子进程被调度时,eax寄存器从内核栈恢复,而eax就是fork的返回值,这样,子进程通过判断该值为0,代码的执行就出现分支。
if(fork())
{
父进程
}
else
{
子进程
}
//smpboot.c中的fork_by_hand,regs是栈上分配的,并没有初始化,不需要
int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
unsigned long unused,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
//childregs指向子进程中的用户空间寄存器结构
childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
struct_cpy(childregs, regs);//从父进程全部复制用户空间寄存器结构,regs对idle1...n无意义
childregs->eax = 0;//子进程的fork返回值为0
childregs->esp = esp;//子进程的用户空间堆栈指针为esp,如果调用do_fork时没有设,将等于父进程的
p->thread.esp = (unsigned long) childregs;//子进程第一次被调度进来时的esp,idle1...idlen也象模象样地指向,其实永远也不会用到
p->thread.esp0 = (unsigned long) (childregs+1);//进程进入系统0环的堆栈指针
p->thread.eip = (unsigned long) ret_from_fork;//进程换入时的eip,从ret_from_fork返回
savesegment(fs,p->thread.fs);
savesegment(gs,p->thread.gs);
unlazy_fpu(current);//保存当前进程的fpu现场
struct_cpy(&p->thread.i387, ¤t->thread.i387);//现场复制到子进程中
return 0;
} |
|