Operating Systems
Level: 3 — Production (from-scratch derivations, code-from-memory, explain-out-loud) Time limit: 45 minutes Total marks: 60
Answer all questions. Show all working. Where code is requested, write it from memory in C or clear pseudocode.
Question 1 — Scheduling from scratch (12 marks)
Four processes arrive as follows:
| Process | Arrival | Burst |
|---|---|---|
| P1 | 0 | 7 |
| P2 | 2 | 4 |
| P3 | 4 | 1 |
| P4 | 5 | 4 |
(a) Draw the Gantt chart and compute average waiting time and average turnaround time for SRTF (preemptive SJF). (7 marks)
(b) Repeat for Round Robin with quantum = 3 (assume a newly arrived process is placed in the ready queue before a process returning from the running state at the same instant). (5 marks)
Question 2 — Mutex from hardware atomics (10 marks)
(a) Write, from memory, the pseudocode for a spinlock using test_and_set, giving the atomic semantics of test_and_set explicitly. (4 marks)
(b) Write a spinlock using compare-and-swap (CAS) and state its atomic semantics. (3 marks)
(c) Explain out loud: which of the three critical-section properties (mutual exclusion, progress, bounded waiting) does a plain TAS spinlock fail to guarantee, and why? (3 marks)
Question 3 — Banker's algorithm (12 marks)
A system has 3 resource types (A, B, C) with total instances (10, 5, 7). State:
| Process | Allocation (A B C) | Max (A B C) |
|---|---|---|
| P0 | 0 1 0 | 7 5 3 |
| P1 | 2 0 0 | 3 2 2 |
| P2 | 3 0 2 | 9 0 2 |
| P3 | 2 1 1 | 2 2 2 |
| P4 | 0 0 2 | 4 3 3 |
(a) Compute Available and the Need matrix. (3 marks)
(b) Determine whether the system is in a safe state; if so give a safe sequence, showing the Work vector at each step. (6 marks)
(c) P1 requests (1, 0, 2). Apply the resource-request algorithm and decide whether it can be granted. (3 marks)
Question 4 — Demand paging & EAT (10 marks)
A system has memory access time 100 ns. Page-fault service time is 8 ms when no dirty write-back is needed and 20 ms when the victim page is dirty. 60% of replaced pages are dirty.
(a) Derive the Effective Access Time (EAT) formula for a page-fault rate , accounting for the dirty/clean split. (4 marks)
(b) The design goal is EAT within 20% of raw memory access time. Compute the maximum tolerable page-fault rate . (4 marks)
(c) Explain out loud the ordered steps the OS takes to service a page fault. (2 marks)
Question 5 — fork/exec/wait code trace (8 marks)
int main() {
int x = 0;
pid_t pid = fork();
if (pid == 0) {
x = x + 5;
printf("A:%d\n", x);
exit(0);
} else {
wait(NULL);
x = x + 10;
printf("B:%d\n", x);
}
return 0;
}(a) State every line of output and its guaranteed order. Justify using process semantics. (4 marks)
(b) Explain why the child's x = x + 5 does not affect the parent's x. Name the memory optimization that makes this cheap. (2 marks)
(c) A student replaces wait(NULL) with nothing (removes the line). Describe the resulting process-table hazard and its name. (2 marks)
Question 6 — Disk scheduling & RAID reasoning (8 marks)
(a) Disk head at cylinder 53, moving toward higher cylinders. Request queue: 98, 183, 37, 122, 14, 124, 65, 67. Compute total head movement for SCAN (goes to end cylinder 199 before reversing) and for C-LOOK. (5 marks)
(b) Explain out loud why RAID 5 suffers a "small-write penalty" and how RAID 10 avoids it, stating the storage-efficiency trade-off. (3 marks)
Answer keyMark scheme & solutions
Question 1
(a) SRTF (7 marks)
Track remaining times; at each event pick smallest remaining among arrived.
- t=0: only P1 → run P1.
- t=2: P2 arrives (rem 4), P1 rem 5 → run P2.
- t=4: P3 arrives (rem 1) < P2 rem 2 → run P3.
- t=5: P3 done (t=4→5). P4 arrives (rem 4). Remaining: P1=5, P2=2, P4=4 → run P2.
- t=7: P2 done. Remaining P1=5, P4=4 → run P4.
- t=11: P4 done. Run P1 (5) → done at 16.
Gantt: P1(0-2) | P2(2-4) | P3(4-5) | P2(5-7) | P4(7-11) | P1(11-16) (2 marks)
Completion: P1=16, P2=7, P3=5, P4=11. Turnaround = Completion − Arrival:
- P1=16, P2=5, P3=1, P4=6 → avg TAT = (16+5+1+6)/4 = 7.0 (2 marks)
Waiting = TAT − Burst:
- P1=9, P2=1, P3=0, P4=2 → avg WT = 12/4 = 3.0 (3 marks)
(b) Round Robin q=3 (5 marks)
Queue events (new arrival enqueued before returning process):
- t=0: run P1 (rem 7→4), during run P2(t2),P3? no P3 at4. Queue after: [P2, P1]
- t=3: run P2 (4→1). Arrivals: P3(t4),P4(t5) enqueue. Queue: [P1, P3, P4, P2]
- t=6: run P1 (4→1). Queue: [P3, P4, P2, P1]
- t=9: run P3 (1→0) done t=10. Queue: [P4, P2, P1]
- t=10: run P4 (4→1). Queue: [P2, P1, P4]
- t=13: run P2 (1→0) done t=14. Queue: [P1, P4]
- t=14: run P1 (1→0) done t=15. Queue: [P4]
- t=15: run P4 (1→0) done t=16.
Gantt: P1(0-3)|P2(3-6)|P1(6-9)|P3(9-10)|P4(10-13)|P2(13-14)|P1(14-15)|P4(15-16) (2 marks)
Completion: P1=15, P2=14, P3=10, P4=16. TAT: P1=15, P2=12, P3=6, P4=11 → avg = 44/4 = 11.0 (1.5) WT = TAT−Burst: P1=8, P2=8, P3=5, P4=7 → avg = 28/4 = 7.0 (1.5)
Question 2
(a) TAS spinlock (4 marks)
test_and_set(target) atomically: reads old value, sets *target=1, returns old. (2)
lock = 0;
acquire(): while (test_and_set(&lock)) ; // spin while old was 1
release(): lock = 0;
(2 marks)
(b) CAS spinlock (3 marks)
CAS(addr, expected, new) atomically: if *addr==expected set *addr=new and return true else return false. (1)
acquire(): while (!CAS(&lock, 0, 1)) ;
release(): lock = 0;
(2 marks)
(c) (3 marks)
Fails bounded waiting (1). ME and progress hold, but there is no queue/ordering: a waiting thread may be starved indefinitely because when the lock frees, any spinning thread (including newly arriving ones) may grab it; no bound on the number of times others enter first (2).
Question 3
(a) (3 marks)
Total = (10,5,7). Sum of Allocation = (7,2,5). Available = (3, 3, 2) (1 mark)
Need = Max − Allocation:
| P | Need |
|---|---|
| P0 | 7 4 3 |
| P1 | 1 2 2 |
| P2 | 6 0 0 |
| P3 | 0 1 1 |
| P4 | 4 3 1 |
| (2 marks) |
(b) Safety (6 marks)
Work=(3,3,2).
- P1 Need(1,2,2)≤Work → Work=(3,3,2)+(2,0,0)=(5,3,2)
- P3 Need(0,1,1)≤Work → Work=(5,3,2)+(2,1,1)=(7,4,3)
- P4 Need(4,3,1)≤(7,4,3) → Work=(7,4,3)+(0,0,2)=(7,4,5)
- P0 Need(7,4,3)≤(7,4,5) → Work=(7,4,5)+(0,1,0)=(7,5,5)
- P2 Need(6,0,0)≤(7,5,5) → Work=(7,5,5)+(3,0,2)=(10,5,7)
All finish → SAFE. Safe sequence: P1, P3, P4, P0, P2 (6 marks; award per correct step, other valid sequences accepted).
(c) P1 requests (1,0,2) (3 marks)
Request(1,0,2) ≤ Need(1,2,2) ✓ and ≤ Available(3,3,2) ✓. Pretend-allocate: Available=(2,3,0), P1 Alloc=(3,0,2), Need=(0,2,0). Run safety from Work=(2,3,0): P3 Need(0,1,1)? C=0>0 no... check: (0,1,1)≤(2,3,0)? C:1≤0 false. Try P1 Need(0,2,0)≤(2,3,0)✓→Work=(4,3,2). Then P3(0,1,1)≤(4,3,2)✓→(6,4,3); P4(4,3,1)✓→(6,4,5); P0(7,4,3)? A:7>6 no; P2(6,0,0)≤(6,4,5)✓→(9,4,7); P0(7,4,3)≤(9,4,7)✓. All finish → safe, GRANT the request (3 marks).
Question 4
(a) EAT (4 marks)
On hit (prob ): 100 ns. On fault (prob ): clean 40% costs 8 ms, dirty 60% costs 20 ms. Average fault service = ms ns. (2)
(2 marks)
(b) Max p (4 marks)
Within 20%: EAT ≤ 120 ns. (≈ 1 fault per 760,000 accesses). (4 marks)
(c) Fault steps (2 marks)
Trap to OS → check reference valid (else abort) → find free frame / choose victim (write back if dirty) → schedule disk read of page → update page table (valid bit, frame) → restart faulting instruction. (2 marks, any ordered ≥4 steps)
Question 5
(a) Output (4 marks)
A:5 then B:10, always in that order. (2)
Child increments its copy of x (0→5) prints A:5, exits. Parent wait(NULL) blocks until child terminates, so A prints before B; then parent's x (still 0) →10, prints B:10. (2)
(b) (2 marks)
fork gives child a separate address space — writes are private; parent's x unchanged (1). Cheap via copy-on-write: pages shared read-only until a write triggers a copy (1).
(c) (2 marks)
Child terminates but parent never reaps it → its PCB/exit status lingers in the process table as a zombie (defunct) process; accumulation can exhaust PID/table entries. (2)
Question 6
(a) (5 marks)
Sorted requests: 14,37,65,67,98,122,124,183. Head 53, moving up.
SCAN (up to 199 then reverse): Up: 53→65→67→98→122→124→183→199, then down: 199→37→14. Movement = (199−53) + (199−14) = 146 + 185 = 331 (2.5)
C-LOOK (up serving, jump to lowest, continue up; no service on jump-back except it counts as movement): Up: 53→65→67→98→122→124→183 = 130. Jump 183→14 = 169. Then 14→37 = 23. Total = 130 + 169 + 23 = 322 (2.5) (Accept 130+169 = 299 if jump-back and remaining lower requests handling stated; standard C-LOOK counts return + serve remaining = 322.)
(b) (3 marks)
RAID 5 small write: updating one block requires read-old-data + read-old-parity, compute new parity, write-data + write-parity = 4 I/Os per logical write (read-modify-write) (1.5). RAID 10 (mirrored stripes) just writes each block to two mirrors = 2 I/Os, no parity recompute (1). Trade-off: RAID 10 costs 50% capacity (mirroring) vs RAID 5's single-parity overhead of only (0.5).
[
{"claim":"SRTF average waiting time = 3.0","code":"tat=[16,5,1,6]; burst=[7,4,1,4]; wt=[t-b for t,b in zip(tat,burst)]; result=(sum(wt)/4==3.0)"},
{"claim":"SRTF average turnaround = 7.0","code":"tat=[16,5,1,6]; result=(sum(tat)/4==7.0)"},
{"claim":"RR q=3 average waiting = 7.0","code":"tat=[15,12,6,11]; burst=[7,4,1,4]; wt=[t-b for t,b in zip(tat,burst)]; result=(sum(wt)/4==7.0)"},
{"claim":"Banker Available = (3,3,2)","code":"total=[10,5,7]; alloc=[[0,1,0],[2,0,0],[3,0,2],[2,1,1],[0,0,2]]; s=[sum(c) for c in zip(*alloc)]; avail=[t-x for t,x in zip(total,s)]; result=(avail==[3,3,2])"},
{"claim":"Max tolerable page fault rate approx 1.316e-6","code":"p=20/15200000; result=(abs(p-1.3157894736842e-6)<1e-9)"},
{"claim":"SCAN total head movement = 331","code":"result=((199-53)+(199-14)==331)"},
{"claim":"C-LOOK total head movement = 322","code":"result=(130+169+23==322)"}
]