I/O & Interrupts
Polling vs interrupts vs DMA, blocking vs non-blocking, and where epoll fits.
Talking to Devices
The CPU is far faster than disks and networks, so the OS must move data to/from devices without wasting cycles. Three techniques, in order of efficiency:
| Method | How | Cost |
|---|---|---|
| Polling | CPU repeatedly checks "ready yet?" | Burns CPU busy-waiting |
| Interrupts | Device signals the CPU when done | CPU works meanwhile; one interrupt per event |
| DMA | A controller moves data to RAM directly, then one interrupt | Frees the CPU during the transfer |
Interrupts
An interrupt is a hardware signal that makes the CPU pause, save state, jump to an interrupt service routine (ISR), then resume. It’s how a keypress, a completed disk read, or a timer tick gets the OS’s attention without polling.
Blocking vs Non-Blocking I/O
- Thread sleeps until data is ready — simple
- Call returns immediately; you poll or get notified — scalable
A blocking read is easy but ties up a thread per connection. To handle thousands of connections, servers use non-blocking I/O + an event loop: ask the OS to watch many file descriptors and tell you which are ready.
epoll and the C10k Problem
The old select()/poll() scan every descriptor each call — O(n). Linux’s epoll (BSD’s kqueue) registers descriptors once and returns only the ready ones — O(ready) — enabling a single thread to serve tens of thousands of sockets. This is the engine under Nginx, Node.js and Redis.
ep = epoll_create1(0) epoll_ctl(ep, ADD, sock, EPOLLIN) # register once while True: events = epoll_wait(ep) # only ready fds for e in events: handle(e)
Interview Questions
Polling vs interrupts?
Polling has the CPU repeatedly check a device, wasting cycles. Interrupts let the device notify the CPU when ready, so the CPU does other work in the meantime.
What is DMA and why does it help?
Direct Memory Access lets a dedicated controller transfer data between a device and RAM without the CPU copying each byte; the CPU is interrupted only once when the whole transfer completes.
Why is epoll better than select for many connections?
select/poll are O(n) — they rescan all descriptors every call. epoll registers interest once and returns only the descriptors that became ready, scaling to tens of thousands of connections in one thread.
How does preemptive scheduling actually preempt?
A hardware timer interrupt periodically transfers control to the kernel, which runs the scheduler and can switch to another process regardless of what was running.