Cs-537: Midterm Exam (Fall 2013) Professor Mcflub: The Solutions Edition
Cs-537: Midterm Exam (Fall 2013) Professor Mcflub: The Solutions Edition
Please put your NAME (mandatory) on THIS page, and this page only.
Name:
1
Professor McFlub always makes mistakes, especially when teaching the undergraduate operating systems course.
In this exam, you get to correct all of McFlub’s mistakes, so that the world won’t be misinformed about how operating
systems function. Unfortunately, sometimes Professor McFlub is actually correct; in those cases, you should just point
that out. Also unfortunately, sometimes McFlub is wrong in more than one way; you have to identify all of them!
Finally, sometimes it is hard to tell; if that is the case, say so! You can’t always know if McFlub is wrong.
Please save the world from McFlub - if you can!
Tips for good answers: just make a short, concise bulleted list of what is wrong, and please make sure to include the
correction. For example:
• The missing code is x = x + 1 just after line 10 (with arrow to point to location where code goes).
2
Grading Page
3
1. Scheduling
“The picture here shows the scheduling of two processes: A, B, and C over time. Let’s look at it.”
(McFlub now draws this on the board)
|
Job | ABCABCABCABC ...
|____________________________
Time -->
“As you can clearly see, this is the behavior of a lottery scheduler, rotating between A, B, and C randomly. And
you can trust the results: I traced this behavior on a lottery scheduler I built late last night.”
• Probably not a lottery scheduler (though you can’t be sure, can you?). More likely Round Robin
• Some people pointed out three processes, not two. This, alas, was Professor A-D’s mistake, not
McFlub’s
ABBCCC
The Turnaround for A is thus 0, 10 for B, and 20 for C. Thus, average turnaround for STCF is 10, which is great.
See, I told you.”
4
3. MLFQ
“The Multi-level Feedback Queue has an intricate set of rules, used to build up a scheduler that achieves many
different goals. It starts with a set of queues, ordered from highest to lowest priority. And then it adds rules for
moving jobs among the queues. Let’s look at the rules, and see if they make sense:
That’s it! Amazingly, these rules are all you need. Well, that and a drink of coffee, if you’re tired like I am most
of the time.”
• Returns from the kernel require a different instruction, which both undoes what the trap did (re-
stores saved state), and changes privileged mode back to user mode
• Retry only happens in some cases (e.g., TLB miss); in other cases (e.g., syscall trap), the return must
return to the instruction after the trapping instruction
5
5. Base and Bounds
“Base/bounds-based virtual memory is really easy. Imagine you have a base register and a bounds register in
each CPU. The base points to the physical memory location where an address space is relocated; the bounds
tells us how big such an address space can be. Let’s do an example to understand this better.
Assume we have the following base/bounds pair:
Base : 0x1000
Bounds : 0x10
0x0
0x4
0x8
0xc
0x1000
0x1004
0x1008
FAULT (because this one is out of bounds)
Make sense?”
• No, because 0xc is a legal virtual address (clearly less than the bounds of 0x10)
• Should have translated to 0x100c instead of faulting
• Actually the OS has to do lot more stuff when using paging.... like:
• Switch PTBR on context switch
• Change page tables appropriately on memory allocation and free (e.g., on sbrk() call into kernel for
malloc, or perhaps automatically for stack)
• Monitor accesses to be able to perform page replacement (e.g., approximate LRU)
• Other examples are possible
6
7. Simple Paging
“With simple linear (array-based) page tables, assume we have the following page table, starting with the first
entry and going to the last:
0x8000002a
0x00000000
0x00000000
0x00000000
0x8000003e
0x00000000
0x80000017
0x00000000
0x00000000
0x8000000e
0x00000000
0x00000000
0x8000001f
0x00000000
0x8000001a
0x80000001
Assuming this is the entire page table, and that each page is 1K, we can see that we have a virtual address space
of size 32KB.
Now let’s look at how to do a translation. The format of each page table entry (PTE) above is as follows:
A single valid bit followed by the PFN (page frame number); you might recall this from the homework (run
it with SEED=1000 and PAGESIZE=1k).
Let’s translate the following virtual address: 0x33ef. As you can quickly see, this is an INVALID ACCESS.
Stupid program!”
(Is McFlub right? If not, please show him how the address really translates)
7
8. Segmentation
“With segmentation as our virtual memory system (not paging), assume we have a system with a 1KB virtual
address space. Assume the segmented address space has two segments: a code/heap combined segment that
grows in the positive direction, and a backwards-growing stack. The top bit of the virtual address is used to
differentiate between these segments.
Here is some segment register information:
See, easy!”
• Lots of advantages for paging, including avoiding external fragmentation and super flexible address
space usage
• Paging generally is not faster (indeed it might be slower with all of the page table accesses needed,
depending on TLB)
• Paging is more complex
• Paging can lead to internal fragmentation (waste within each page)
8
10. TLBs
“TLBs make paging systems run faster. Let’s imagine the following code snippet without TLBs:
int a[4096];
int b[4096];
int c = 0;
Without TLBs, on a system with 4-byte integers and a 4KB page size, and assuming a linear page table, this
code would access memory an additional 8192 times (due to page table accesses) – this is a worst-case analysis.
With TLBs, the page tables are only accessed 8 times in the worst-case. What a reduction! Oh, hold on: I think
I might have forgotten to think about instruction references...”
9
11. Multi-level Page Tables.
“I want to make multi-level page tables clearer for you. Imagine you have a linear page table for a process with a
64-byte address space (yes, tiny) and 4-byte pages. Assume each PTE is 1 byte in size. A multi-level page table
lets us chop the page table into page-sized chunks, and only allocate those chunks if there is a valid mapping in
the page of PTEs. The page directory points to those valid chunks, as follows.
Page directory:
Make sense?”
If the page size is 4 bytes, we need to chop up the page table into page-sized chunks. This would group
them into four groups of four, not eight groups of two. The page directory (PD) then would only have four
entries (and also nicely fit into a page). The first entry of the PD would be valid, the second not, and the
third and fourth valid. The first entry would point to A, the third to B* (added above), and the fourth to
C* (also added).
10
12. Spin Locks
“Assume we have a new instruction called the Load-and-Store-Zero, and it does the following atomically (here
is C pseudo-code):
Let’s use it to build a spin lock. Oh, I forgot my notes. Can someone write down how to build a spin lock out
of this instruction? Yeah, write down the code for both lock and unlock, as well as some kind of initialization
routine. No, I don’t remember how it should work; this is why I asked you to do it!”
(please help McFlub by using the LoadAndStoreZero instruction to build a working spin lock)
Here is one solution. The key idea is to realize that the free state of this lock should be 1, and locked 0;
then LoadAndStoreZero (LASZ) works fine:
11
14. Producers and Consumers
“Here is some code for the producer/consumer problem we are trying to solve. We’ll use a new primitive:
Pthread cond broadcast(). Unlike traditional signaling, this wakes up all threads waiting on a condition. Here
is some code using such a broadcast:
Now I think that this code doesn’t work. Or does it? Oh, I don’t know! Anyone have any ideas?”
This code seemingly makes the mistake of only using one condition variable in the producer/consumer
problem, but solves it by using broadcast to wake all waiting threads. Because each thread re-checks the
condition when awoken, only those who should be able to make progress will do so. Of course, this can be
inefficient, which is why we normally use two CVs and signal accordingly thus waking up only those who
need to be awoken.
12
15. Semaphores
“Semaphores are useful for lots of things. I found this code that uses semaphores. Pretty sure this is useful for
something, though I don’t remember what.
13
16. Deadlock?
“I wrote some code and it keeps deadlocking. How frustrating! Here is how the code works. Thread 1 grabs
Locks A and B (in some order); Thread 2 grabs Locks B and C (in some order); Thread 3 grabs Locks C and
D (in some order); Thread 4 grabs Locks D and A (in some order). Why in the world does this code deadlock?
Somebody help me; I just find concurrency hard.”
Assume Thread 1 grabs A, but then is waiting for B; Thread 2 grabs B and is waiting for C; Thread 3
grabs C but is waiting for D; Thread 4 grabs D but is waiting for A. Thus a cycle and a deadlock.
Solve in many possible ways. A good way is to order the lock acquistions: always grab A before B before
C before D. Doing so would prevent deadlock.
14