Hand-In Procedure
You are to turn in this homework at the beginning of lecture. Please write up your answers to the exercises below and hand them in to a staff member at the beginning of the lecture. Write your CSE login ID at the top of your submission
Some traps push an extra error code onto the stack (see Table 5-1 and Figure 5-3 from Volume 3). But this error code isn't pushed
by the INT instruction. Can the user confuse the kernel by invoking
"INT 0xc
" (or any other vector that usually pushes an error
code)? Why not?
Read: swtch.S and proc.c (focus on the code that switches
between processes, specifically scheduler
and sched
).
Also process creation: sys_fork() and copyproc().
In this part of the homework you will investigate how the kernel switches between two processes.
Assignment:
Suppose a process that is running in the kernel
calls sched()
, which ends up jumping
into scheduler()
.
Turn in:
Where is the stack that sched()
executes on?
Turn in:
Where is the stack that scheduler()
executes on?
Turn in:
When sched()
calls swtch()
,
does that call to swtch()
ever return? If so, when?
Now think back to lecture 2 and the invariants
that gcc expects any function, including swtch
, to
maintain. Compare these invariants with what swtch
actually implements, and the state that our kernel maintains in
a struct context
.
Turn in: Could swtch
do less work and still be
correct? Could we reduce the size of a struct context
?
Provide concrete examples if yes, or argue for why not.
Surround the call to swtch()
in scheduler()
with calls
to cprintf()
like this:
cprintf("a"); swtch(&cpu->scheduler, &proc->context); cprintf("b");
Similarly,
surround the call to swtch()
in sched()
with calls
to cprintf()
like this:
cprintf("c"); swtch(&proc->context, cpu->scheduler); cprintf("d");
Rebuild your kernel and boot it on QEMU. With a few exceptions you should see a regular four-character pattern repeated over and over.
Turn in: What is the four-character pattern?
Turn in: The very first characters are ac
. Why does
this happen?
// caller must hold proc_table_lock. void sched(void) { scheduler2(); } // caller must hold proc_table_lock. void scheduler2(void) { struct proc *p; struct proc *from = cp; // remember who we are int i; for(;;){ for(i = 0; i < NPROC; i++){ p = &proc[i]; if(p->state != RUNNABLE) continue; cp = p; setupsegs(p); p->state = RUNNING; swtch(&from->context, &p->context); // a return from swtch() means some other call to // scheduler2() decided to run us. cp = from; setupsegs(cp); return; } release(&proc_table_lock); acquire(&proc_table_lock); } }This new swtch()-less sched() works most of the time, but not always. What is likely to go wrong?
fork()
, why do we need to
store pid
in a temporary stack variable [2282]?
Based on MIT 6.828 materials by Frans Kaashoek and others; and Yale OS course materials by Bryan Ford.