kernel/proc.c
690 lines
1#include "types.h"2#include "param.h"3#include "memlayout.h"4#include "riscv.h"5#include "spinlock.h"6#include "proc.h"7#include "defs.h"89struct cpu cpus[NCPU];1011struct proc proc[NPROC];1213struct proc *initproc;1415int nextpid = 1;16struct spinlock pid_lock;1718extern void forkret(void);19static void freeproc(struct proc *p);2021extern char trampoline[]; // trampoline.S2223// helps ensure that wakeups of wait()ing24// parents are not lost. helps obey the25// memory model when using p->parent.26// must be acquired before any p->lock.27struct spinlock wait_lock;2829// Allocate a page for each process's kernel stack.30// Map it high in memory, followed by an invalid31// guard page.32void33proc_mapstacks(pagetable_t kpgtbl)34{35 struct proc *p;36 37 for(p = proc; p < &proc[NPROC]; p++) {38 char *pa = kalloc();39 if(pa == 0)40 panic("kalloc");41 uint64 va = KSTACK((int) (p - proc));42 kvmmap(kpgtbl, va, (uint64)pa, PGSIZE, PTE_R | PTE_W);43 }44}4546// initialize the proc table.47void48procinit(void)49{50 struct proc *p;51 52 initlock(&pid_lock, "nextpid");53 initlock(&wait_lock, "wait_lock");54 for(p = proc; p < &proc[NPROC]; p++) {55 initlock(&p->lock, "proc");56 p->state = UNUSED;57 p->kstack = KSTACK((int) (p - proc));58 }59}6061// Must be called with interrupts disabled,62// to prevent race with process being moved63// to a different CPU.64int65cpuid()66{67 int id = r_tp();68 return id;69}7071// Return this CPU's cpu struct.72// Interrupts must be disabled.73struct cpu*74mycpu(void)75{76 int id = cpuid();77 struct cpu *c = &cpus[id];78 return c;79}8081// Return the current struct proc *, or zero if none.82struct proc*83myproc(void)84{85 push_off();86 struct cpu *c = mycpu();87 struct proc *p = c->proc;88 pop_off();89 return p;90}9192int93allocpid()94{95 int pid;96 97 acquire(&pid_lock);98 pid = nextpid;99 nextpid = nextpid + 1;100 release(&pid_lock);101102 return pid;103}104105// Look in the process table for an UNUSED proc.106// If found, initialize state required to run in the kernel,107// and return with p->lock held.108// If there are no free procs, or a memory allocation fails, return 0.109static struct proc*110allocproc(void)111{112 struct proc *p;113114 for(p = proc; p < &proc[NPROC]; p++) {115 acquire(&p->lock);116 if(p->state == UNUSED) {117 goto found;118 } else {119 release(&p->lock);120 }121 }122 return 0;123124found:125 p->pid = allocpid();126 p->state = USED;127128 // Allocate a trapframe page.129 if((p->trapframe = (struct trapframe *)kalloc()) == 0){130 freeproc(p);131 release(&p->lock);132 return 0;133 }134135 // An empty user page table.136 p->pagetable = proc_pagetable(p);137 if(p->pagetable == 0){138 freeproc(p);139 release(&p->lock);140 return 0;141 }142143 // Set up new context to start executing at forkret,144 // which returns to user space.145 memset(&p->context, 0, sizeof(p->context));146 p->context.ra = (uint64)forkret;147 p->context.sp = p->kstack + PGSIZE;148149 return p;150}151152// free a proc structure and the data hanging from it,153// including user pages.154// p->lock must be held.155static void156freeproc(struct proc *p)157{158 if(p->trapframe)159 kfree((void*)p->trapframe);160 p->trapframe = 0;161 if(p->pagetable)162 proc_freepagetable(p->pagetable, p->sz);163 p->pagetable = 0;164 p->sz = 0;165 p->pid = 0;166 p->parent = 0;167 p->name[0] = 0;168 p->chan = 0;169 p->killed = 0;170 p->xstate = 0;171 p->state = UNUSED;172}173174// Create a user page table for a given process, with no user memory,175// but with trampoline and trapframe pages.176pagetable_t177proc_pagetable(struct proc *p)178{179 pagetable_t pagetable;180181 // An empty page table.182 pagetable = uvmcreate();183 if(pagetable == 0)184 return 0;185186 // map the trampoline code (for system call return)187 // at the highest user virtual address.188 // only the supervisor uses it, on the way189 // to/from user space, so not PTE_U.190 if(mappages(pagetable, TRAMPOLINE, PGSIZE,191 (uint64)trampoline, PTE_R | PTE_X) < 0){192 uvmfree(pagetable, 0);193 return 0;194 }195196 // map the trapframe page just below the trampoline page, for197 // trampoline.S.198 if(mappages(pagetable, TRAPFRAME, PGSIZE,199 (uint64)(p->trapframe), PTE_R | PTE_W) < 0){200 uvmunmap(pagetable, TRAMPOLINE, 1, 0);201 uvmfree(pagetable, 0);202 return 0;203 }204205 return pagetable;206}207208// Free a process's page table, and free the209// physical memory it refers to.210void211proc_freepagetable(pagetable_t pagetable, uint64 sz)212{213 uvmunmap(pagetable, TRAMPOLINE, 1, 0);214 uvmunmap(pagetable, TRAPFRAME, 1, 0);215 uvmfree(pagetable, sz);216}217218// Set up first user process.219void220userinit(void)221{222 struct proc *p;223224 p = allocproc();225 initproc = p;226 227 p->cwd = namei("/");228229 p->state = RUNNABLE;230231 release(&p->lock);232}233234// Grow or shrink user memory by n bytes.235// Return 0 on success, -1 on failure.236int237growproc(int n)238{239 uint64 sz;240 struct proc *p = myproc();241242 sz = p->sz;243 if(n > 0){244 if(sz + n > TRAPFRAME) {245 return -1;246 }247 if((sz = uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) {248 return -1;249 }250 } else if(n < 0){251 sz = uvmdealloc(p->pagetable, sz, sz + n);252 }253 p->sz = sz;254 return 0;255}256257// Create a new process, copying the parent.258// Sets up child kernel stack to return as if from fork() system call.259int260kfork(void)261{262 int i, pid;263 struct proc *np;264 struct proc *p = myproc();265266 // Allocate process.267 if((np = allocproc()) == 0){268 return -1;269 }270271 // Copy user memory from parent to child.272 if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){273 freeproc(np);274 release(&np->lock);275 return -1;276 }277 np->sz = p->sz;278279 // copy saved user registers.280 *(np->trapframe) = *(p->trapframe);281282 // Cause fork to return 0 in the child.283 np->trapframe->a0 = 0;284285 // increment reference counts on open file descriptors.286 for(i = 0; i < NOFILE; i++)287 if(p->ofile[i])288 np->ofile[i] = filedup(p->ofile[i]);289 np->cwd = idup(p->cwd);290291 safestrcpy(np->name, p->name, sizeof(p->name));292293 pid = np->pid;294295 release(&np->lock);296297 acquire(&wait_lock);298 np->parent = p;299 release(&wait_lock);300301 acquire(&np->lock);302 np->state = RUNNABLE;303 release(&np->lock);304305 return pid;306}307308// Pass p's abandoned children to init.309// Caller must hold wait_lock.310void311reparent(struct proc *p)312{313 struct proc *pp;314315 for(pp = proc; pp < &proc[NPROC]; pp++){316 if(pp->parent == p){317 pp->parent = initproc;318 wakeup(initproc);319 }320 }321}322323// Exit the current process. Does not return.324// An exited process remains in the zombie state325// until its parent calls wait().326void327kexit(int status)328{329 struct proc *p = myproc();330331 if(p == initproc)332 panic("init exiting");333334 // Close all open files.335 for(int fd = 0; fd < NOFILE; fd++){336 if(p->ofile[fd]){337 struct file *f = p->ofile[fd];338 fileclose(f);339 p->ofile[fd] = 0;340 }341 }342343 begin_op();344 iput(p->cwd);345 end_op();346 p->cwd = 0;347348 acquire(&wait_lock);349350 // Give any children to init.351 reparent(p);352353 // Parent might be sleeping in wait().354 wakeup(p->parent);355 356 acquire(&p->lock);357358 p->xstate = status;359 p->state = ZOMBIE;360361 release(&wait_lock);362363 // Jump into the scheduler, never to return.364 sched();365 panic("zombie exit");366}367368// Wait for a child process to exit and return its pid.369// Return -1 if this process has no children.370int371kwait(uint64 addr)372{373 struct proc *pp;374 int havekids, pid;375 struct proc *p = myproc();376377 acquire(&wait_lock);378379 for(;;){380 // Scan through table looking for exited children.381 havekids = 0;382 for(pp = proc; pp < &proc[NPROC]; pp++){383 if(pp->parent == p){384 // make sure the child isn't still in exit() or swtch().385 acquire(&pp->lock);386387 havekids = 1;388 if(pp->state == ZOMBIE){389 // Found one.390 pid = pp->pid;391 if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate,392 sizeof(pp->xstate)) < 0) {393 release(&pp->lock);394 release(&wait_lock);395 return -1;396 }397 freeproc(pp);398 release(&pp->lock);399 release(&wait_lock);400 return pid;401 }402 release(&pp->lock);403 }404 }405406 // No point waiting if we don't have any children.407 if(!havekids || killed(p)){408 release(&wait_lock);409 return -1;410 }411 412 // Wait for a child to exit.413 sleep(p, &wait_lock); //DOC: wait-sleep414 }415}416417// Per-CPU process scheduler.418// Each CPU calls scheduler() after setting itself up.419// Scheduler never returns. It loops, doing:420// - choose a process to run.421// - swtch to start running that process.422// - eventually that process transfers control423// via swtch back to the scheduler.424void425scheduler(void)426{427 struct proc *p;428 struct cpu *c = mycpu();429430 c->proc = 0;431 for(;;){432 // The most recent process to run may have had interrupts433 // turned off; enable them to avoid a deadlock if all434 // processes are waiting. Then turn them back off435 // to avoid a possible race between an interrupt436 // and wfi.437 intr_on();438 intr_off();439440 int found = 0;441 for(p = proc; p < &proc[NPROC]; p++) {442 acquire(&p->lock);443 if(p->state == RUNNABLE) {444 // Switch to chosen process. It is the process's job445 // to release its lock and then reacquire it446 // before jumping back to us.447 p->state = RUNNING;448 c->proc = p;449 swtch(&c->context, &p->context);450451 // Process is done running for now.452 // It should have changed its p->state before coming back.453 c->proc = 0;454 found = 1;455 }456 release(&p->lock);457 }458 if(found == 0) {459 // nothing to run; stop running on this core until an interrupt.460 asm volatile("wfi");461 }462 }463}464465// Switch to scheduler. Must hold only p->lock466// and have changed proc->state. Saves and restores467// intena because intena is a property of this468// kernel thread, not this CPU. It should469// be proc->intena and proc->noff, but that would470// break in the few places where a lock is held but471// there's no process.472void473sched(void)474{475 int intena;476 struct proc *p = myproc();477478 if(!holding(&p->lock))479 panic("sched p->lock");480 if(mycpu()->noff != 1)481 panic("sched locks");482 if(p->state == RUNNING)483 panic("sched RUNNING");484 if(intr_get())485 panic("sched interruptible");486487 intena = mycpu()->intena;488 swtch(&p->context, &mycpu()->context);489 mycpu()->intena = intena;490}491492// Give up the CPU for one scheduling round.493void494yield(void)495{496 struct proc *p = myproc();497 acquire(&p->lock);498 p->state = RUNNABLE;499 sched();500 release(&p->lock);501}502503// A fork child's very first scheduling by scheduler()504// will swtch to forkret.505void506forkret(void)507{508 extern char userret[];509 static int first = 1;510 struct proc *p = myproc();511512 // Still holding p->lock from scheduler.513 release(&p->lock);514515 if (first) {516 // File system initialization must be run in the context of a517 // regular process (e.g., because it calls sleep), and thus cannot518 // be run from main().519 fsinit(ROOTDEV);520521 first = 0;522 // ensure other cores see first=0.523 __sync_synchronize();524525 // We can invoke kexec() now that file system is initialized.526 // Put the return value (argc) of kexec into a0.527 p->trapframe->a0 = kexec("/init", (char *[]){ "/init", 0 });528 if (p->trapframe->a0 == -1) {529 panic("exec");530 }531 }532533 // return to user space, mimicing usertrap()'s return.534 prepare_return();535 uint64 satp = MAKE_SATP(p->pagetable);536 uint64 trampoline_userret = TRAMPOLINE + (userret - trampoline);537 ((void (*)(uint64))trampoline_userret)(satp);538}539540// Sleep on channel chan, releasing condition lock lk.541// Re-acquires lk when awakened.542void543sleep(void *chan, struct spinlock *lk)544{545 struct proc *p = myproc();546 547 // Must acquire p->lock in order to548 // change p->state and then call sched.549 // Once we hold p->lock, we can be550 // guaranteed that we won't miss any wakeup551 // (wakeup locks p->lock),552 // so it's okay to release lk.553554 acquire(&p->lock); //DOC: sleeplock1555 release(lk);556557 // Go to sleep.558 p->chan = chan;559 p->state = SLEEPING;560561 sched();562563 // Tidy up.564 p->chan = 0;565566 // Reacquire original lock.567 release(&p->lock);568 acquire(lk);569}570571// Wake up all processes sleeping on channel chan.572// Caller should hold the condition lock.573void574wakeup(void *chan)575{576 struct proc *p;577578 for(p = proc; p < &proc[NPROC]; p++) {579 if(p != myproc()){580 acquire(&p->lock);581 if(p->state == SLEEPING && p->chan == chan) {582 p->state = RUNNABLE;583 }584 release(&p->lock);585 }586 }587}588589// Kill the process with the given pid.590// The victim won't exit until it tries to return591// to user space (see usertrap() in trap.c).592int593kkill(int pid)594{595 struct proc *p;596597 for(p = proc; p < &proc[NPROC]; p++){598 acquire(&p->lock);599 if(p->pid == pid){600 p->killed = 1;601 if(p->state == SLEEPING){602 // Wake process from sleep().603 p->state = RUNNABLE;604 }605 release(&p->lock);606 return 0;607 }608 release(&p->lock);609 }610 return -1;611}612613void614setkilled(struct proc *p)615{616 acquire(&p->lock);617 p->killed = 1;618 release(&p->lock);619}620621int622killed(struct proc *p)623{624 int k;625 626 acquire(&p->lock);627 k = p->killed;628 release(&p->lock);629 return k;630}631632// Copy to either a user address, or kernel address,633// depending on usr_dst.634// Returns 0 on success, -1 on error.635int636either_copyout(int user_dst, uint64 dst, void *src, uint64 len)637{638 struct proc *p = myproc();639 if(user_dst){640 return copyout(p->pagetable, dst, src, len);641 } else {642 memmove((char *)dst, src, len);643 return 0;644 }645}646647// Copy from either a user address, or kernel address,648// depending on usr_src.649// Returns 0 on success, -1 on error.650int651either_copyin(void *dst, int user_src, uint64 src, uint64 len)652{653 struct proc *p = myproc();654 if(user_src){655 return copyin(p->pagetable, dst, src, len);656 } else {657 memmove(dst, (char*)src, len);658 return 0;659 }660}661662// Print a process listing to console. For debugging.663// Runs when user types ^P on console.664// No lock to avoid wedging a stuck machine further.665void666procdump(void)667{668 static char *states[] = {669 [UNUSED] "unused",670 [USED] "used",671 [SLEEPING] "sleep ",672 [RUNNABLE] "runble",673 [RUNNING] "run ",674 [ZOMBIE] "zombie"675 };676 struct proc *p;677 char *state;678679 printf("\n");680 for(p = proc; p < &proc[NPROC]; p++){681 if(p->state == UNUSED)682 continue;683 if(p->state >= 0 && p->state < NELEM(states) && states[p->state])684 state = states[p->state];685 else686 state = "???";687 printf("%d %s %s", p->pid, state, p->name);688 printf("\n");689 }690}691