Linux Scheduling Policies Explained – SCHED_OTHER, FIFO, RR, DEADLINE and More
Part 2 of the CPU scheduler module in our free Linux kernel development course – every Linux scheduling policy, priority range, and when to use each
Beginner to Intermediate
CPU Scheduling – Lesson 2
Modern 6.x kernels
In the previous lesson of this free Linux kernel development course we established that Linux schedules threads, never processes. The next question is obvious: by what rules? The answer is Linux scheduling policies. A scheduling policy is the algorithm that decides how a thread competes for the CPU – whether it shares time fairly, runs with strict real-time priority, or must meet hard deadlines.
The POSIX standard requires a compliant operating system to offer at least three policies. Linux implements those three and goes well beyond them, adding batch, idle, and deadline policies. Understanding Linux scheduling policies deeply is essential for anyone following our free Linux device drivers course or free embedded systems course, because driver threads, IRQ threads, and real-time applications all depend on choosing the right policy.
Topics Covered in This Lesson
SCHED_OTHER
SCHED_FIFO
SCHED_RR
SCHED_DEADLINE
SCHED_BATCH / SCHED_IDLE
Nice value
Real-time priority
What You Will Learn
- The three POSIX scheduling policies and the extra policies Linux adds on top
- How the nice value (-20 to +19) and real-time priority (1 to 99) scales work – and how they relate
- The exact behavioral difference between SCHED_FIFO and SCHED_RR
- What SCHED_DEADLINE offers and why it outranks every other policy
- How real-time throttling protects your system from a runaway real-time thread
- How to view the policy and priority of any thread on your machine
Prerequisites
Read Part 1 of this series (the Kernel Schedulable Entity) first. You need a Linux machine with a modern 6.x kernel for the hands-on commands. Root or sudo access is helpful for the real-time experiments but not mandatory for reading policies.
Why Multiple Scheduling Policies Exist
A desktop browser, an audio-processing thread, a background backup job, and a motor-control loop in an embedded system all have completely different needs. One wants responsiveness, one wants guaranteed periodic CPU time, one should politely stay out of the way, and one must never miss a deadline. No single algorithm can serve all of them well, so the kernel exposes several Linux scheduling policies and lets each thread declare which rules it wants to play by.
Every thread on the system always has exactly one policy. If you never set one, the thread runs under the default policy, SCHED_OTHER (also called SCHED_NORMAL inside the kernel).
The Complete Policy Table (Modern Kernels)
| Policy | Type | Priority scale | Behavior in one line | Typical use |
|---|---|---|---|---|
SCHED_OTHER |
Fair (non-RT) | Nice −20 … +19 | Default; fair time-sharing via EEVDF (kernel 6.6+) | Almost everything: apps, services, shells |
SCHED_BATCH |
Fair (non-RT) | Nice −20 … +19 | Like OTHER but treated as CPU-hungry; fewer wakeup preemptions | Compiles, batch jobs, number crunching |
SCHED_IDLE |
Fair (non-RT) | Nice ignored (extremely low weight) | Runs only when the CPU has nearly nothing else to do | Background indexers, opportunistic cleanup |
SCHED_FIFO |
Real-time (POSIX) | RT priority 1 … 99 | Runs until it blocks, yields, or a higher-priority RT thread appears – no time slice | Short, critical control loops; IRQ threads |
SCHED_RR |
Real-time (POSIX) | RT priority 1 … 99 | Like FIFO, but equal-priority threads rotate on a fixed time slice | Multiple cooperating RT threads at one priority |
SCHED_DEADLINE |
Real-time (Linux) | No priority – uses runtime/deadline/period | Guarantees a CPU budget every period; preempts all other policies | Periodic hard-deadline work: audio, robotics, video pipelines |
The three policies required by POSIX are SCHED_OTHER, SCHED_FIFO, and SCHED_RR. SCHED_BATCH, SCHED_IDLE, and SCHED_DEADLINE are Linux-specific extensions.
The Two Priority Scales – Do Not Mix Them Up
Beginners frequently confuse the nice value with real-time priority. They are separate scales for separate worlds:
| Aspect | Nice value | Real-time priority |
|---|---|---|
| Applies to | SCHED_OTHER / SCHED_BATCH | SCHED_FIFO / SCHED_RR |
| Range | −20 (highest weight) … +19 (lowest) | 1 (lowest) … 99 (highest) |
| Meaning | A relative weight: a nicer thread gets a smaller share, but never starves | A strict rank: higher always preempts lower, and can starve it forever |
| Relationship | Any real-time thread (even RT priority 1) always beats every nice-based thread (even nice −20) | |
A useful rule of thumb: each step down the nice scale gives a thread roughly 10% more CPU weight relative to its neighbors. The nice value shapes proportions; real-time priority defines absolute rank.
SCHED_FIFO vs SCHED_RR – the Only Difference
Both are fixed-priority real-time policies with the same 1–99 range. The single difference appears when two or more threads share the same priority:
- SCHED_FIFO: the running thread keeps the CPU until it voluntarily blocks, yields, or is preempted by a strictly higher priority. Same-priority peers wait indefinitely.
- SCHED_RR: the kernel enforces a time slice (visible in
/proc/sys/kernel/sched_rr_timeslice_ms, typically 100 ms). When the slice expires, the thread moves to the back of its priority level and the next same-priority thread runs.
SCHED_DEADLINE – Beyond Priorities
Priorities cannot express “I need 2 ms of CPU every 10 ms”. SCHED_DEADLINE can. Each deadline thread declares three parameters – runtime, deadline, and period – and the kernel’s admission control either guarantees that budget or refuses to accept the thread. Deadline threads outrank FIFO and RR, making this the highest-privilege policy on Linux. It is ideal for periodic embedded workloads such as sensor sampling and motor control.
Real-Time Throttling – Your Safety Net
A buggy SCHED_FIFO thread at priority 99 that spins forever would freeze the machine. To prevent this, the kernel by default reserves a small share of each second for non-real-time work:
# Default: RT threads may use 950000 us out of every 1000000 us
cat /proc/sys/kernel/sched_rt_period_us
cat /proc/sys/kernel/sched_rt_runtime_us
That 5% reserve keeps your shell alive even when a real-time thread misbehaves. Disable it (-1) only on dedicated, well-tested real-time systems.
Hands-On: View Policy and Priority of Any Thread
# Show policy class and RT priority for every thread
# cls: TS = SCHED_OTHER, B = BATCH, IDL = IDLE, FF = FIFO, RR = RR, DLN = DEADLINE
ps -eLo pid,tid,cls,rtprio,ni,comm | head -20
# Inspect one thread in detail with chrt
chrt -p 1 # policy and priority of PID 1 (systemd/init)
# Find real-time threads on your system right now
ps -eLo cls,rtprio,comm | grep -E '^ *(FF|RR)'
On most desktop systems you will find kernel threads such as migration/N and threaded IRQ handlers running under real-time policies – proof that the kernel itself relies on these policies for correctness.
A quick experiment with nice (no root needed for positive values):
# Run a CPU burner politely at nice +15
nice -n 15 sh -c 'while :; do :; done' &
# Watch its share drop when a nice-0 competitor appears
sh -c 'while :; do :; done' &
top # observe %CPU: nice 0 dominates, nice +15 gets scraps
kill %1 %2
Common Mistakes and Best Practices
- Do not use RT priority 99 casually. Priority 99 competes with critical kernel threads. Well-designed systems leave the top levels for the kernel and use modest values (e.g. 10–50) for applications.
- Never run an unbounded loop under SCHED_FIFO. Real-time threads must block or yield; a spinning FIFO thread starves everything below it (only throttling saves you).
- Do not assume nice affects real-time threads. It does not. Nice is meaningful only for the fair policies.
- Prefer SCHED_DEADLINE for periodic work. If your requirement is “X time every Y period”, deadline scheduling states it directly instead of hoping a priority number works out.
- Remember that raising priority needs privilege. Setting RT policies or negative nice values requires
CAP_SYS_NICEor an appropriateRLIMIT_RTPRIO.
Interview Questions and Answers
Q1: Which scheduling policies does POSIX mandate, and what does Linux add?
A: POSIX mandates SCHED_OTHER, SCHED_FIFO, and SCHED_RR. Linux adds SCHED_BATCH, SCHED_IDLE, and SCHED_DEADLINE.
Q2: What is the only behavioral difference between SCHED_FIFO and SCHED_RR?
A: Time slicing among equal-priority threads. FIFO has none – the runner continues until it blocks or is preempted by a higher priority. RR rotates equal-priority threads on a fixed time slice.
Q3: Can a SCHED_OTHER thread with nice −20 preempt a SCHED_FIFO thread with priority 1?
A: No. Real-time policies always outrank fair policies. The nice scale and the RT priority scale never compete directly.
Q4: Why does SCHED_DEADLINE perform admission control?
A: Because it makes guarantees. The kernel must verify that the sum of all declared runtime/period budgets fits within available CPU capacity; otherwise it rejects the request instead of silently missing deadlines.
Q5: What happens to the system if a priority-99 FIFO thread enters an infinite loop?
A: By default, RT throttling caps real-time execution (typically 950 ms per second), leaving about 5% for normal threads – enough to log in and kill the offender. With throttling disabled, that CPU is effectively lost.
FAQ
Is SCHED_OTHER the same as SCHED_NORMAL?
Yes. User-space headers call it SCHED_OTHER; kernel source calls it SCHED_NORMAL. Same policy, value 0.
Does a higher nice number mean higher priority?
No – the opposite. Nice +19 is the most “polite” (lowest weight); nice −20 is the most demanding.
Do these policies still apply on kernels using EEVDF?
Yes. EEVDF (kernel 6.6+) replaced the internal algorithm of the fair class, but the policies, their semantics, and both priority scales are unchanged.
Which policy should an embedded control loop use?
If the work is periodic with a hard budget, SCHED_DEADLINE is the modern answer. For short event-driven critical sections, SCHED_FIFO at a moderate priority is common.
Is this content part of a paid course?
No – this is part of the free Linux kernel development course at EmbeddedPathashala, which also includes a free Linux device drivers course and a free embedded systems course.
Key Takeaways
- Linux implements the three POSIX policies plus BATCH, IDLE, and DEADLINE.
- Nice (−20…+19) shapes fair-share proportions; RT priority (1…99) is a strict rank.
- Any real-time thread outranks every fair-policy thread; deadline threads outrank everyone.
- FIFO and RR differ only in time slicing among equal priorities.
- RT throttling reserves a small CPU share so a runaway real-time thread cannot freeze the machine.
Next in the Free Linux Kernel Development Course
Lesson 3 opens the hood: modular scheduling classes and the modern EEVDF fair scheduler that replaced CFS.

2 Comments