« Previous Lecture | Next Lecture »
Linux CPU Scheduler Explained: Scheduling Classes and Policies (Updated for Modern Kernels)
Part 1 of our free Linux kernel development course — understand how the Linux CPU scheduler decides which thread runs next
The Linux CPU scheduler is the piece of kernel code that answers one deceptively simple question millions of times per second: which thread should run on this CPU right now? In this lesson of our free Linux kernel development course, you will learn how the Linux CPU scheduler is organized internally, what scheduling classes and scheduling policies are, and how modern kernels (6.6 and newer, including the current 7.x series) pick the next task to run.
This tutorial is part of EmbeddedPathashala’s free Linux kernel programming course and free embedded systems course. Everything here reflects the scheduler as it exists in today’s kernels — including the EEVDF fair scheduler and the new sched_ext class — not the older CFS-only description you will find in many books.
What You Will Learn
- Why the thread (not the process) is the unit of scheduling in Linux
- The modular scheduling-class architecture of the Linux CPU scheduler
- All the scheduling policies:
SCHED_OTHER,SCHED_BATCH,SCHED_IDLE,SCHED_FIFO,SCHED_RR,SCHED_DEADLINE, and the new BPF-basedsched_ext - How the kernel walks the class hierarchy to pick the next task
- What changed in kernel 6.6 (EEVDF) and kernel 6.12 (
sched_ext)
Prerequisites
- Basic C programming and comfort with the Linux command line
- Understanding of processes and threads (covered earlier in this free Linux kernel development course)
- Any Linux machine or virtual machine — kernel 6.6 or newer recommended
The Thread Is What Gets Scheduled
A common beginner mistake is thinking Linux schedules processes. It does not. On Linux, the kernel schedulable entity (KSE) is the thread. A process is simply a container: it holds the address space, open files, and credentials, while its threads are the actual units of execution that compete for CPU time. A single-threaded process is just a process with exactly one schedulable thread.
Every thread carries two scheduling attributes, assigned per thread, not per process:
- A scheduling policy — the algorithm that governs it
- A priority — either a nice value (for normal threads) or a real-time priority (for real-time threads)
The default for every new thread is SCHED_OTHER (also called SCHED_NORMAL) with real-time priority 0 and nice value 0.
Linux CPU Scheduler Architecture: Scheduling Classes
The Linux CPU scheduler is not one giant algorithm. Since kernel 2.6.23 it has been modular: the core scheduler (kernel/sched/core.c) knows nothing about fairness, deadlines, or time slices. Instead, it delegates to a chain of scheduling classes, each implementing its own algorithm behind a common interface (a structure of function pointers such as enqueue_task, dequeue_task, and pick_task).
When a CPU needs a new task, the core scheduler walks the classes in strict priority order and asks each one: “do you have a runnable task?” The first class that answers yes wins. This means a runnable real-time thread will always be chosen before any normal thread.
| Core Scheduler (kernel/sched/core.c) — asks each class in order ↓ | ||
| 1. stop_sched_class | Highest priority. Kernel-internal only (CPU hotplug, migration). Userspace can never use it. | |
| 2. dl_sched_class | Deadline tasks: SCHED_DEADLINE (runtime / deadline / period model) |
|
| 3. rt_sched_class | Real-time tasks: SCHED_FIFO and SCHED_RR (priorities 1–99) |
|
| 4. fair_sched_class | Normal tasks: SCHED_OTHER, SCHED_BATCH, SCHED_IDLE. Algorithm: EEVDF (was CFS before kernel 6.6) |
|
| 5. ext_sched_class | sched_ext (kernel 6.12+): custom schedulers written as BPF programs (SCHED_EXT) |
|
| 6. idle_sched_class | The per-CPU idle thread (swapper). Runs only when nothing else is runnable. | |
Note: the exact position of ext_sched_class relative to the fair class can depend on kernel configuration, but conceptually it sits alongside/below the fair class and above idle. The key idea to remember for interviews: classes are consulted in fixed priority order, and stop > deadline > RT > fair > idle always holds.
Scheduling Policies in the Linux CPU Scheduler
Each scheduling class implements one or more policies that userspace can select. Here is the complete, up-to-date map:
| Policy | Class | Priority Range | Typical Use |
|---|---|---|---|
SCHED_OTHER |
fair (EEVDF) | nice −20 to +19 | Default. Almost everything: shells, browsers, daemons |
SCHED_BATCH |
fair (EEVDF) | nice −20 to +19 | CPU-heavy batch jobs; treated as less interactive |
SCHED_IDLE |
fair (EEVDF) | (nice ignored) | Extremely low importance work (indexers, background scans) |
SCHED_FIFO |
rt | RT prio 1–99 | Run-to-completion real-time; no time slicing |
SCHED_RR |
rt | RT prio 1–99 | Real-time with round-robin time slices among equal priority |
SCHED_DEADLINE |
dl | runtime/deadline/period | Periodic hard-deadline work (audio pipelines, control loops) |
SCHED_EXT |
ext (6.12+) | defined by BPF scheduler | Custom schedulers (gaming, datacenter experiments) |
What Changed in Modern Kernels: CFS → EEVDF and sched_ext
If you learned Linux CPU scheduling from books written before 2023, two big updates matter:
1. EEVDF replaced the CFS pick logic (kernel 6.6, October 2023)
The Completely Fair Scheduler (CFS) drove SCHED_OTHER threads from kernel 2.6.23 to 6.5. Since kernel 6.6, the fair class uses EEVDF (Earliest Eligible Virtual Deadline First). The fair class, its file kernel/sched/fair.c, and much of the surrounding machinery (load weights, cgroup support) remain — but the decision of which fair task runs next is now deadline-based rather than “smallest vruntime wins”. We cover EEVDF in depth in the next lecture of this free Linux kernel programming course.
2. sched_ext arrived (kernel 6.12, late 2024)
sched_ext is a new scheduling class whose behavior is supplied at runtime by a BPF program. This lets developers experiment with completely custom scheduling algorithms — without patching or rebuilding the kernel — and safely fall back to the default scheduler if the BPF scheduler ever misbehaves. Valve’s SteamOS-related work and datacenter operators have been early adopters.
How the Scheduler Picks the Next Task: The Big Picture
| Scheduling point reached (timer tick, task sleeps/wakes, syscall return, preemption) |
| ↓ |
| Core scheduler runs schedule() → asks classes top-down: stop → deadline → rt → fair → ext → idle |
| ↓ |
| First class with a runnable task returns it → context switch to that task |
| ↓ |
| If no class has anything runnable → per-CPU idle thread runs |
Because most systems run few or no real-time tasks, in practice the fair class answers the question the vast majority of the time. That is why the fair scheduler (CFS historically, EEVDF today) gets so much attention in any Linux kernel development course.
Quick Hands-On: See Scheduling Classes on Your System
You can observe policies right now. Every thread exposes its policy through /proc:
# Show the scheduling policy number of PID 1 (field 41 of /proc/PID/stat)
awk '{print "policy number:", $41}' /proc/1/stat
# Human-readable details for any thread
grep -E "policy|prio" /proc/1/sched
Policy numbers map as: 0 = SCHED_OTHER, 1 = SCHED_FIFO, 2 = SCHED_RR, 3 = SCHED_BATCH, 5 = SCHED_IDLE, 6 = SCHED_DEADLINE, 7 = SCHED_EXT. In the third lecture of this series we build a complete tool around chrt and ps to query every thread on the system.
Common Mistakes and Interview Traps
- “Linux schedules processes” — wrong; it schedules threads (KSEs).
- “Higher nice value means higher priority” — wrong; nice +19 is the lowest normal priority, nice −20 the highest.
- “CFS is the current Linux scheduler” — outdated; since kernel 6.6 the fair class uses EEVDF.
- “Real-time priority applies to SCHED_OTHER threads” — no; normal threads always report RT priority 0. Their weight comes from the nice value.
- Setting SCHED_FIFO priority 99 on a busy-looping thread — this can starve the whole CPU. Kernels reserve a small RT bandwidth safety margin, but it is still a classic self-inflicted lockup.
Best Practices
- Leave threads on
SCHED_OTHERunless you have a measured latency requirement. - Prefer
SCHED_DEADLINEover FIFO/RR for periodic real-time work — it lets the kernel do admission control. - Use
SCHED_IDLEorSCHED_BATCHfor background jobs on embedded devices to protect the UI/main loop. - On embedded Linux, audit RT threads with the querying techniques from lecture 3 — rogue vendors sometimes ship drivers with unjustified RT priorities.
Key Takeaways
- The Linux CPU scheduler schedules threads, each with a per-thread policy and priority.
- The scheduler is modular: fixed-priority scheduling classes (stop > deadline > rt > fair > ext > idle) hide different algorithms behind one interface.
- Since kernel 6.6, the fair class runs EEVDF; since 6.12, sched_ext enables BPF-defined custom schedulers.
- The default policy everywhere is
SCHED_OTHERwith RT priority 0.
Conclusion
You now have the modern mental model of the Linux CPU scheduler: a small, algorithm-agnostic core that consults scheduling classes in strict priority order, with the EEVDF-powered fair class doing most of the day-to-day work. This architecture is exactly why Linux could swap CFS for EEVDF, and later add sched_ext, without disturbing real-time or deadline scheduling. In the next lecture of this free Linux kernel development course, we go inside the fair class and understand how EEVDF actually chooses among normal threads — eligibility, lag, and virtual deadlines made simple.
FAQ
What is the Linux CPU scheduler?
It is the kernel subsystem that decides which runnable thread executes on each CPU and for how long. It is modular, built from priority-ordered scheduling classes.
Which scheduler does Linux use today?
For normal threads, modern kernels (6.6 and later, including the current 7.x series) use EEVDF inside the fair scheduling class. Real-time threads use the RT and deadline classes, and kernel 6.12+ optionally supports BPF-based custom schedulers via sched_ext.
Is CFS still used in Linux?
The fair scheduling class and its source file remain, but the task-selection algorithm was changed from CFS’s smallest-vruntime rule to EEVDF’s earliest-eligible-virtual-deadline rule in kernel 6.6.
What is the default scheduling policy in Linux?
SCHED_OTHER (also called SCHED_NORMAL) with real-time priority 0 and nice value 0.
What is the difference between SCHED_FIFO and SCHED_RR?
Both are real-time policies with priorities 1–99. FIFO tasks run until they block, yield, or are preempted by higher priority; RR adds a time slice so equal-priority RT tasks rotate.
What is sched_ext?
A scheduling class merged in kernel 6.12 that lets you load a custom CPU scheduler as a BPF program at runtime, with automatic fallback to the default scheduler on error.
Does a process or a thread get scheduled in Linux?
The thread. Scheduling policy and priority are per-thread attributes; two threads of the same process can run under different policies.
Where is this free Linux kernel development course going next?
Lecture 2 covers the EEVDF fair scheduler internals, and lecture 3 shows practical querying of any thread’s policy and priority with chrt, ps, and C code.
Continue the free Linux kernel programming course on EmbeddedPathashala

2 Comments