2020301918-os/kern/wait.c

113 lines
3.4 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 <mmu.h>
#include <errno.h>
#include <x86.h>
#include <kern/syscall.h>
#include <kern/wait.h>
#include <kern/process.h>
#include <kern/pmap.h>
#include <kern/sche.h>
#include <kern/kmalloc.h>
/*
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)
{
// 相比于fork来说wait的实现简单很多
// 语义实现比较清晰没有fork那么多难点要处理所以这里并不会给大家太多引导
// 需要大家自己思考wait怎么实现。
// 在实现之前你必须得读一遍文档`man 2 wait`
// 了解到wait大概要做什么
// panic("Unimplement! Read The F**king Manual");
// 当然读文档是一方面,最重要的还是代码实现
// wait系统调用与exit系统调用关系密切所以在实现wait之前需要先读一遍exit为好
// 可能读完exit的代码你可能知道wait该具体做什么了
// panic("Unimplement! Read The F**king Source Code");
again:
while (xchg(&p_proc_ready->pcb.lock, 1) == 1)
schedule();
PROCESS_0 *p_fa = &p_proc_ready->pcb;
int child_pid = -1;
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语义吗
done:
xchg(&p_fa->lock, 0);
// panic("Unimplement! soul torture");
return child_pid;
}
ssize_t
do_wait(int *wstatus)
{
assert((uintptr_t)wstatus < KERNBASE);
assert((uintptr_t)wstatus + sizeof(wstatus) < KERNBASE);
return kern_wait(wstatus);
}