Test yourself · category 7 of 20
Scheduling and swtch One scheduler loop per hart, the 14 registers swtch saves, the p->lock handed across every switch, and the intena bookkeeping that keeps interrupts honest.
All Not yet answered Got wrong Reset this category
swtch saves the registers of the thread that is stopping into a struct context.
Which registers are they?
kernel/proc.h
1 // Saved registers for kernel context switches.
Check Try again
Hart 1 is running process A. A’s timer tick makes it yield , and hart 1 next runs
process B. How many calls to swtch does hart 1 make between “running A” and
“running B”?
Check Try again
When sched switches away from a process, hart 1 continues in scheduler . Which
memory is hart 1’s stack pointer pointing into while the scheduler scans proc[]?
Check Try again
4 warm-up Choose all that apply Which of these functions call sched directly?
Check Try again
In swtch , click the instruction at which the hart stops using the old thread’s stack
and starts using the new thread’s stack.
Your pick: none yet (click a line in the code)
Check Try again
A process created by fork has never run. When a scheduler first calls
swtch(&c->context, &p->context) for it, where does swtch’s ret jump?
kernel/proc.c
143 // Set up new context to start executing at forkret,
144 // which returns to user space.
Check Try again
Lines 10–23 of swtch store the old thread’s registers into its context. How many
bytes do they write in total?
Check Try again
8 warm-up True or false, and why True or false: swtch ought to save and restore tp as well, and leaving it out
means a process resumed on a different hart will compute mycpu wrongly.
Check Try again
yield acquires p->lock, sets p->state = RUNNABLE, and calls sched still
holding the lock . The lock is released by the scheduler only after swtch . Why must
it stay held across the switch?
kernel/proc.c
499 // Give up the CPU for one scheduling round.
Check Try again
Each pass of scheduler 's outer loop executes intr_on() immediately followed by
intr_off(). What is the point of turning interrupts on for a single instruction?
kernel/proc.c
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
Check Try again
Hart 2 is idle. A timer interrupt has been pending, and it is taken right after
intr_on() at line 441. What does kerneltrap do with it?
kernel/trap.c
145 panic ( "kerneltrap: not from supervisor mode" );
147 panic ( "kerneltrap: interrupts enabled" );
150 // interrupt or trap from an unknown source
156 // give up the CPU if this is a timer interrupt.
160 // the yield() may have caused some traps to occur,
161 // so restore trap registers for use by kernelvec.S's sepc instruction.
Check Try again
An idle hart runs one full pass of scheduler 's inner for loop and finds nothing
RUNNABLE. How many times does it call acquire during that pass?
kernel/proc.c
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
466 // nothing to run; stop running on this core until an interrupt.
Check Try again
13 solid Fill in the machine state Pid 5 was spinning in user mode on hart 1 when a timer interrupt arrived. usertrap
called yield , which called sched , which called swtch . Hart 1 has just
executed line 26, ld sp, 8(a1). What is hart 1’s state?
Privilege mode choose… M (machine) S (supervisor) U (user) Active stack choose… user stack the process's kernel stack scheduler stack (stack0) boot stack (stack0) no usable stack Page table (satp) choose… paging off kernel page table user page table Interrupts (sstatus.SIE) choose… on off noff choose… 0 1 2 3 4 intena choose… 0 1 — (noff is 0)
Check Try again
14 solid Fill in the machine state Hart 0’s scheduler has just returned from acquire(&p->lock) at line 446, during a
scan. What is hart 0’s state?
kernel/proc.c
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
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
Privilege mode choose… M (machine) S (supervisor) U (user) Active stack choose… user stack the process's kernel stack scheduler stack (stack0) boot stack (stack0) no usable stack Page table (satp) choose… paging off kernel page table user page table Interrupts (sstatus.SIE) choose… on off noff choose… 0 1 2 3 4 intena choose… 0 1 — (noff is 0)
Check Try again
15 solid Choose all that apply Which of these are true at the instant scheduler executes the call
swtch(&c->context, &p->context) on line 453?
kernel/proc.c
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
Check Try again
Pid 5 is preempted by a timer tick on hart 1 and later resumed by hart 0. Put these
events in the order they must happen.
Hart 1’s scheduler releases pid 5’s p->lock (line 463) ↑ ↓ Hart 0’s swtch loads pid 5’s context, and yield releases the lock ↑ ↓ usertrap sees which_dev == 2 and calls yield↑ ↓ sched checks its four rules and copies intena into a local↑ ↓ Hart 0’s scheduler acquires pid 5’s p->lock, sees RUNNABLE and sets RUNNING ↑ ↓ swtch saves pid 5’s registers and loads hart 1’s scheduler context↑ ↓ yield acquires pid 5’s p->lock and sets RUNNABLE↑ ↓ Check Try again
Hart 1’s scheduler switched to the process in proc[4]. A tick later that process
yields, and the scheduler returns from the swtch on line 453. Which slot does it
examine next?
kernel/proc.c
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
466 // nothing to run; stop running on this core until an interrupt.
Check Try again
Each release(&p->lock) below releases a lock that was acquired somewhere else. Match
each release with the code that acquired that lock.
release(&p->lock) in scheduler , line 463, just after swtch has returnedchoose… kkill itself, at line 609, a moment earlier The process’s own thread, in yield, sleep or kexit, before it called sched A scheduler, just before it switched back to a process that had stopped in yield A scheduler, just before it switched to a process that had never run release(&p->lock) in forkret , line 520choose… kkill itself, at line 609, a moment earlier The process’s own thread, in yield, sleep or kexit, before it called sched A scheduler, just before it switched back to a process that had stopped in yield A scheduler, just before it switched to a process that had never run release(&p->lock) at the end of yield , line 507choose… kkill itself, at line 609, a moment earlier The process’s own thread, in yield, sleep or kexit, before it called sched A scheduler, just before it switched back to a process that had stopped in yield A scheduler, just before it switched to a process that had never run release(&p->lock) in kkill , line 616choose… kkill itself, at line 609, a moment earlier The process’s own thread, in yield, sleep or kexit, before it called sched A scheduler, just before it switched back to a process that had stopped in yield A scheduler, just before it switched to a process that had never run Check Try again
Once a process is running, its p->lock is free: any scheduler can lock the slot and
look at it. Click the line that makes those schedulers leave the process alone.
kernel/proc.c
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
Your pick: none yet (click a line in the code)
Check Try again
Why does scheduler turn interrupts off (line 442) before scanning, instead of
leaving them on for the scan?
kernel/proc.c
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
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
466 // nothing to run; stop running on this core until an interrupt.
Check Try again
Right after its swtch returns, scheduler executes mycpu()->intena = 0 (line
456). What would go wrong without that line?
kernel/proc.c
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
Check Try again
22 deep Choose all that apply Process P stops on hart 1 through sched and is later resumed on hart 2. Which of
these are carried from hart 1 to hart 2 with P , so that P finds its own values after
the switch?
Check Try again
23 deep True or false, and why True or false: when an idle hart executes wfi on line 467, its timer interrupt can
still end the wait, even though sstatus.SIE is 0 at that point.
kernel/proc.c
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
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.
455 // Don't re-enable interrupts on release.
458 // Process is done running for now.
459 // It should have changed its p->state before coming back.
466 // nothing to run; stop running on this core until an interrupt.
Check Try again
24 deep Choose all that apply Suppose release(&p->lock) on line 520 were moved to become the first statement inside
the if (first) block, so that init still releases it but no later fork child does.
A new child, pid 9, reaches user mode on hart 1. Which of these would then happen?
kernel/proc.c
510 // A fork child's very first scheduling by scheduler()
511 // will swtch to forkret.
519 // Still holding p->lock from scheduler.
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.
538 // return to user space, mimicing usertrap()'s return.
Check Try again
cat called sleep from inside read, with interrupts on, on hart 1. It is woken
and resumed by hart 2’s scheduler. Suppose line 496 of sched ,
mycpu()->intena = intena;, were deleted (line 494 kept). What changes for cat?
Check Try again
← The stacks All categories fork, exec, exit, wait, kill →