From 52a5d090ea9171f68e253412f067666fa4bbf429 Mon Sep 17 00:00:00 2001 From: ridethepig Date: Tue, 22 Nov 2022 00:54:03 +0800 Subject: [PATCH] get familiar with new code and babystep in fork --- .vscode/settings.json | 2 +- kern/fork.c | 44 +++++++++++++++++++++++++++++++++++++------ kern/main.c | 2 +- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d264713..6df04d7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.detectIndentation": false, - "editor.tabSize": 8, + "editor.tabSize": 4, "editor.insertSpaces": false, "files.associations": { "*.h": "c", diff --git a/kern/fork.c b/kern/fork.c index 1a39172..6a93772 100644 --- a/kern/fork.c +++ b/kern/fork.c @@ -1,7 +1,10 @@ #include +#include +#include #include #include +#include ssize_t kern_fork(PROCESS_0 *p_fa) @@ -11,17 +14,34 @@ kern_fork(PROCESS_0 *p_fa) // 这样你在焦虑的同时也在浪费时间,就跟你在实验五中被页表折磨一样 // 人在触碰到未知的时候总是害怕的,这是天性,所以请你先冷静下来 // fork系统调用会一步步引导你写出来,不会让你本科造火箭的 - panic("Unimplement! CALM DOWN!"); + // panic("Unimplement! CALM DOWN!"); // 推荐是边写边想,而不是想一车然后写,这样非常容易计划赶不上变化 - + //? before all, lock father + while (xchg(&p_fa->lock, 1) == 1) + schedule(); // fork的第一步你需要找一个空闲(IDLE)的进程作为你要fork的子进程 - panic("Unimplement! find a idle process"); - + 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"); + // panic("Unimplement! read pcb"); // 在阅读完pcb之后终于可以开始fork工作了 // 本质上相当于将父进程的pcb内容复制到子进程pcb中 @@ -33,7 +53,19 @@ kern_fork(PROCESS_0 *p_fa) // 3. 在fork结束后,肯定会调度到子进程,那么你怎么保证子进程能够正常进入用户态? // (你肯定会觉得这个问题问的莫名其妙的,只能说你如果遇到那一块问题了就会体会到这个问题的重要性, // 这需要你对调度整个过程都掌握比较清楚) - panic("Unimplement! copy pcb?"); + //? 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"); diff --git a/kern/main.c b/kern/main.c index d0f3df4..87e6057 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("initproc.bin") < 0) + if (do_exec("testfork.bin") < 0) panic("init process failed"); // 切换tss tss.esp0 = (u32)(&p_proc->user_regs + 1);