diff --git a/kern/fork.c b/kern/fork.c index 5165f2b..b42b4d0 100644 --- a/kern/fork.c +++ b/kern/fork.c @@ -125,7 +125,7 @@ kern_fork(PROCESS_0 *p_fa) if (proc_child == NULL) { // NO hell. no free proc_table found. xchg(&p_fa->lock, 0); - return ENOMEM; + return -EAGAIN; } PROCESS_0 *p_child = &proc_child->pcb; // 再之后你需要做的是好好阅读一下pcb的数据结构,搞明白结构体中每个成员的语义 diff --git a/kern/main.c b/kern/main.c index 87e6057..d0f3df4 100644 --- a/kern/main.c +++ b/kern/main.c @@ -40,7 +40,7 @@ void kernel_main(void) p_proc->priority = p_proc->ticks = 1; // 在实现了exec系统调用后main函数的负担就少了 // 只需要调用一个函数接口就能实现进程的加载 - if (do_exec("testfork.bin") < 0) + if (do_exec("initproc.bin") < 0) panic("init process failed"); // 切换tss tss.esp0 = (u32)(&p_proc->user_regs + 1); diff --git a/kern/wait.c b/kern/wait.c index 16fd9bf..94992f6 100644 --- a/kern/wait.c +++ b/kern/wait.c @@ -1,9 +1,23 @@ #include #include +#include +#include #include #include +#include +#include +#include +#include +/* +The wait() system call suspends execution of the calling thread + until one of its children terminates. +RETURN VALUE +on success, returns the process ID of the terminated child; +on failure, -1 is returned. +! however the testwait.bin expects a valued return other than simply -1 +*/ ssize_t kern_wait(int *wstatus) { @@ -13,21 +27,82 @@ kern_wait(int *wstatus) // 在实现之前你必须得读一遍文档`man 2 wait` // 了解到wait大概要做什么 - panic("Unimplement! Read The F**king Manual"); + // panic("Unimplement! Read The F**king Manual"); // 当然读文档是一方面,最重要的还是代码实现 // wait系统调用与exit系统调用关系密切,所以在实现wait之前需要先读一遍exit为好 // 可能读完exit的代码你可能知道wait该具体做什么了 - panic("Unimplement! Read The F**king Source Code"); + // panic("Unimplement! Read The F**king Source Code"); + PROCESS_0 *p_fa = &p_proc_ready->pcb; + int child_pid = -1; +again: + while (xchg(&p_fa->lock, 1) == 1) + schedule(); + struct son_node* p_son = p_fa->fork_tree.sons; + if (p_son == NULL) { + xchg(&p_fa->lock, 0); + return -ECHILD; + } + assert(p_son->pre == NULL); // make sure it is the head of the list + while (p_son != NULL) { + if (p_son->p_son->statu == ZOMBIE) { +/* +struct s_proc { +user_regs; // let it be +kern_regs; // let it be +lock; // get and release before kfree +statu; // set to IDLE +pid; // keep it util return +cr3; // let it be +page_list; // recycle it +exit_code; // set to wstatus +priority; // let it be +ticks; // let it be +fork_tree; // already cleared +}; +*/ + while (xchg(&p_son->p_son->lock, 1) == 1) + schedule(); + // just use this value, which is '(status & 0xFF) << 8' in exit.c::do_exit + if (wstatus != NULL) + *wstatus = p_son->p_son->exit_code; + // recycle_pages in pmap.c + recycle_pages(p_son->p_son->page_list); + // free it in proc table, 'cause in fork I judge free by statu + p_son->p_son->statu = IDLE; + // remove p_son from p_fa's son list + if (p_son->pre != NULL) { + p_son->pre->nxt = p_son->nxt; + } + else { + p_fa->fork_tree.sons = p_son->nxt; + } + if (p_son->nxt != NULL) { + p_son->nxt->pre = p_son->pre; + } + // keep p_son's pid for retval, 'cause the pointer will get freed before return + child_pid = p_son->p_son->pid; + xchg(&p_son->p_son->lock, 0); + kfree(p_son); + goto done; + } + p_son = p_son->nxt; + } + p_fa->statu = SLEEP; + xchg(&p_fa->lock, 0); + schedule(); + goto again; // 接下来就是你自己的实现了,我们在设计的时候这段代码不会有太大问题 // 在实现完后你任然要对自己来个灵魂拷问 // 1. 上锁上了吗?所有临界情况都考虑到了吗?(永远要相信有各种奇奇怪怪的并发问题) // 2. 所有错误情况都判断到了吗?错误情况怎么处理?(RTFM->`man 2 wait`) // 3. 是否所有的资源都正确回收了? // 4. 你写的代码真的符合wait语义吗? - panic("Unimplement! soul torture"); - return 0; +done: + xchg(&p_fa->lock, 0); + // panic("Unimplement! soul torture"); + return child_pid; } ssize_t