系列文章 : [6.1810] 跟著 MIT 6.1810 學習基礎作業系統觀念
// initialize the proc table.
void
procinit(void)
{
struct proc *p;
initlock(&pid_lock, "nextpid");
initlock(&wait_lock, "wait_lock");
for(p = proc; p < &proc[NPROC]; p++) {
initlock(&p->lock, "proc");
p->state = UNUSED;
p->kstack = KSTACK((int) (p - proc));
}
}
// Allocate a page for each process's kernel stack.
// Map it high in memory, followed by an invalid
// guard page.
void
proc_mapstacks(pagetable_t kpgtbl)
{
struct proc *p;
for(p = proc; p < &proc[NPROC]; p++) {
char *pa = kalloc();
if(pa == 0)
panic("kalloc");
uint64 va = KSTACK((int) (p - proc));
kvmmap(kpgtbl, va, (uint64)pa, PGSIZE, PTE_R | PTE_W);
}
}
kalloc 配置實體 RAM,並且會為 root-kernel-page-table 配置每一個 kernel process 的 kernel stack 的 pa <-> va 映射。int
allocpid()
{
int pid;
acquire(&pid_lock);
pid = nextpid;
nextpid = nextpid + 1;
release(&pid_lock);
return pid;
}
// Look in the process table for an UNUSED proc.
// If found, initialize state required to run in the kernel,
// and return with p->lock held.
// If there are no free procs, or a memory allocation fails, return 0.
static struct proc*
allocproc(void)
{
struct proc *p;
UNUSED 的 struct-proc。假如有找到的話,就會該 struct-proc 進行初始化 ( allocates a PID, a trapframe page, a trampoline page, an empty page table )。重要的是,這邊回傳的 struct-proc,是已經取得 struct-proc->lock 的狀態! 呼叫這個 function 的 caller,有義務要解這個鎖。 for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == UNUSED) {
goto found;
} else {
release(&p->lock);
}
}
return 0;
遍尋 global-process-table,看有沒有 UNUSED 的 struct-proc。
found:
p->pid = allocpid();
p->state = USED;
// Allocate a trapframe page.
if((p->trapframe = (struct trapframe *)kalloc()) == 0){
freeproc(p);
release(&p->lock);
return 0;
}
RUNNABLE。UNUSED。 // An empty user page table.
p->pagetable = proc_pagetable(p);
if(p->pagetable == 0){
freeproc(p);
release(&p->lock);
return 0;
}
為這個新的 process 配置一塊新的 pagetable。
// Set up new context to start executing at forkret,
// which returns to user space.
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
return p;
}
在 kernel space 會跳去的 PC ( program counter ) 值。// free a proc structure and the data hanging from it,
// including user pages.
// p->lock must be held.
static void
freeproc(struct proc *p)
{
不會去 release struct-proc->lock,caller 要記得去 release。 if(p->trapframe)
kfree((void*)p->trapframe);
p->trapframe = 0;
假如 trapframe 存在,則 free 掉 trapfame。
if(p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
p->pagetable = 0;
假如 pagetable 存在,則 free 掉 pagetable。
p->sz = 0;
p->pid = 0;
p->parent = 0;
p->name[0] = 0;
p->chan = 0;
p->killed = 0;
p->xstate = 0;
p->state = UNUSED;
}
reset 所有相關的 struc-proc 的 field。
// Create a user page table for a given process, with no user memory,
// but with trampoline and trapframe pages.
pagetable_t
proc_pagetable(struct proc *p)
{
pagetable_t pagetable;
trampoline
trapframe
// An empty page table.
pagetable = uvmcreate();
if(pagetable == 0)
return 0;
// map the trampoline code (for system call return)
// at the highest user virtual address.
// only the supervisor uses it, on the way
// to/from user space, so not PTE_U.
if(mappages(pagetable, TRAMPOLINE, PGSIZE,
(uint64)trampoline, PTE_R | PTE_X) < 0){
uvmfree(pagetable, 0);
return 0;
}
// map the trapframe page just below the trampoline page, for
// trampoline.S.
if(mappages(pagetable, TRAPFRAME, PGSIZE,
(uint64)(p->trapframe), PTE_R | PTE_W) < 0){
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmfree(pagetable, 0);
return 0;
}
return pagetable;
}
// Free a process's page table, and free the
// physical memory it refers to.
void
proc_freepagetable(pagetable_t pagetable, uint64 sz)
{
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmunmap(pagetable, TRAPFRAME, 1, 0);
uvmfree(pagetable, sz);
}
freewalk function 會真的去 free 掉這個 pagetablekfree((void*)pagetable);
// Set up first user process.
void
userinit(void)
{
struct proc *p;
p = allocproc();
initproc = p;
p->cwd = namei("/");
p->state = RUNNABLE;
release(&p->lock);
}
forkret function 裡面,假如看到是第一個 user process,會讓該 user process kexec(“/init”...)
// Shrink user memory by n bytes.
// Return 0 on success, -1 on failure.
int
growproc(int n)
{
uint64 sz;
struct proc *p = myproc();
sz = p->sz;
if(n > 0){
if((sz = uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) {
return -1;
}
} else if(n < 0){
sz = uvmdealloc(p->pagetable, sz, sz + n);
}
p->sz = sz;
return 0;
}
uvmalloc 進行 allocate。uvmdealloc 進行 deallocate。