Exercise 1: Blocking With No Other Ready Process — Possible Solution ==================================================================== THE TEST ------------------------------ solo.transition(ProcessState.RUNNING) sched = Scheduler() # genuinely empty -- no other process exists iok.programs[solo.pid] = [('READ_DISK_BLOCKING',), ('WORK',)] for _ in range(20): iok.run_step() RESULT ------------------------------ after step 1: solo own state = BLOCKED, current_pcb = None after 20 real steps: solo own state = RUNNING, own remaining ops = 0 solo blocks on its very first turn, current_pcb correctly becomes None, and by step 20 solo has resumed, run its own follow-up WORK step, and has zero ops left. WHY THE CPU GOING IDLE DOESN'T STALL THE KERNEL ------------------------------ run_step() always ticks the disk forward FIRST, unconditionally, on every single real step -- completely independent of whether self.current_pcb is None or points at a real running process: def run_step(self): completed = self.driver.disk.tick() if completed is not None: self.interrupts.dispatch(DISK_INTERRUPT, completed) if self.current_pcb is not None: ... Because the disk's own clock advances regardless, the 15-tick operation genuinely finishes on schedule even with nobody running at all. Once it does, _on_disk_complete() adds solo back to the ready queue and transitions it to READY. The NEXT timer interrupt (fired from the unconditional ticks_since_switch counter at the bottom of run_step(), which also keeps incrementing regardless of current_pcb) then picks solo up via the fixed _on_timer() (Finding 4's own guard correctly skips trying to re-add the None current_pcb) and resumes it. WHY THIS IS THE SCENARIO THAT EXPOSED FINDING 4'S OWN BUG ------------------------------ This exact sequence -- current_pcb genuinely None, followed by a timer interrupt firing after a process has been added back to the ready queue -- is precisely the state combination the ORIGINAL, unguarded _on_timer() crashed on. This exercise is effectively Finding 4's own bug reproduced from first principles, using the real (fixed) kernel to confirm it now completes cleanly rather than crashing. WHY THIS WORKS AS AN ANSWER ------------------------------ Deliberately using the smallest possible system -- exactly one process, zero others -- removes every other variable and isolates the single question this exercise is actually testing: does the kernel correctly handle a genuinely idle CPU, or does it only work by accident because there's always been a second process to fall back on. Confirming solo resumes and completes correctly proves it's the former.