xv6, line by line
tour 13
Tours13 swtch and the lock handed across a context switch

Tour 13 · Time and scheduling · about 31 minutes · 21 steps

swtch and the lock handed across a context switch

Everywhere else in xv6, the thread that acquires a spinlock releases it. A context switch breaks that rule on purpose. When a process gives up its CPU, it acquires its own p->lock, and the scheduler releases it. When the scheduler starts a process, the scheduler acquires the lock, and the process releases it. This tour is about why that odd rule is exactly right, and about the 29 instructions of swtch in the middle.

You will follow cat as it goes to sleep waiting for a line of keyboard input on hart 1, see hart 1 start a brand-new process that has never run (through forkret), and then see cat wake up on hart 2 and continue as though nothing happened. On the way you will meet the four checks in sched, the 14 registers a switch saves, and the small bookkeeping problem of intena: a fact about a thread that has to live in a structure that belongs to a CPU.

Best after: 11. From a timer tick to a context switch, 12. One scheduler per hart, 15. Spinlocks from the hardware up

Who is running where

The machine has three harts. Earlier you started grind &: the shell’s child (pid 3) forked grind (pid 4) and exited; grind at once forked pid 5 to run iter, which forked two workers (pids 6 and 7) that loop forever doing random system calls, including frequent forks. The pid counter has been climbing ever since. Now you have typed cat, which the shell (pid 2, asleep in wait) started; call it pid 213 (the exact numbers are only an example). When the tour starts:

Hart What it is doing
0 Running a grind worker (pid 6), which has just forked a child, pid 240 (the numbers are examples)
1 Running cat (pid 213) in the kernel, in read on the console: the process this tour follows
2 Idle in its scheduler (both grind workers are on other harts or waiting for the disk)

You have not typed anything yet, so cat has nothing to read.

Three harts are running. This tour follows one path through the code, but the machine has three CPUs executing at the same time. Watch the locks held display at the top of each step, and read the Meanwhile, on other harts boxes: they show what the other CPUs could be doing at that very moment.
The route
  1. 1cat has nothing to read kernel/console.c
  2. 2sleep acquires cat's p->lock kernel/proc.c
  3. 3Two counters that belong to the CPU kernel/spinlock.c
  4. 4sched's four checks kernel/proc.c
  5. 5Save the thread's intena kernel/proc.c
  6. 6What a context is kernel/proc.h
  7. 7swtch saves cat kernel/swtch.S
  8. 8swtch loads the scheduler and returns into it kernel/swtch.S
  9. 9The scheduler resets intena kernel/proc.c
  10. 10Released by a thread that never acquired it kernel/spinlock.c
  11. 11Hart 1 picks a process that has never run kernel/proc.c
  12. 12Flashback: a context forged by allocproc kernel/proc.c
  13. 13swtch saves hart 1's scheduler kernel/swtch.S
  14. 14swtch "returns" into forkret kernel/swtch.S
  15. 15forkret releases the scheduler's lock kernel/proc.c
  16. 16A keystroke on hart 0 kernel/console.c
  17. 17wakeup marks cat RUNNABLE kernel/proc.c
  18. 18Hart 2's scheduler switches to cat kernel/proc.c
  19. 19Back in sched, on another hart kernel/proc.c
  20. 20sleep releases the lock hart 2's scheduler took kernel/proc.c
  21. 21The rule, and the compromise behind it kernel/proc.c

Keys: ← → step · Home start