Assignment 3: v6 problem set (HINTS)

Please note that the following hints are not complete solutions! (I.e., if you turn them in as is, you would not merit full credit for the assignment.) They're merely posted here to help you study for the midterm exam.

I. Kernel data structures

  1. According to the comments that precede them, separate proc (0358) and user (0413) structures are allocated for every active process. If this is the case, explain the discrepancy in their manner of allocation at lines 0376 (for the proc array) and 0459 (for the u variable).

    • This has to do with the fact that [a] the proc structure needs to be accessible for a process even while it is not the current process and while it may be swapped out (why?) and [b] the u variable is used at all times to reference the current user structure --- the other ones are not needed and in fact may be swapped out.
  2. The proc and user structures are said to cross-reference each other by way of component pointers. It should be noted, however, that the pointer stored in the proc structure is in fact a physical block number, and not a virtual address. Why is this the case? How/When is this address used?

    • A hint in the form of a question here: if the address stored for the user structure were in fact a virtual address, what would it be? Would it always be usable?

II. System startup

  1. Explain the purpose of the computations performed in lines 0632-0634. What is the function of the following two lines of code?

    • What is the user data area used for?
  2. In what process context are lines 0670-0672 executed, and what is their purpose?

    • How do we get back here from main, and what do the values (0170000 and 0) placed in the PS and PC registers by the rtt instruction at 672 accomplish?
  3. While proc[0] isn't technically created until line 1589, by this time we have already performed a subroutine jump (0669) and interrupts may also have occurred (e.g., the clock interrupt). What process's stack frame is being used to keep track of these actions?

    • The thing to realize is that even though we don't technically make proc[0] the structure for the current process until 1589, the "current" process hasn't changed since the first line of code executed in the startup sequence. After all, we don't perform a context switch until the first call to swtch, which happens a while later!
  4. An important convention found in v6 is that the u_procp pointer in the user struct points back to its associated proc array entry. Explain why line 1891 results in an inconsistency, and why it is necessary.

    • This is a little subtle. It's perhaps more useful to think about how we would point the new user struct at the proc structure of the new process if we don't create this inconsistency! Think on it: if the new user struct isn't the current one, then what virtual address do we use to access it?

III. Memory initialization / mapping

  1. What is the resulting memory mapping by the end of line 0669? Does proc 0’s user structure necessarily begin at the beginning of the 6th physical page? Why or why not?

    • It's pretty close to the mapping established by the boot conventions (i.e., when memory management isn't yet enabled). For proc 0's user structure, refer back to line 635.
  2. After reading through the estabur (1650) and sureg (1739) functions, explain in your own words the purpose of the u.u_uisa and u.u_uisd arrays, and the responsibilities of the two functions that access them.

    • One populates the prototype values for the user mode virtual memory mapping registers, and the other copies the prototypes over to the actual registers. Which is which, and what is the distinction?

IV. Long / Short term scheduling

  1. What is accomplished by the savu/retu pair found at the start of the swtch function (at lines 2189 and 2193)? Are they absolutely necessary for the kernel to operate correctly? What is their ultimate purpose? (Hint: look forward to the conditional at line 2218)

    • At 2218 we see a conditional that has the current process idling when there is no runnable process. What happens if the current process is anything other than proc 0? Additional hint: what happens to its priority as the clock keeps ticking by? (Is this desirable?)
  2. One of the problems with priority based scheduling is starvation. A common approach to dealing with starvation is aging, where the priority of the current process is decreased over time. v6 takes this a step further, by also increasing the priority of non-running processes.

    Identify the sections of v6 code that implement priority aging and briefly explain how they work.

    • Priority aging has to take place as time passes by -- what function gets called periodically, based on the ticking of the clock? (this hint is a bit heavy-handed, for sure).

      When you've identified the function, you also want to determine (a) how much we age processes and (b) how often we do it.

  3. During lecture we identified the runrun flag as indicating that a higher priority process is ready to run; we confirmed its semantics by examining the setrun function (2134). It is interesting to contrast the conditions checked at lines 2141 and 2165, however --- is setpri buggy? Explain.

    • Well, Lions doesn't seem to think so (section 8.10). Big hint -- check out line 3828.
  4. After reading through the sched (long term scheduling / swapping) function on your own, explain when the '3 second / 2 second' rule is applied, and discuss the intuition behind it.

    • Note that the rule doesn't always get applied -- only when there is "no easy core" (1997). But what does that mean? After figuring that out, look around to make sure you know what value is stored in n at the two conditionals at lines 2003 and 2013, and you should have your answer.

V. Interrupts / Traps

  1. Why is it necessary at lines 756 and 777 for the trap and call functions to quickly save the value of the PS register onto the stack? What is it used for (if anything), later on?

    • What are the values added to br7 in the trap interrupt entries on lines 512-518 and 547-549? What bits of the PS register do they populate, and what else are those bits used for? Next, figure out which of the arguments contains these bits in the call to 2693, and you're mostly there!
  2. What is the primary difference between the aretu (line 734) and retu (line 740)? Under what conditions would a call to aretu be required?

    • What is a non-local jump?
  3. In the exit system call implementation (3219), what is the purpose of the loop starting at line 3250? In particular, what is achieved by the assignment at line 3252?

    • Who reaps the orphaned child zombie process?