UNIX v6 的fork系统调用实现分析 - webdancer's Blog
UNIX v6 的fork系统调用实现分析
最近一直在阅读《莱昂氏unix代码分析》,硬件的基础有点差,PDP11结构也是不太清楚,汇编语言也不行。有很多的疑问,现在还是看一看unix v6 中的fork系统调用如何实现的呢?
/* */ #include "../param.h" #include "../user.h" #include "../proc.h" #include "../text.h" #include "../systm.h" #include "../file.h" #include "../inode.h" #include "../buf.h" /* ------------------------- */ /* * Create a new process-- the internal version of * sys fork. * It returns 1 in the new process. * How this happens is rather hard to understand. * The essential fact is that the new process is created * in such a way that it appears to have started executing * in the same call to newproc as the parent; * but in fact the code that runs is that of swtch. * The subtle implication of the return value of swtch * (see above) is that this is the value that newproc’s * caller in the new process sees. */ newproc()//无参数 { int a1, a2; struct proc *p, *up; register struct proc *rpp; register *rip, n; p = NULL; /* * First, just locate a slot for a process * and copy the useful info from this process into it.//为新建的进程寻找存储槽,并复制有用的信息。 * The panic "cannot happen" because fork already * checked for the existence of a slot. */ retry: mpid++;//mpid,整形值,0-32767之间递增,用作进程号。 if(mpid < 0) { mpid = 0; goto retry; } for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {//在proc数组中,寻找空元素。 if(rpp->p_stat == NULL && p==NULL)//由p_stat来判断,是否为空。 p = rpp; if (rpp->p_pid==mpid) goto retry; } if ((rpp = p)==NULL) panic("no procs"); /* * make proc entry for new proc */ rip = u.u_procp;//当前进程proc项的地址。 up = rip; rpp->p_stat = SRUN; rpp->p_flag = SLOAD; rpp->p_uid = rip->p_uid; rpp->p_ttyp = rip->p_ttyp; rpp->p_nice = rip->p_nice; rpp->p_textp = rip->p_textp; rpp->p_pid = mpid; rpp->p_ppid = rip->p_ppid; rpp->p_time = 0; /* * make duplicate entries * where needed//复制打开文件。 */ for(rip = &u.u_ofile[0]; rip < &u.u_ofile[NOFILE];) if((rpp = *rip++) != NULL) rpp->f_count++; if((rpp=up->p_textp) != NULL) { rpp->x_count++; rpp->x_ccount++; } u.u_cdir->i_count++; /* * Partially simulate the environment * of the new process so that when it is actually * created (by copying) it will look right. */ savu(u.u_rsav);//保存环境和栈指针。 rpp = p; u.u_procp = rpp; rip = up; n = rip->p_size; a1 = rip->p_addr; rpp->p_size = n; a2 = malloc(coremap, n);//申请内存。 /* * If there is not enough core for the * new process, swap put the current process to * generate the copy. */ if(a2 == NULL) {//申请不到内存。 rip->p_stat = SIDL; rpp->p_addr = a1; savu(u.u_ssav); xswap(rpp, 0, 0); rpp->p_flag =| SSWAP; rip->p_stat = SRUN; } else { /* * There is core, so just copy. */ rpp->p_addr = a2; while(n--) copyseg(a1++, a2++); } u.u_procp = rip; return(0); }
总结一下过程:
1.首先,应该为进程取得一个惟一的进程号。
2.将当前进程的proc复制到新进程的proc结构。
3.将当前进程的打开文件复制到新进程,同时增加文件引用。
4.进行内存分配,如果内存不足,则放入交换区,否则,分配内存。
UNIX的proc数组,当前LINUX是一个task_struct 结构的双向链表,结构更加复杂。但是,实现的基本思想应该变化不大。