系列文章 : [6.1810] 跟著 MIT 6.1810 學習基礎作業系統觀念
// Pass p's abandoned children to init.
// Caller must hold wait_lock.
void
reparent(struct proc *p)
{
struct proc *pp;
for(pp = proc; pp < &proc[NPROC]; pp++){
if(pp->parent == p){
pp->parent = initproc;
wakeup(initproc);
}
}
}
struct proc *p 所有的 children-processinitproc
wait 去回收 children-process 的資源 ( 假如 children-process exit 的話 )struct proc *p 要呼叫 kexit 結束執行的時候,會去呼叫。因為每個 process 都需要有 parent,當原本的 parent 結束自己的生命週期,停止執行的時候,需要讓 initproc 成為新的 parent。// A fork child's very first scheduling by scheduler()
// will swtch to forkret.
void
forkret(void)
{
kernel space function。因為在 allocproc function 這邊,會將 p->context.ra = (uint64)forkret;。在 CPU-scheduler-thread 挑選到這個 struct-proc 的時候,會去執行 forkret。user space function 會是 parent process 的下一道 instruction,因為 kfork 會把 parent process 的 struct-proc->trapframe 複製給 child process,而 trapframe 裡面包含 epc,也就是從 kernel space return 回 user space 的時候,Program Counter 會被設定的值。 extern char userret[];
static int first = 1;
struct proc *p = myproc();
// Still holding p->lock from scheduler.
release(&p->lock);
if (first) {
// File system initialization must be run in the context of a
// regular process (e.g., because it calls sleep), and thus cannot
// be run from main().
fsinit(ROOTDEV);
first = 0;
// ensure other cores see first=0.
__sync_synchronize();
// We can invoke kexec() now that file system is initialized.
// Put the return value (argc) of kexec into a0.
p->trapframe->a0 = kexec("/init", (char *[]){ "/init", 0 });
if (p->trapframe->a0 == -1) {
panic("exec");
}
}
sleep,所以需要在一般的 process 下進行初始化,而這個 initproc 正是開機以來的第一個 process。fsinit ),所以可以使用 kexec。 // return to user space, mimicing usertrap()'s return.
prepare_return();
uint64 satp = MAKE_SATP(p->pagetable);
uint64 trampoline_userret = TRAMPOLINE + (userret - trampoline);
((void (*)(uint64))trampoline_userret)(satp);
}
MAKE_SATP,將 pagetabe 指標轉換成 satp register 的格式virtual address。kernel/trampoline.S/userret 這個 function。void
setkilled(struct proc *p)
{
acquire(&p->lock);
p->killed = 1;
release(&p->lock);
}
kexit 去結束掉自己的生命。int
killed(struct proc *p)
{
int k;
acquire(&p->lock);
k = p->killed;
release(&p->lock);
return k;
}
去判斷一個 process 是否已經被 kill 掉了。
// Copy to either a user address, or kernel address,
// depending on usr_dst.
// Returns 0 on success, -1 on error.
int
either_copyout(int user_dst, uint64 dst, void *src, uint64 len)
{
user space 或是 kernel space。目的地 ( destination ) 可以是 user space 或是 kernel space。 struct proc *p = myproc();
if(user_dst){
return copyout(p->pagetable, dst, src, len);
} else {
memmove((char *)dst, src, len);
return 0;
}
}
// Copy from either a user address, or kernel address,
// depending on usr_src.
// Returns 0 on success, -1 on error.
int
either_copyin(void *dst, int user_src, uint64 src, uint64 len)
{
user space 或是 kernel space 複製資料到 kernel space。來源 ( source ) 可以是 user space 或是 kernel space。 struct proc *p = myproc();
if(user_src){
return copyin(p->pagetable, dst, src, len);
} else {
memmove(dst, (char*)src, len);
return 0;
}
}
// Print a process listing to console. For debugging.
// Runs when user types ^P on console.
// No lock to avoid wedging a stuck machine further.
void
procdump(void)
{
static char *states[] = {
[UNUSED] "unused",
[USED] "used",
[SLEEPING] "sleep ",
[RUNNABLE] "runble",
[RUNNING] "run ",
[ZOMBIE] "zombie"
};
struct proc *p;
char *state;
printf("\n");
for(p = proc; p < &proc[NPROC]; p++){
if(p->state == UNUSED)
continue;
if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
state = states[p->state];
else
state = "???";
printf("%d %s %s", p->pid, state, p->name);
printf("\n");
}
}
非 UNUSED 的 process 的資訊,是個方便 debug 的好工具。ctrl+p,就可以執行這個 function 來 dump 所有 struct-proc 的資訊