wc finds the pipe empty, and piperead calls sleep_prepare(&pi->nread) on line
124. Right after that call returns, what has changed?
Test yourself · category 10 of 20
Sleep/wakeup and sleep-locks
How this tree’s sleep_prepare, sleep and wakeup avoid lost wakeups without passing a lock to sleep, why every sleep sits in a loop, and how sleep-locks are built on top of them.
True or false: in this kernel, the caller passes its condition lock to sleep, and
sleep releases it before the process goes to sleep.
Why?
wakeup finds a process that is SLEEPING with p->chan equal to the channel. What
state does it give that process?
piperead sleeps on the channel &pi->nread. When pipewrite calls
wakeup(&pi->nread), what does wakeup do with the integer stored at that address?
Which of these are true of a sleep-lock but not of a spinlock, in this kernel?
Match each place that sleeps with the channel it registers on.
Line 119 of piperead is a while, not an if. Why?
wc reads from an empty pipe whose writer is still open and goes to sleep. Put the
steps in order.
- release(&pi->lock)
- sched() switches to this hart’s scheduler
- see nread == nwrite with writeopen set, and killed() returning 0
- acquire(&pi->lock)
- the scheduler releases wc’s p->lock
- sleep_prepare(&pi->nread): p->chan is set under p->lock
- sleep(): under p->lock, p->chan is still set, so p->state = SLEEPING
A process has called sleep_prepare but not yet sleep; it is still RUNNING.
Another hart calls wakeup on its channel. Click the line of wakeup that makes the
process’s coming sleep() return without sleeping.
Your pick: none yet (click a line in the code)
wc is between lines 125 and 126 of pipe.c: registered on &pi->nread, pi->lock
released, sleep() not yet called. On another hart, cat takes pi->lock, writes 512
bytes and calls wakeup(&pi->nread). What happens to wc?
When pipewrite finds the pipe full, it calls wakeup(&pi->nread) on line 89 before
it registers on &pi->nwrite and sleeps. What could happen without line 89?
A reader is SLEEPING in piperead, registered on &pi->nread. Which of these
events can make it RUNNABLE?
One call to wakeup runs on a machine where exactly one process is registered on the
channel. How many times does that call execute acquire(&p->lock)?
ls holds an inode’s sleep-lock and a buffer’s sleep-lock, and goes to sleep in
virtio_disk_rw waiting for the disk (line 290). When sched checks
mycpu()->noff on line 487, what value does it find?
A process is writing to the console. In uartwrite it holds tx_lock (a sleep-lock)
and has just returned from sleep_prepare(&tx_chan) on line 86; it is about to read
LSR on line 87. What is the state of its hart?
holding checks a spinlock’s owner by hart (lk->cpu), but holdingsleep checks
a sleep-lock’s owner by process ID (lk->pid). Why the difference?
ls holds a buffer’s sleep-lock. grep calls acquiresleep on the same lock, and
ls calls releasesleep only after grep is fully asleep. No third process wants the
lock. Put the events in order.
- ls: wakeup(lk) makes grep RUNNABLE
- grep: re-acquires lk->lk, sees locked == 0, sets locked = 1 and pid
- grep: sleep_prepare(lk) sets grep’s p->chan = lk
- grep: acquire(&lk->lk), sees locked == 1
- grep: sleep() marks grep SLEEPING and switches away
- ls: under lk->lk, locked = 0 and pid = 0
- grep: release(&lk->lk)
pipewrite is about to go to sleep because the pipe is full (line 88 was true). At
that moment, what is pi->nwrite - pi->nread?
Hart 0 is idle in its scheduler. At the top of the loop, line 441 turns interrupts on
and the pending timer interrupt is taken at once. clockintr holds tickslock and is
inside wakeup(&ticks), holding one process’s p->lock. What is the state of hart 0?
True or false: once kkill has set wc’s killed flag, wc cannot go to sleep in
piperead's wait loop until it has noticed the kill.
Why?
uartwrite sleeps on &tx_chan without holding any spinlock: its condition is the
LSR_TX_IDLE bit of a device register, and the waker is uartintr. Why can’t the
“transmitter is idle” wakeup be lost?
iput calls acquiresleep(&ip->lock) on line 362 while holding the spinlock
itable.lock. Why doesn’t this break the rule “never sleep while holding a spinlock”?
True or false: in kexit, swapping lines 353 and 355, so that the process takes its
own p->lock before calling wakeup(p->parent), would be harmless.
Why?
A process P has p->chan != 0. Which of these could be true at that moment?