How Linux picks the next task: scheduling classes (deadline/RT/CFS/idle), CFS/EEVDF fairness via vruntime + nice weight & the red-black tree, preemption (need_resched, PREEMPT levels) and the context switch cost, per-CPU run queues, load balancing over scheduling domains, and CPU affinity/isolation.
How the kernel decides which task runs next on each CPU — priorities, fairness, preemption, and the context switch. Original, interview-focused notes on the Linux scheduler.
The scheduler picks the next task per-CPU from scheduling classes in priority order: stop → deadline → real-time → CFS (normal) → idle. Most tasks live in CFS, whose goal is fairness: give every runnable task a proportional share of CPU.
| Class | For | Policy |
|---|---|---|
Deadline (SCHED_DEADLINE) | Hard timing | EDF — earliest deadline first (runtime/period/deadline). |
Real-time (SCHED_FIFO/SCHED_RR) | Latency-critical | Fixed priority 1–99; RT always beats normal tasks. |
CFS / EEVDF (SCHED_NORMAL) | Everything else | Proportional fair share, weighted by nice. |
Idle (SCHED_IDLE) | Background | Runs only when nothing else is runnable. |
A higher class always preempts a lower one, so a busy SCHED_FIFO task can starve normal tasks — why RT
priorities are used sparingly.
The Completely Fair Scheduler (in recent kernels, refined by EEVDF) models an ideal "everyone runs at once" CPU and picks whoever is most behind:
vruntime — each task's accumulated runtime, weighted by nice. Low-nice
(high-priority) tasks accrue vruntime slower, so they get more CPU.vruntime; the scheduler
runs the leftmost (smallest vruntime) task. O(log n) pick.TIF_NEED_RESCHED; schedule() then runs.PREEMPT_NONE (server, only at syscall
boundaries), PREEMPT_VOLUNTARY, PREEMPT (low-latency), PREEMPT_RT
(real-time, nearly everything preemptible).CR3, if the mm differs — threads of one process skip this), restore the new task. Costs
cycles plus TLB/cache disturbance — the real price.taskset, sched_setaffinity) pins tasks; isolation
(isolcpus, cgroup cpuset) reserves CPUs — the low-latency/trading toolkit. See
Low-Latency.nice actually change? (weight → CPU share, not a fixed slice)