orange's学习--第十章:fork()函数的实现

模仿Minix中也有个INIT进程,作为用户进程的祖先。

Init进程将来会fork出子进程,那么Init的所有内存范围都将被复制到新的位置,并在那里运行。如果Init用与其他进程相同的处理方法,使用0~4GB的扁平空间作为LDT描述符,那么我们在内存中将找不到另一块空间来存放它——在32位系统中,4GB是全部内存空间。那么Init进程的内存应该被限制在怎样的范围之内呢?最简单的思路就是,内核有多大,Init进程的内存空间就有多大,这样不但大大缩小了进程占用的内存,而且可以保证对read(  )、write(  )等所有库函数的调用都是合法的。你可能会说,Init进程还可以更小,没错,因为内核中的大部分代码对Init是不会直接调用的,但更小的Init将会增加代码的复杂程度,所以我们还是偷个懒,用整个内核占用的内存来当做Init的内存范围。这个范围就是kernel.bin文件的ELF内存范围,用现成的工具(如readelf)可以很容易地得到。init进程执行fork()函数时,会把父进程init进程的所有内容(就是kernel.bin的所有内容)都复制到新的子进程内存里面,浪费很多。

由于子进程复制了父进程所有的内容(包含进程表和程序内存内容),所以子进程的eip位置和父进程一样等待fork函数的返回值(因为程序编译都是编译成ELF文件是和偏移地址有关的仅仅基地址不同是可以执行的)。子进程由于(复制)使用了跟父进程几乎一样的进程表,所以目前也是挂起状态,我们需要给它也发一个消息,这样不但解除其阻塞,而且将零作为返回值传递给子进程,以便让它知道自己的身份。对于父进程,do_fork(  )正常返回后会由MM的主消息循环发送消息给它,我们只需要在do_fork(  )中给mm_msg.PID赋值就好了。

进程生出子进程的时候,可能已经打开了文件,我们需要在父进程和子进程之间共享文件,所以我们需要通知FS,由它来完成相应的工作。只有共享了文件,父进程和子进程才不至于在写文件时发生相互覆盖的情况。而且正是由于需要共享文件,所以f_desc_table[ ]才不能被并入进程表中。假设进程P生成了进程C,那么P和C共享使用f_desc_table[  ]中的同一个file_desc结构,这时fd_cnt为2,表明有两个进程在使用这一结构。等进程P或C退出时,fd_cnt自减。若P和C都已退出,fd_cnt自减为零,这时系统应将fd_inode赋值为零,这样这个f_desc_tabel[ ]条目就又可被使用了。

(内存分配方案)在这里我们就使用了一种十分老土的方案,那就是划定格子,每个格子大小固定。有新的进程需要内存,就给它一个格子,而且这个进程在整个生命周期中,只能使用这个格子的内存。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值