7.9 Process Locking
The lock associated with each process (p->lock
) is the
most complex lock in xv6.
A simple way to think about p->lock
is
that it must be held while reading or writing any of the following
struct proc
fields:
p->state
,
p->chan
,
p->killed
,
p->xstate
,
and
p->pid
.
These fields can be used by other processes, or by scheduler
threads on other CPUs, so it’s natural that they
must be protected by a lock.
However, most uses of p->lock
are protecting higher-level
aspects of xv6’s process data structures and algorithms. Here’s
the full set of things that p->lock
does:
-
•
Along with
p->state
, it prevents races in allocatingproc[]
slots for new processes. -
•
It conceals a process from view while it is being created or destroyed.
-
•
It prevents a parent’s
wait
from collecting a process that has set its state toZOMBIE
but has not yet yielded the CPU. -
•
It prevents another CPU’s scheduler from deciding to run a yielding process after it sets its state to
RUNNABLE
but before it finishesswtch
. -
•
It ensures that only one CPU’s scheduler decides to run a
RUNNABLE
processes. -
•
It prevents a timer interrupt from causing a process to yield while it is in
swtch
. -
•
Along with the condition lock, it helps prevent
wakeup
from overlooking a process that is callingsleep
but has not finished yielding the CPU. -
•
It prevents the victim process of
kill
from exiting and perhaps being re-allocated betweenkill
’s check ofp->pid
and settingp->killed
. -
•
It makes
kill
’s check and write ofp->state
atomic.
The p->parent
field is protected by the global lock
wait_lock
rather than by p->lock
.
Only a process’s parent modifies p->parent
, though
the field is read both by the process itself and by other
processes searching for their children. The purpose of
wait_lock
is to act as the condition lock when
wait
sleeps waiting for any child to exit. An
exiting child holds either wait_lock
or p->lock
until after it has set its state to ZOMBIE
, woken
up its parent, and yielded the CPU. wait_lock
also
serializes concurrent exit
s by a parent and child,
so that the init
process (which inherits the child)
is guaranteed to be woken up from its wait
.
wait_lock
is a global lock rather than a per-process
lock in each parent, because, until a process acquires it,
it cannot know who its parent is.