While one program waits on the disk, does the CPU rest or go do something else? Changing who sits at the counter costs a moment: write down where you left off, then fetch the next person's papers.
See this first in FoundationsCan a computer do something else while it waits?Two common questions, answered here: "When code hits IO, does the CPU rest or go do something else?" and "With one core, how is work split up — and when does the CPU actually rest?" Short answer: it almost never rests. Follow program A from the moment it asks for a file, through B and C running, the CPU sleeping, and A resuming.
Your code runs in user mode, where it cannot command devices or touch other programs' memory. For that it must ask the OS — a system call — which switches the CPU into kernel mode to run OS code. Note that the CPU is not resting here; it is simply running different code.
A running program's current state lives in a few CPU registers: how far it got (PC), values mid-computation, the stack position. That bundle is its context. A CPU holds one context at a time, so running someone else means writing this one down and loading another. Save + restore = a context switch — the amber and blue slots in the animation.
Voluntarily: a program that must wait calls into the kernel and drops to Waiting. Forcibly: a hardware timer interrupts every few milliseconds and hands control back to the kernel, so a program that never yields still gets pushed aside. That is preemption.
When the disk finishes it raises an interrupt; the CPU stops what it is doing, jumps to kernel handler code, and the waiting program moves from Waiting to Ready. The CPU never sits watching the disk — the device reports back.
Only when nothing is Ready. Then the kernel runs the idle task, which uses an instruction like HLT to drop the CPU into a low-power state until the next interrupt. That is why laptops last and why a server can show 5% CPU. The hatched band in the timeline is that real rest.
The CPU is running program A. Its registers hold A's PC and values — a CPU holds exactly one program's context at a time. B and C wait with their contexts parked in storage.
Try it in the simulator
Now run it for real. Below are three programs with different personalities: A keeps calling a function, B does nothing but heavy computation, and C is a server that queries a database. They share a single CPU. The green border marks whoever currently holds it, and each PC marker shows how far that program has run. Watch this in particular — while A calls tax() and returns, the CPU never moves to another program (a call is just a jump). C, by contrast, yields at db.query(), and B never yields so it gets dragged out when its time slice expires. The log below names the reason every time. Change the time slice and watch switches — and the kernel's share — rise or fall.
Terms in this chapter
Why it evolved this way
If scheduling relied on goodwill alone, one infinite loop could freeze the whole machine — early systems worked exactly that way. Timer-based preemption is what made one runaway program survivable. Keep this in mind: the event loop, later, does not have it.
The CPU does not rest while waiting — it goes elsewhere through the kernel. It rests only when nothing is Ready.
The remaining problem
But processes were expensive to create and switch (ch.4). Is there a lighter way to run several flows inside one program? →