xv6, line by line
kernel/proc.c

kernel/proc.c

C · 703 lines · annotated 100% · kernel · upstream

About this file

The process manager: the code that creates, schedules, puts to sleep, wakes, kills and destroys processes. It is also the place where xv6’s concurrency is hardest, because several CPUs run this code at the same time and each process’s state is touched by its own CPU, by other CPUs and by interrupt handlers.

The life of a process, and where to read about each step:

  1. allocproc claims an UNUSED slot in proc and gives it a PID (process ID), a trapframe, a page table and a fresh kernel context that starts in forkret.
  2. kfork (or, for the very first process, userinit) fills it in and marks it RUNNABLE.
  3. Each CPU’s scheduler picks RUNNABLE processes and runs them with swtch. A process gives the CPU back through sched: from yield (timer interrupt), from sleep (waiting for an event, until wakeup), or from kexit.
  4. kexit makes the process a zombie; the parent’s kwait collects its exit status and calls freeproc, which returns the slot to UNUSED.

Locks used here, and the order they must be taken in (see deadlock):

  • wait_lock (one global lock) protects every p->parent and makes “check for exited children, then sleep” atomic in kwait. Always taken before any p->lock.
  • p->lock (one per process) protects state, chan, killed, xstate and pid, and is held across every context switch of that process.
  • pid_lock protects nextpid; nothing else is taken while it is held.
  • Condition locks of other subsystems (such as tickslock) are taken before p->lock, because sleep_prepare and wakeup take p->lock while their caller holds one.
  • p->lock is not always innermost: pid_lock, kmem.lock (inside kalloc and kfree) and, in userinit, itable.lock are taken while holding it. None of these ever takes a p->lock, so the order stays consistent.

Read before: kernel/proc.h, kernel/spinlock.c, kernel/swtch.S. Read next: kernel/trap.c (how processes enter and leave the kernel) and kernel/exec.c.

