1Which lock protects each field you want to report?
Your record has six fields: pid, parent’s pid, state, size, name, and the hart a process is running on. For each one, find every piece of code that writes it and note which lock that code holds while it writes. Which fields can a lock you take make safe to read, and which can’t?
Start with the comments inside struct proc (kernel/proc.h:85 to
kernel/proc.h:103), then check them against the writers: search the kernel for
->state =, ->pid =, ->parent =, ->sz and ->name. The hart is not in
struct proc at all; look at struct cpu in the same header.
A lock protects a field only against writers that take the same lock. If even one writer stores to the field without it, holding the lock while you read does not stop that store.
You should end up with four groups: fields every writer changes under p->lock, one
field every writer changes under wait_lock, fields the process writes about itself
with no lock, and one field outside struct proc written by the scheduler.
The reference design
| Field | Written by | Lock the writer holds |
|---|---|---|
state |
allocproc, userinit, kfork, kexit, yield, sleep, wakeup, kkill, scheduler, freeproc |
that process’s p->lock, always |
pid |
allocproc (kernel/proc.c:125), freeproc (kernel/proc.c:165) |
p->lock |
parent |
kfork (kernel/proc.c:297), reparent (kernel/proc.c:316), kwait (kernel/proc.c:397) |
wait_lock |
sz |
growproc (kernel/proc.c:252), lazy sbrk (kernel/sysproc.c:62), kexec (kernel/exec.c:135); also kfork for the child and freeproc |
none for the process’s own writes |
name |
kexec (kernel/exec.c:130); also kfork for the child and freeproc (name[0] = 0) |
none for kexec |
| hart | c->proc = p and c->proc = 0 in scheduler (kernel/proc.c:452, kernel/proc.c:460) |
the p->lock of the process c->proc points to |
So p->lock makes state, pid and the hart readable together, wait_lock makes
parent readable, and nothing you can take makes sz and name safe: their owner
writes them while it runs, perhaps on another hart at this very moment, without any
lock. The comment in proc.h calls them “private to the process”, which is exactly
right for the process itself and exactly the problem for anybody else. (kfork and
freeproc write them under p->lock, but that only covers a child that cannot run yet
and a slot that is being freed.)
Check yourself
Match each field with what protects it against concurrent writers.
True or false: if procinfo holds p->lock while it copies p->name, it can never
see a name that is half the old program’s and half the new one’s.
Why?