2020301918-os/kern/fork.c

89 lines
4.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <assert.h>
#include <x86.h>
#include <errno.h>
#include <kern/fork.h>
#include <kern/syscall.h>
#include <kern/trap.h>
ssize_t
kern_fork(PROCESS_0 *p_fa)
{
// 这可能是你第一次实现一个比较完整的功能,你可能会比较畏惧
// 但是放心,别怕,先别想自己要实现一个这么大的东西而毫无思路
// 这样你在焦虑的同时也在浪费时间,就跟你在实验五中被页表折磨一样
// 人在触碰到未知的时候总是害怕的,这是天性,所以请你先冷静下来
// fork系统调用会一步步引导你写出来不会让你本科造火箭的
// panic("Unimplement! CALM DOWN!");
// 推荐是边写边想,而不是想一车然后写,这样非常容易计划赶不上变化
//? before all, lock father
while (xchg(&p_fa->lock, 1) == 1)
schedule();
// fork的第一步你需要找一个空闲IDLE的进程作为你要fork的子进程
PROCESS_0 *p_child = NULL;
int i = 0;
//? maybe cli will be better when preserving a proc resource
DISABLE_INT();
for (i = 1; i < PCB_SIZE; ++ i) {
if (proc_table[i].pcb.statu == IDLE) {
proc_table[i].pcb.statu = INITING;
p_child = &proc_table[i];
break;
}
}
ENABLE_INT();
if (p_child == NULL) {
// NO hell. no free proc_table found.
xchg(&p_fa->lock, 0);
return ENOMEM;
}
// 再之后你需要做的是好好阅读一下pcb的数据结构搞明白结构体中每个成员的语义
// 别光扫一遍,要搞明白这个成员到底在哪里被用到了,具体是怎么用的
// 可能exec和exit系统调用的代码能够帮助你对pcb的理解不先理解好pcb你fork是无从下手的
// panic("Unimplement! read pcb");
// 在阅读完pcb之后终于可以开始fork工作了
// 本质上相当于将父进程的pcb内容复制到子进程pcb中
// 但是你需要想清楚,哪些应该复制到子进程,哪些不应该复制,哪些应该子进程自己初始化
// 其中有三个难点
// 1. 子进程"fork"的返回值怎么处理?(需要你对系统调用整个过程都掌握比较清楚,如果非常清晰这个问题不会很大)
// 2. 子进程内存如何复制别傻乎乎地复制父进程的cr3本质上相当于与父进程共享同一块内存
// 而共享内存肯定不符合fork的语义这样一个进程写内存某块地方会影响到另一个进程这个东西需要你自己思考如何复制父进程的内存
// 3. 在fork结束后肯定会调度到子进程那么你怎么保证子进程能够正常进入用户态
// (你肯定会觉得这个问题问的莫名其妙的,只能说你如果遇到那一块问题了就会体会到这个问题的重要性,
// 这需要你对调度整个过程都掌握比较清楚)
//? Start to COPY
//? 1. COPY PCB
*p_child = *p_fa; // anyway, first copy all
p_child->cr3 = 0;
p_child->fork_tree.p_fa = NULL;
p_child->fork_tree.sons = NULL;
p_child->page_list = NULL;
// the null before is just a reminder to change them
p_child->pid = i; // well, for simplicity, let pid be index in proc table
p_child->user_regs.eax = 0; //! maybe, set user_ctx.eax as the retval?
//? 2. ALLOC PAGES AND COPY PHYSICAL MEMORY
//TODO see how to copy the pages from parent
//? 3. SET OTHER CHILD STATUS
// 别忘了维护进程树,将这对父子进程关系添加进去
panic("Unimplement! maintain process tree");
// 最后你需要将子进程的状态置为READY说明fork已经好了子进程准备就绪了
panic("Unimplement! change status to READY");
// 在你写完fork代码时先别急着运行跑先要对自己来个灵魂拷问
// 1. 上锁上了吗?所有临界情况都考虑到了吗?(永远要相信有各种奇奇怪怪的并发问题)
// 2. 所有错误情况都判断到了吗错误情况怎么处理RTFM->`man 2 fork`
// 3. 你写的代码真的符合fork语义吗
panic("Unimplement! soul torture");
return 0;
}
ssize_t
do_fork(void)
{
return kern_fork(&p_proc_ready->pcb);
}