1#include "types.h"
2#include "param.h"
4#include "riscv.h"
5#include "spinlock.h"
6#include "proc.h"
7#include "defs.h"
9struct cpu cpus[NCPU];
11struct proc proc[NPROC];
13struct proc *initproc;
15int nextpid = 1;
18extern void forkret(void);
19static void freeproc(struct proc *p);
21extern char trampoline[]; // trampoline.S
23// helps ensure that wakeups of wait()ing
24// parents are not lost. helps obey the
25// memory model when using p->parent.
26// must be acquired before any p->lock.
29// Allocate a page for each process's kernel stack.
30// Map it high in memory, followed by an invalid
31// guard page.
32void
35 struct proc *p;
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));
43 }
46// initialize the proc table.
47void
50 struct proc *p;
52 initlock(&pid_lock, "nextpid");
53 initlock(&wait_lock, "wait_lock");
54 for (p = proc; p < &proc[NPROC]; p++) {
55 initlock(&p->lock, "proc");
57 p->kstack = KSTACK((int)(p - proc));
58 }
61// Must be called with interrupts disabled,
62// to prevent race with process being moved
63// to a different CPU.
64int
67 int id = r_tp();
68 return id;
71// Return this CPU's cpu struct.
72// Interrupts must be disabled.
73struct cpu *
74mycpu(void)
76 int id = cpuid();
77 struct cpu *c = &cpus[id];
78 return c;
81// Return the current struct proc *, or zero if none.
82struct proc *
83myproc(void)
86 struct cpu *c = mycpu();
87 struct proc *p = c->proc;
89 return p;
92int
95 int pid;
102 return pid;
105// 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 *
112 struct proc *p;
114 for (p = proc; p < &proc[NPROC]; p++) {
116 if (p->state == UNUSED) {
117 goto found;
118 } else {
120 }
121 }
122 return 0;
128 // Allocate a trapframe page.
129 if ((p->trapframe = (struct trapframe *)kalloc()) == 0) {
132 return 0;
133 }
135 // An empty user page table.
137 if (p->pagetable == 0) {
140 return 0;
141 }
143 // Set up new context to start executing at forkret,
144 // which returns to user space.
145 memset(&p->context, 0, sizeof(p->context));
149 return p;
152// free a proc structure and the data hanging from it,
153// including user pages.
154// p->lock must be held.
155static void
156freeproc(struct proc *p)
159 kfree((void *)p->trapframe);
164 p->sz = 0;
165 p->pid = 0;
166 p->name[0] = 0;
167 p->chan = 0;
168 p->killed = 0;
169 p->xstate = 0;
173// Create a user page table for a given process, with no user memory,
174// but with trampoline and trapframe pages.
180 // An empty page table.
182 if (pagetable == 0)
183 return 0;
185 // map the trampoline code (for system call return)
186 // at the highest user virtual address.
187 // only the supervisor uses it, on the way
188 // to/from user space, so not PTE_U.
190 PTE_R | PTE_X) < 0) {
192 return 0;
193 }
195 // map the trapframe page just below the trampoline page, for
196 // trampoline.S.
198 PTE_R | PTE_W) < 0) {
201 return 0;
202 }
204 return pagetable;
207// Free a process's page table, and free the
208// physical memory it refers to.
209void
217// Set up first user process.
218void
221 struct proc *p;
226 p->cwd = namei("/");
233// Grow or shrink user memory by n bytes.
234// Return 0 on success, -1 on failure.
235int
239 struct proc *p = myproc();
241 sz = p->sz;
242 if (n > 0) {
243 if (sz + n > TRAPFRAME) {
244 return -1;
245 }
246 if ((sz = uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) {
247 return -1;
248 }
249 } else if (n < 0) {
251 }
252 p->sz = sz;
253 return 0;
256// Create a new process, copying the parent.
257// Sets up child kernel stack to return as if from fork() system call.
258int
259kfork(void)
261 int i, pid;
262 struct proc *np;
263 struct proc *p = myproc();
265 // Allocate process.
266 if ((np = allocproc()) == 0) {
267 return -1;
268 }
270 // Copy user memory from parent to child.
271 if (uvmcopy(p->pagetable, np->pagetable, p->sz) < 0) {
274 return -1;
275 }
276 np->sz = p->sz;
278 // copy saved user registers.
281 // Cause fork to return 0 in the child.
284 // increment reference counts on open file descriptors.
285 for (i = 0; i < NOFILE; i++)
286 if (p->ofile[i])
288 np->cwd = idup(p->cwd);
290 safestrcpy(np->name, p->name, sizeof(p->name));
304 return pid;
307// Pass p's abandoned children to init.
308// Caller must hold wait_lock.
309void
310reparent(struct proc *p)
312 struct proc *pp;
314 for (pp = proc; pp < &proc[NPROC]; pp++) {
315 if (pp->parent == p) {
318 }
319 }
322// Exit the current process. Does not return.
323// An exited process remains in the zombie state
324// until its parent calls wait().
325void
328 struct proc *p = myproc();
330 if (p == initproc)
331 panic("init exiting");
333 // Close all open files.
334 for (int fd = 0; fd < NOFILE; fd++) {
335 if (p->ofile[fd]) {
336 struct file *f = p->ofile[fd];
338 p->ofile[fd] = 0;
339 }
340 }
345 p->cwd = 0;
349 // Give any children to init.
352 // Parent might be sleeping in wait().
362 // Jump into the scheduler, never to return.
364 panic("zombie exit");
367// Wait for a child process to exit and return its pid.
368// Return -1 if this process has no children.
369int
372 struct proc *pp;
374 struct proc *p = myproc();
378 for (;;) {
379 // Scan through table looking for exited children.
381 for (pp = proc; pp < &proc[NPROC]; pp++) {
382 if (pp->parent == p) {
383 // make sure the child isn't still in exit() or swtch().
387 if (pp->state == ZOMBIE) {
388 // Found one.
390 if (addr != 0 &&
391 copyout(p->pagetable, p->sz, addr, (char *)&pp->xstate,
392 sizeof(pp->xstate)) < 0) {
395 return -1;
396 }
397 pp->parent = 0;
401 return pid;
402 }
404 }
405 }
407 // No point waiting if we don't have any children.
408 if (!havekids || killed(p)) {
410 return -1;
411 }
413 // Wait for a child to exit.
414 sleep_prepare(p); //DOC: wait-sleep
418 }
421// Per-CPU process scheduler.
422// Each CPU calls scheduler() after setting itself up.
423// Scheduler never returns. It loops, doing:
424// - choose a process to run.
425// - swtch to start running that process.
426// - eventually that process transfers control
427// via swtch back to the scheduler.
428void
431 struct proc *p;
432 struct cpu *c = mycpu();
434 c->proc = 0;
435 for (;;) {
436 // The most recent process to run may have had interrupts
437 // turned off; enable them to avoid a deadlock if all
438 // processes are waiting. Then turn them back off
439 // to avoid a possible race between an interrupt
440 // and wfi.
444 int found = 0;
445 for (p = proc; p < &proc[NPROC]; p++) {
447 if (p->state == RUNNABLE) {
448 // Switch to chosen process. It is the process's job
449 // to release its lock and then reacquire it
450 // before jumping back to us.
452 c->proc = p;
455 // Don't re-enable interrupts on release.
456 mycpu()->intena = 0;
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
460 c->proc = 0;
461 found = 1;
462 }
464 }
465 if (found == 0) {
466 // nothing to run; stop running on this core until an interrupt.
467 asm volatile("wfi");
468 }
469 }
472// Switch to scheduler. Must hold only p->lock
473// and have changed proc->state. Saves and restores
474// intena because intena is a property of this
475// kernel thread, not this CPU. It should
476// be proc->intena and proc->noff, but that would
477// break in the few places where a lock is held but
478// there's no process.
479void
480sched(void)
482 int intena;
483 struct proc *p = myproc();
485 if (!holding(&p->lock))
486 panic("sched p->lock");
487 if (mycpu()->noff != 1)
488 panic("sched locks");
489 if (p->state == RUNNING)
490 panic("sched RUNNING");
491 if (intr_get())
492 panic("sched interruptible");
499// Give up the CPU for one scheduling round.
500void
501yield(void)
503 struct proc *p = myproc();
510// A fork child's very first scheduling by scheduler()
511// will swtch to forkret.
512void
515 extern char userret[];
516 static int first = 1;
517 struct proc *p = myproc();
519 // Still holding p->lock from scheduler.
522 if (first) {
523 first = 0;
525 // File system initialization must be run in the context of a
526 // regular process (e.g., because it calls sleep), and thus cannot
527 // be run from main().
530 // We can invoke kexec() now that file system is initialized.
531 // Put the return value (argc) of kexec into a0.
532 p->trapframe->a0 = kexec("/init", (char *[]){"/init", 0});
533 if (p->trapframe->a0 == -1) {
534 panic("exec");
535 }
536 }
538 // return to user space, mimicing usertrap()'s return.
545// Register current process as waiting for wakeups on chan.
546void
549 struct proc *p = myproc();
552 if (chan == 0)
553 panic("sleep_prepare: zero chan");
558// Put the thread to sleep. Assumes sleep_prepare() was called before.
559// If the channel registered by sleep_prepare() has been woken up in
560// the meantime, do not go to sleep, and instead return immediately.
561void
562sleep(void)
564 struct proc *p = myproc();
567 if (p->chan != 0) {
570 }
574// Wake up all processes sleeping on channel chan.
575void
578 struct proc *p;
580 for (p = proc; p < &proc[NPROC]; p++) {
582 if (p->chan == chan) {
583 // If the process is waiting for wakeups on this channel,
584 // signal that the wakeup happened by clearing p->chan.
585 p->chan = 0;
587 // If this waiting process has gotten so far as to actually
588 // go to sleep, also set it back to RUNNING.
589 if (p->state == SLEEPING) {
591 }
592 }
594 }
597// Kill the process with the given pid.
598// The victim won't exit until it tries to return
599// to user space (see usertrap() in trap.c).
600int
603 struct proc *p;
605 if (pid == 0)
606 return -1;
608 for (p = proc; p < &proc[NPROC]; p++) {
610 if (p->pid == pid) {
611 p->killed = 1;
612 if (p->state == SLEEPING) {
613 // Wake process from sleep().
615 }
617 return 0;
618 }
620 }
621 return -1;
624void
628 p->killed = 1;
632int
633killed(struct proc *p)
635 int k;
640 return k;
643// Copy to either a user address, or kernel address,
644// depending on usr_dst.
645// Returns 0 on success, -1 on error.
646int
649 struct proc *p = myproc();
650 if (user_dst) {
651 return copyout(p->pagetable, p->sz, dst, src, len);
652 } else {
653 memmove((char *)dst, src, len);
654 return 0;
655 }
658// Copy from either a user address, or kernel address,
659// depending on usr_src.
660// Returns 0 on success, -1 on error.
661int
664 struct proc *p = myproc();
665 if (user_src) {
666 return copyin(p->pagetable, p->sz, dst, src, len);
667 } else {
668 memmove(dst, (char *)src, len);
669 return 0;
670 }
673// Print a process listing to console. For debugging.
674// Runs when user types ^P on console.
675// No lock to avoid wedging a stuck machine further.
676void
679 static char *states[] = {
680 // clang-format off
681 [UNUSED] = "unused",
682 [USED] = "used",
683 [SLEEPING] = "sleep ",
684 [RUNNABLE] = "runble",
685 [RUNNING] = "run ",
686 [ZOMBIE] = "zombie"
687 // clang-format on
688 };
689 struct proc *p;
690 char *state;
692 printk("\n");
693 for (p = proc; p < &proc[NPROC]; p++) {
694 if (p->state == UNUSED)
695 continue;
696 if (p->state >= 0 && p->state < NELEM(states) && states[p->state])
698 else
699 state = "???";
700 printk("%d %s %s", p->pid, state, p->name);
701 printk("\n");
702 }