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 结构的双向链表,结构更加复杂。但是,实现的基本思想应该变化不大。




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee