Tag: Linux Scheduling

  • Scheduling in Linux | Master How Linux Decides What Runs Next (2026)

    Scheduling in Linux explains how the kernel decides which process or thread runs on the CPU, when it runs, and for how long

    If you have ever wondered how Linux decides which program runs right now and which one waits, you are already thinking about Scheduling in Linux.

    It is one of those topics that sounds complicated at first, but once you understand the basics, everything suddenly clicks. And honestly, Linux scheduling is one of the reasons Linux feels fast, responsive, and reliable, even when many things are happening at the same time.

    So grab a coffee, relax, and let us walk through scheduling in Linux like two engineers chatting at a desk, not like a textbook shouting definitions at you.

    What Is Scheduling in Linux ?

    At its core, Scheduling in Linux is about time sharing.

    Your CPU can execute only one instruction per core at a time. But Linux runs hundreds or even thousands of tasks together. So the kernel acts like a smart traffic controller. It decides:

    • Which process should run now
    • Which process should wait
    • How long each process can run
    • When to switch to another task

    This decision-making system is called the Linux scheduler.

    Without scheduling, your system would freeze the moment two programs tried to run together.

    Why Scheduling Matters More Than You Think

    You may not notice scheduling directly, but you feel it every day:

    • Smooth UI while compiling code
    • Music continues while downloading files
    • Server handles thousands of requests
    • Embedded systems meet real-time deadlines

    All of this depends on how efficiently Linux manages scheduling under many-core systems.

    Bad scheduling means lag, audio glitches, missed deadlines, or system hangs. Good scheduling means Linux quietly does its job in the background.

    Processes, Threads, and Tasks: Clearing the Confusion

    Before going deeper, let us clear one important thing.

    In Linux scheduling terms:

    • Process: A program in execution
    • Thread: A lightweight execution unit inside a process
    • Task: Linux treats both processes and threads as tasks

    So when we talk about scheduling in Linux, we are really talking about task scheduling.

    Exploring Various Scheduling Aspects & Policies in Linux

    Linux does not use a single scheduling strategy for everything. That would be inefficient.

    Instead, Linux provides multiple scheduling policies, each designed for a specific type of workload.

    Let us explore them one by one.

    Scheduling Classes in Linux

    Linux organizes scheduling using scheduling classes. Each class has its own rules.

    From highest priority to lowest:

    1. Stop Scheduler
    2. Real-Time Scheduler
    3. Completely Fair Scheduler (CFS)
    4. Idle Scheduler

    Most users interact mainly with CFS, but real-time scheduling is extremely important in embedded and automotive systems.

    Completely Fair Scheduler (CFS): The Default Scheduler

    The Completely Fair Scheduler is the default scheduler for normal Linux processes.

    Its goal is simple:

    Give every runnable task a fair share of CPU time.

    Instead of fixed time slices, CFS uses virtual runtime.

    What Is Virtual Runtime?

    Think of virtual runtime as a stopwatch for each task.

    • If a task runs more, its virtual runtime increases
    • Tasks with lower virtual runtime get priority
    • The scheduler always picks the task that has run the least

    This makes scheduling in Linux feel fair and responsive.

    Why CFS Feels Smooth

    CFS avoids long waiting times. Interactive tasks like terminals and browsers stay responsive because they often sleep and wake quickly, keeping their virtual runtime low.

    That is why Linux desktops feel snappy even under load.

    Nice Value and Priority in Linux Scheduling

    You may have heard about nice values.

    Nice values influence how much CPU time a task gets.

    • Range: -20 (highest priority) to +19 (lowest priority)
    • Default nice value: 0

    Lower nice value means:

    • Task runs more often
    • Lower virtual runtime growth

    This directly affects scheduling behavior.

    Real-Time Scheduling in Linux

    Now let us move to the serious side of scheduling.

    Real-time scheduling is used when timing matters more than fairness.

    Linux provides two main real-time policies:

    • SCHED_FIFO
    • SCHED_RR

    SCHED_FIFO (First In, First Out)

    This is the simplest real-time policy.

    • Highest priority task runs first
    • It keeps running until:
      • It blocks
      • It yields
      • A higher priority task arrives

    There is no time slicing here.

    This policy is dangerous if misused, but powerful when used correctly.

    SCHED_RR (Round Robin)

    SCHED_RR is similar to FIFO but with time slicing.

    • Tasks of equal priority take turns
    • Each task runs for a fixed time quantum
    • After that, it moves to the back of the queue

    This is safer than FIFO for many real-time systems.

    Why Real-Time Scheduling Exists

    Real-time scheduling is essential for:

    • Audio processing
    • Automotive systems
    • Industrial control
    • Robotics
    • Medical devices

    In these cases, missing a deadline is worse than being slow.

    Scheduling in Linux on Many-Core Systems

    Modern CPUs have many cores. Some servers have dozens.

    So how does Linux handle scheduling under many-core systems?

    This is where Linux truly shines.

    Per-CPU Run Queues

    Each CPU core has its own run queue.

    This avoids bottlenecks and improves scalability.

    Tasks are usually scheduled on the same CPU where they last ran. This improves cache performance.

    Load Balancing

    Linux periodically checks if some CPUs are overloaded while others are idle.

    If imbalance is detected:

    • Tasks are migrated
    • Load is redistributed

    This is how Linux manages scheduling efficiently across many cores.

    CPU Affinity and Schedulin

    Linux allows binding tasks to specific CPUs.

    This is called CPU affinity.

    Why would you do this?

    • Improve cache locality
    • Avoid unnecessary migrations
    • Meet real-time constraints

    In embedded and performance-critical systems, CPU affinity plays a huge role in scheduling behavior.

    Preemption and Scheduling Latency

    Preemption means interrupting a running task to run another one.

    Linux supports different levels of preemption:

    • Non-preemptible kernel
    • Voluntary preemption
    • Full preemption
    • Real-time preemption (PREEMPT_RT)

    More preemption means:

    • Lower latency
    • Better real-time performance
    • Slightly higher overhead

    Choosing the right model is crucial for real-time workloads.

    Scheduler Tick and Tickless Kernel

    Older Linux kernels used periodic timer ticks.

    Modern kernels support tickless scheduling.

    This means:

    • CPU sleeps when idle
    • Better power efficiency
    • Fewer interruptions

    This improvement plays a silent but important role in modern scheduling in Linux.

    How Context Switching Fits into Scheduling

    Every time Linux switches from one task to another, a context switch happens.

    This involves:

    • Saving registers
    • Loading new task state
    • Switching memory context

    Context switches are expensive.

    Good scheduling tries to:

    • Minimize unnecessary switches
    • Keep tasks on the same CPU
    • Improve cache usage

    Scheduling Groups and Cgroups

    Linux allows grouping tasks using control groups (cgroups).

    With cgroups, you can:

    • Limit CPU usage
    • Prioritize certain workloads
    • Isolate services

    This is heavily used in containers and cloud systems.

    Scheduling in Linux becomes even more powerful when combined with cgroups.

    How Scheduling Affects Embedded Linux Systems

    In embedded systems, scheduling is not just about fairness.

    It is about:

    • Determinism
    • Latency
    • Predictability

    Real-time scheduling, CPU isolation, and preemption models are commonly used to ensure deadlines are met.

    This is why understanding scheduling in Linux is critical for embedded developers.

    Common Scheduling Mistakes Beginners Make

    Let us talk honestly for a moment.

    Here are mistakes many beginners make:

    • Using real-time policies without understanding risks
    • Setting very high priorities everywhere
    • Ignoring CPU affinity
    • Blaming Linux when poor scheduling design causes issues

    Scheduling is powerful, but it must be used carefully.

    How to Observe Scheduling Behavior

    You can learn a lot just by observing:

    • top
    • htop
    • ps
    • /proc/schedstat
    • perf

    These tools show how Linux scheduling decisions affect real workloads.

    Why Linux Scheduling Scales So Well

    Linux scheduling is battle-tested.

    It runs:

    • Phones
    • Cars
    • Supercomputers
    • Cloud servers
    • Embedded boards

    The same core scheduling design adapts to all these environments.

    That is why Linux is trusted everywhere.

    Scheduling in Linux for Interviews

    If you are preparing for interviews, focus on:

    • Difference between CFS and real-time scheduling
    • Virtual runtime concept
    • Nice values and priorities
    • FIFO vs RR
    • Scheduling on multi-core systems

    Understanding concepts matters more than memorizing definitions.

    Final Thoughts: Why Scheduling in Linux Is Worth Learning

    Scheduling in Linux is not just a kernel topic.

    It is a mindset.

    It teaches you:

    • Fairness vs priority
    • Latency vs throughput
    • Simplicity vs control

    Once you understand scheduling, many performance issues suddenly make sense.

    Linux Scheduling Interview Questions & Answers

    Round 1: Basic / Screening Round (Foundations Check)

    1. What is scheduling in Linux?

    Scheduling in Linux is the mechanism the kernel uses to decide which process or thread gets CPU time and when. Since multiple tasks run at the same time, scheduling ensures fair and efficient CPU usage.

    2. Why is scheduling needed in an operating system?

    Because the CPU can run only one task per core at a time. Scheduling allows multiple programs to share the CPU without freezing the system.

    3. What is a process and how is it related to scheduling?

    A process is a program in execution. The Linux scheduler decides when each process or thread should run on the CPU.

    4. Which scheduler is used by default in Linux?

    Linux uses the Completely Fair Scheduler (CFS) for normal processes.

    5. What does “fair” mean in Completely Fair Scheduler?

    Fair means every runnable task gets a fair share of CPU time based on how much it has already used, not equal time slices.

    6. What is a nice value?

    Nice value controls the priority of a process. Lower nice value means higher priority and more CPU time.

    7. What is the nice value range in Linux?

    The range is from -20 (highest priority) to +19 (lowest priority).

    8. What happens when multiple processes want the CPU at the same time?

    The scheduler switches between them using context switching so that each process gets CPU time.

    9. What is context switching?

    Context switching is the process of saving the state of one task and loading the state of another task when the CPU switches between them.

    10. Is scheduling done at user level or kernel level?

    Scheduling is done entirely in the kernel.

    Round 2: Technical / Core Linux Round (Deep Understanding)

    1. How does the Completely Fair Scheduler decide which task runs next?

    CFS tracks a value called virtual runtime. The task with the lowest virtual runtime is selected to run next because it has used the least CPU time.

    2. What is virtual runtime in Linux scheduling?

    Virtual runtime is a weighted measure of how much CPU time a task has consumed. Tasks that run more accumulate higher virtual runtime.

    3. What are scheduling policies available in Linux?

    Common policies include:

    • SCHED_OTHER (CFS)
    • SCHED_FIFO
    • SCHED_RR
    • SCHED_IDLE

    4. What is the difference between SCHED_FIFO and SCHED_RR?

    SCHED_FIFO runs tasks until they block or yield.
    SCHED_RR adds time slicing so tasks of equal priority share CPU in a round-robin manner.

    5. Why can real-time scheduling be risky if misused?

    Because real-time tasks can starve normal tasks and even freeze the system if they never block or yield.

    6. How does Linux handle scheduling on multi-core systems?

    Each CPU core has its own run queue. Linux balances the load by migrating tasks between cores when required.

    7. What is CPU affinity?

    CPU affinity binds a process to a specific CPU core, preventing it from running on other cores.

    8. Why is CPU affinity useful?

    It improves cache usage, reduces task migration overhead, and helps meet real-time timing requirements.

    9. What is preemption in Linux scheduling?

    Preemption allows the kernel to interrupt a running task to schedule a higher-priority task.

    10. How does preemption affect system latency?

    More preemption reduces latency but slightly increases scheduling overhead.

    11. What role do cgroups play in scheduling?

    Cgroups allow grouping processes and controlling CPU usage, priority, and isolation.

    12. How does scheduling impact embedded Linux systems?

    In embedded systems, scheduling affects determinism, latency, and deadline handling, especially in real-time applications.

    13. How can you observe scheduling behavior in a running Linux system?

    Using tools like top, htop, ps, perf, and /proc scheduler statistics.

    14. What is scheduler latency?

    Scheduler latency is the time a task waits before it gets CPU after becoming runnable.

    15. Why is Linux scheduling considered scalable?

    Because it uses per-CPU run queues, load balancing, and efficient algorithms that scale well across many-core systems.

    Interview Tip

    Interviewers are not looking for fancy words.
    They want to see that you:

    • Understand fairness vs priority
    • Know when real-time scheduling is needed
    • Can explain scheduling in simple terms

    If you explain calmly and clearly, you are already ahead of most candidates.

    Frequently Asked Questions (FAQ) on Scheduling in Linux

    1. What does scheduling mean in Linux in simple terms?

    Scheduling in Linux is how the operating system decides which program or task gets to use the CPU at any given moment. Since many programs run at the same time, Linux constantly switches between them to keep everything working smoothly.

    2. Why is scheduling important in Linux systems?

    Without proper scheduling, your system would freeze or feel extremely slow. Scheduling makes sure important tasks get CPU time on time while background tasks wait politely, keeping the system responsive.

    3. Which scheduler does Linux use by default?

    Linux uses the Completely Fair Scheduler (CFS) for normal processes. It focuses on fairness by ensuring every task gets its share of CPU time based on how much it has already used.

    4. What is the difference between normal scheduling and real-time scheduling in Linux?

    Normal scheduling focuses on fairness, while real-time scheduling focuses on deadlines. Real-time tasks must run immediately when needed, even if other tasks have to wait.

    5. What are SCHED_FIFO and SCHED_RR in Linux scheduling?

    These are real-time scheduling policies.
    SCHED_FIFO runs tasks in priority order without time slicing, while SCHED_RR gives equal-priority tasks a fixed time slice in a round-robin fashion.

    6. What is a nice value and how does it affect scheduling?

    A nice value controls how “polite” a process is. Lower nice values give higher priority, meaning the task gets more CPU time compared to others.

    7. How does Linux handle scheduling on multi-core processors?

    Linux uses per-CPU run queues and load balancing. Each core schedules tasks independently, and the kernel moves tasks between cores to keep the workload balanced.

    8. What is virtual runtime in the Linux scheduler?

    Virtual runtime is a value used by CFS to track how much CPU time a task has received. Tasks with lower virtual runtime are scheduled first to maintain fairness.

    9. Can I control which CPU core a process runs on?

    Yes. Linux supports CPU affinity, allowing you to bind a task to specific CPU cores. This is useful for performance tuning and real-time systems.

    10. Is Linux scheduling suitable for real-time and embedded systems?

    Yes. Linux supports real-time scheduling policies and preemption models, making it suitable for embedded, automotive, and industrial systems when configured properly.

    11. What problems can occur due to poor scheduling configuration?

    Poor scheduling can cause high latency, missed deadlines, system lag, or even system hangs, especially when real-time priorities are misused.

    12. Do I need deep kernel knowledge to understand Linux scheduling?

    Not at all. Basic understanding of processes, priorities, and scheduling policies is enough to work effectively with Linux scheduling in most real-world scenarios.

    Read More about Process : What is is Process

    Read More about System Call in Linux : What is System call

    Read More about IPC : What is IPC

  • Master How Does the Linux Process Scheduler Work? (2026)

    Are you curious about how Linux manages multiple programs running simultaneously? If you’ve ever wondered how your system decides which process gets the CPU at a given time, you’re about to discover the fascinating world of the Linux Process Scheduler. In this article, we’ll break it down step by step, explain its importance, and help you understand how Linux keeps everything running smoothly.

    What is a Linux Process Scheduler?

    The Linux Process Scheduler is the component of the Linux kernel responsible for deciding which process runs at any given moment. Think of it as a traffic controller for your CPU — it ensures that every process gets a fair share of processing power and that critical tasks are prioritized.

    Every program or task in Linux is represented as a process, and since CPUs can only execute one instruction at a time per core, the scheduler plays a crucial role in multitasking. Without it, your system could become slow, unresponsive, or chaotic.

    Key Functions of the Linux Process Scheduler

    The Linux scheduler has several important functions:

    1. Process Prioritization: Determines which process should run first based on priority levels.
    2. Time Slicing: Allocates a specific time slot to each process to ensure fair CPU usage.
    3. Load Balancing: Distributes processes across multiple CPU cores for efficiency.
    4. Preemption: Interrupts lower-priority tasks to execute higher-priority tasks immediately.
    5. Fairness: Ensures that no process starves and every process gets CPU time.

    Types of Linux Process Schedulers

    Linux supports different scheduling algorithms to meet varying system needs. Here are the main types:

    1. Completely Fair Scheduler (CFS)

    • Default scheduler for Linux since kernel 2.6.23.
    • Focuses on fair distribution of CPU time to all processes.
    • Uses virtual runtime to track and prioritize tasks.

    2. Real-Time Scheduler

    • Handles time-sensitive tasks with strict deadlines.
    • Supports policies like SCHED_FIFO (first-in-first-out) and SCHED_RR (round-robin).
    • Essential for embedded systems, robotics, and real-time applications.

    3. Deadline Scheduler

    • Ensures tasks meet specific timing constraints.
    • Primarily used in high-performance and real-time environments.

    How Does Scheduling Affect System Performance?

    The efficiency of the Linux scheduler directly impacts:

    • System responsiveness: Faster response for interactive applications.
    • CPU utilization: Ensures no core remains idle unnecessarily.
    • Application performance: Critical processes get prioritized without starving others.

    By optimizing scheduling policies, Linux can provide both high performance and fairness, balancing user experience and system efficiency.

    Here’s a simple C++ example:

    #include <iostream>
    #include <thread>
    #include <chrono>
    #include <vector>
    #include <mutex>
    #include <unistd.h>
    #include <pthread.h>
    
    std::mutex coutMutex;
    
    // Function to simulate a CPU-bound task
    void cpuTask(int id, int priority) {
        // Set thread priority (works on Linux)
        sched_param sch;
        sch.sched_priority = priority;
        if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &sch)) {
            std::lock_guard<std::mutex> lock(coutMutex);
            std::cout << "Failed to set thread priority for thread " << id << "\n";
        }
    
        for(int i = 0; i < 5; ++i) {
            std::lock_guard<std::mutex> lock(coutMutex);
            std::cout << "Thread " << id << " running iteration " << i+1 << "\n";
            std::this_thread::sleep_for(std::chrono::milliseconds(500)); // Simulate work
        }
    }
    
    int main() {
        std::vector<std::thread> threads;
    
        // Create threads with different priorities
        threads.emplace_back(cpuTask, 1, 80); // High priority
        threads.emplace_back(cpuTask, 2, 50); // Medium priority
        threads.emplace_back(cpuTask, 3, 20); // Low priority
    
        // Join threads
        for(auto &t : threads) {
            t.join();
        }
    
        std::cout << "All threads completed!" << std::endl;
        return 0;
    }
    

    Key Concepts Explained by This Code:

    1. Threads simulate processes: In Linux, threads are scheduled like processes by the kernel.
    2. Setting thread priority:
      • SCHED_FIFO is a real-time scheduling policy (first-in-first-out).
      • Priority affects which thread gets CPU time first.
    3. Fair CPU distribution: Even threads with lower priority eventually get CPU time.
    4. Time slicing simulation: sleep_for() shows how CPU time is shared among threads.

    How to Run:

    1. Save the file as scheduler_demo.cpp.
    2. Compile using g++: g++ -pthread scheduler_demo.cpp -o scheduler_demo
    3. Run with sudo (required for setting real-time priorities): sudo ./scheduler_demo

    Now we break down the C++ code I shared and explain what it does, step by step, in the context of Linux Process Scheduling :

    Header Files

    #include <iostream>
    #include <thread>
    #include <chrono>
    #include <vector>
    #include <mutex>
    #include <unistd.h>
    #include <pthread.h>
    
    • iostream → For printing output to console.
    • thread → For creating and managing threads (simulating processes).
    • chrono → For controlling time delays (sleep_for simulates CPU work).
    • vector → To store multiple threads.
    • mutex → To safely print from multiple threads without garbled output.
    • unistd.h and pthread.h → For POSIX thread scheduling and priority manipulation.

    Mutex for Safe Printing

    std::mutex coutMutex;
    
    • Since multiple threads run simultaneously, printing directly can overlap.
    • coutMutex ensures one thread prints at a time, making output readable.

    CPU-Bound Task Function

    void cpuTask(int id, int priority) {
        sched_param sch;
        sch.sched_priority = priority;
        if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &sch)) {
            std::lock_guard<std::mutex> lock(coutMutex);
            std::cout << "Failed to set thread priority for thread " << id << "\n";
        }
    
        for(int i = 0; i < 5; ++i) {
            std::lock_guard<std::mutex> lock(coutMutex);
            std::cout << "Thread " << id << " running iteration " << i+1 << "\n";
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    }
    

    What happens here:

    1. Set thread priority:
      • sched_param sch sets the thread priority.
      • pthread_setschedparam assigns it using SCHED_FIFO (first-in-first-out real-time policy).
      • Higher numbers → higher priority.
    2. Simulate CPU work:
      • A for loop runs 5 iterations.
      • Each iteration prints which thread is running.
      • sleep_for(500ms) simulates some CPU time being consumed.
    3. Safe printing:
      • lock_guard<std::mutex> ensures threads print one by one, preventing mixed output.

    Scheduler concept illustrated:

    • Threads with higher priority (like 80) are favored by the Linux scheduler.
    • Lower priority threads (like 20) may get CPU later, but all threads eventually run, showing fairness.

    Main Function

    int main() {
        std::vector<std::thread> threads;
    
        // Create threads with different priorities
        threads.emplace_back(cpuTask, 1, 80); // High priority
        threads.emplace_back(cpuTask, 2, 50); // Medium priority
        threads.emplace_back(cpuTask, 3, 20); // Low priority
    
        // Join threads
        for(auto &t : threads) {
            t.join();
        }
    
        std::cout << "All threads completed!" << std::endl;
        return 0;
    }
    

    Step-by-step:

    1. Create threads with priorities:
      • Thread 1 → High priority (80)
      • Thread 2 → Medium priority (50)
      • Thread 3 → Low priority (20)
    2. Join threads:
      • t.join() ensures the main program waits until all threads finish.
    3. Final output:
      • After all threads complete their iterations, the program prints: "All threads completed!"

    Linux Scheduler Demonstration:

    • High priority threads will often run first.
    • Medium and low priority threads get CPU in between based on the scheduling policy.
    • You can see time-sharing and fairness in action.

    How user-space threads “tell” the CPU to run first and what actually happens in Linux.

    User Space Can Only Request Priority

    In our C++ code:

    pthread_setschedparam(pthread_self(), SCHED_FIFO, &sch);
    
    • This requests the kernel to schedule this thread with a given policy and priority.
    • It does not guarantee the CPU will run this thread first.
    • The kernel’s scheduler still decides when and for how long each thread gets CPU time.

    Think of it like: raising your hand in class — you’re asking for attention, but the teacher decides who speaks first.

    How Linux Scheduler Handles It

    When a thread requests a scheduling policy/priority:

    1. The kernel checks the requested policy and priority.
      • Example: SCHED_FIFO threads with higher priority are favored.
      • Example: SCHED_RR threads get CPU in a round-robin fashion among same-priority threads.
    2. The scheduler decides which thread runs next based on:
      • Thread priority
      • Current CPU load
      • Fairness (in CFS, lower virtual runtime threads run first)
      • Core affinity (which CPU cores are available)
    3. The CPU switches to the selected thread preemptively if needed.
      • Higher-priority threads can interrupt lower-priority ones.

    Why Our Code “Feels” Like High-Priority Runs First

    • Thread 1 has priority 80 (high), Thread 2 has 50 (medium), Thread 3 has 20 (low).
    • When these threads are ready, the kernel usually schedules the higher-priority thread first.
    • But the kernel still decides, so timing is not guaranteed.

    Note: On Linux, changing real-time priorities usually requires sudo because user-space cannot normally run high-priority real-time threads without permission.

    Linux Process Creation and Scheduling Flow

    Process Creation (User Request → Kernel)

    1. You type a command like: ./myprogram in the shell.
    2. The shell calls fork() system call → creates a child process (a duplicate of itself).
      • Inside the kernel, a new task_struct is allocated for the process.
      • task_struct contains process details: PID, scheduling policy, priority, state, etc.
    3. The child process then calls execve() → replaces its memory with the new program (myprogram).
      • Loads program code from disk into memory.
      • Initializes stack, heap, registers.
      • Process is now READY to run.

    Process States in the Kernel

    A process can be in these states:

    • NEW → Just created (fork() called).
    • READY → Waiting in the runqueue for CPU time.
    • RUNNING → Actively executing instructions on a CPU core.
    • WAITING / SLEEPING → Waiting for I/O (like reading a file).
    • TERMINATED → Finished execution.

    The scheduler moves processes between these states.

    Scheduler Flow (How CPU Picks a Process)

    Linux uses CFS (Completely Fair Scheduler) by default for normal tasks.

    High-level flow:

    1. Runqueue:
      Each CPU core has a runqueue (a list of runnable processes).
    2. Pick Next Task:
      Scheduler picks the process with the lowest virtual runtime (vruntime) → meaning the one that has had the least CPU time recently.
    3. Context Switch:
      • Scheduler saves the current process’s state (registers, stack pointer, program counter).
      • Loads the next process’s state.
      • CPU starts executing the new process.
    4. Time Slice / Preemption:
      • Each process gets a fair time slice (based on priority/niceness).
      • If time slice expires, the scheduler may preempt it and pick another process.

    Special Scheduling Classes

    Linux supports multiple schedulers depending on policy:

    • CFS (SCHED_NORMAL) → Default fair scheduler.
    • Real-Time (SCHED_FIFO, SCHED_RR) → For real-time tasks, strictly priority-based.
    • Deadline Scheduler (SCHED_DEADLINE) → For tasks with deadlines.

    Detailed Response Flow (Step by Step)

    Here’s the entire flow from process creation to CPU execution:

    1. User runs program → shell calls fork() → kernel creates new task_struct.
    2. Kernel assigns PID → adds process to runqueue of a CPU.
    3. Scheduler invoked (either periodically via timer interrupt or when a process yields).
    4. Kernel picks next process based on scheduling policy:
      • For CFS: choose lowest vruntime.
      • For RT: choose highest-priority RT task.
    5. Context switch occurs: save current process state, load new process state.
    6. CPU executes instructions of chosen process.
    7. Interrupts & I/O requests may move process back to waiting state.
    8. When I/O completes → kernel wakes process → adds back to runqueue.
    9. Steps 3–8 repeat until process calls exit().
    10. Kernel cleans up process resources (memory, file descriptors, task_struct).

    Visualizing

    [User runs program] 
           ↓
     fork() + execve()
           ↓
     [Kernel creates task_struct] 
           ↓
     Process added to Runqueue (READY state)
           ↓
    [Scheduler picks next process]
           ↓
     Context Switch → Load process state
           ↓
     CPU executes process (RUNNING)
           ↓
     ┌─────────────────────────────────────┐
     |   If timeslice expires → back to READY   |
     |   If I/O requested → go to WAITING       |
     |   If finished → go to TERMINATED         |
     └─────────────────────────────────────┘
           ↓
    Repeat for all runnable processes
    

    Scheduling flow through code

    User-Space Simulation of Scheduling (C++ Example)

    This is not the real scheduler, but it helps you “see” the flow:

    #include <iostream>
    #include <queue>
    #include <thread>
    #include <chrono>
    
    struct Process {
        int pid;
        int burstTime;
        int remainingTime;
    };
    
    // Simple round-robin scheduler simulation
    void roundRobinScheduler(std::queue<Process> &readyQueue, int timeSlice) {
        while (!readyQueue.empty()) {
            Process current = readyQueue.front();
            readyQueue.pop();
    
            std::cout << "Running process PID " << current.pid << " for ";
            int runTime = std::min(timeSlice, current.remainingTime);
            std::cout << runTime << " ms\n";
    
            std::this_thread::sleep_for(std::chrono::milliseconds(runTime));
            current.remainingTime -= runTime;
    
            if (current.remainingTime > 0) {
                std::cout << "Process PID " << current.pid 
                          << " back to READY queue with " 
                          << current.remainingTime << " ms left\n";
                readyQueue.push(current); // back to queue
            } else {
                std::cout << "Process PID " << current.pid << " finished execution!\n";
            }
        }
    }
    
    int main() {
        std::queue<Process> readyQueue;
    
        // Create 3 processes with different burst times
        readyQueue.push({1, 10, 10});
        readyQueue.push({2, 5, 5});
        readyQueue.push({3, 7, 7});
    
        int timeSlice = 3; // each process gets 3 ms CPU time
        roundRobinScheduler(readyQueue, timeSlice);
    
        std::cout << "All processes completed!\n";
        return 0;
    }
    

    What this shows:

    • readyQueue → simulates the kernel’s runqueue.
    • roundRobinScheduler → picks processes in FIFO order, runs them for a time slice, then puts them back if not finished.
    • Shows transitions: READY → RUNNING → (READY or TERMINATED).
    • Output will look like how the kernel “time-slices” processes.

    Kernel-Level Pseudo-Code (Real Flow in Linux)

    Inside Linux kernel (kernel/sched/core.c), the scheduling flow looks like this (simplified):

    // Called whenever scheduler needs to pick next process
    schedule() {
        struct task_struct *prev, *next;
    
        prev = current; // process currently running
        put_prev_task(prev); // save its state
    
        // Pick the next task from runqueue
        next = pick_next_task(rq);
    
        if (next != prev) {
            context_switch(prev, next);
        }
    }
    

    And the CFS Scheduler (pick_next_task) looks like:

    pick_next_task(struct rq *rq) {
        // CFS stores tasks in a red-black tree ordered by vruntime
        // vruntime = "virtual runtime", tracks how much CPU each task used
        struct sched_entity *se = leftmost_entity(rq->cfs.rb_root);
        return task_of(se); // process with least CPU time
    }
    

    What this shows:

    • schedule() is the heart of Linux scheduling.
    • The runqueue (rq) holds all runnable tasks.
    • pick_next_task() → chooses the process with lowest vruntime (fair scheduling).
    • context_switch() → performs the actual switch: save old process state, load new one.

    Flow with Code Context

    1. Process created (fork() + execve()) → kernel makes a task_struct.
    2. Added to runqueue (enqueue_task).
    3. Timer interrupt or event calls schedule().
    4. pick_next_task() chooses process (CFS or RT).
    5. context_switch() → CPU starts executing new process.
    6. When timeslice ends or process blocks → back to READY state.

    Mapping C++ Simulation ↔ Linux Kernel Scheduler

    Process Creation

    C++ Simulation:

    readyQueue.push({1, 10, 10});
    
    • You manually create processes (PID, burst time).

    Linux Kernel:

    fork() + execve()
    
    • Kernel creates a new task_struct.
    • Loads program into memory.
    • Adds it to CPU’s runqueue.

    Ready Queue

    C++ Simulation:

    std::queue<Process> readyQueue;
    
    • A simple FIFO queue for processes waiting for CPU.

    Linux Kernel:

    struct rq {
        struct cfs_rq cfs; // Red-black tree of tasks (CFS)
    };
    
    • Each CPU has a runqueue (rq).
    • Tasks stored in red-black tree, sorted by vruntime (fairness).

    Scheduler Decision

    C++ Simulation:

    Process current = readyQueue.front();
    readyQueue.pop();
    
    • Picks the first process in queue.

    Linux Kernel:

    next = pick_next_task(rq);
    
    • Picks task with smallest vruntime (least CPU so far).
    • Ensures fairness.

    Process Execution

    C++ Simulation:

    int runTime = std::min(timeSlice, current.remainingTime);
    std::this_thread::sleep_for(std::chrono::milliseconds(runTime));
    
    • Simulates the process “running” for a time slice.

    Linux Kernel:

    context_switch(prev, next);
    
    • Saves current process registers, stack, PC.
    • Loads next process’s state.
    • CPU runs the new process until time slice expires or it blocks.

    Returning to Ready Queue

    C++ Simulation:

    if (current.remainingTime > 0) {
        readyQueue.push(current);
    }
    
    • If process not finished → back to queue.

    Linux Kernel:

    enqueue_task(rq, task);
    
    • If process not finished → put back in runqueue with updated vruntime.

    Process Exit

    C++ Simulation:

    std::cout << "Process PID " << current.pid << " finished execution!\n";
    
    • Prints when process completes.

    Linux Kernel:

    do_exit();
    release_task();
    
    • Kernel cleans up memory, closes files, removes task_struct.

    Visual Diagram

    User Program (C++ Simulation)          Linux Kernel Scheduler (Real)
    
      Create process manually                fork() + execve()
            │                                       │
       Push into readyQueue                enqueue_task(runqueue)
            │                                       │
      Pop process from queue                pick_next_task()
            │                                       │
     Simulate run (sleep_for)   ←──────→    context_switch()
            │                                       │
     If not finished → push back          enqueue_task(rq, task)
     If finished → print done             do_exit(), cleanup
    

    FAQs About Linux Process Scheduler

    1.What is the Linux Process Scheduler?

    Ans: The Linux Process Scheduler is a kernel component responsible for deciding which process runs on the CPU and when. It manages CPU time fairly among processes, supports multitasking, and ensures real-time tasks get priority when needed.

    2.How does the Linux scheduler work?

    Ans: The Linux scheduler works by:
    Placing processes into run queues.
    Choosing the highest priority process (based on policy like CFS, FIFO, or RR).
    Assigning CPU time to that process.
    Performing context switching when another process needs to run.
    This ensures fairness, efficiency, and responsiveness.

    3.What are the types of Linux scheduling policies?

    Ans: Linux supports multiple scheduling policies:
    CFS (Completely Fair Scheduler) → Default, balances CPU fairly among tasks.
    SCHED_FIFO → Real-time, runs highest-priority task until it blocks or finishes.
    SCHED_RR → Real-time, round-robin scheduling among tasks with the same priority.
    SCHED_DEADLINE → For time-critical tasks with deadlines.

    4.How does Linux create and schedule a process?

    Ans: The flow is:
    User calls fork() or clone() → creates a new process.
    Kernel assigns a PID and creates a task_struct for the new process.
    Process is placed in the ready queue.
    Scheduler picks the next process based on priority and policy.
    CPU executes that process.

    5.What is task_struct in Linux scheduling?

    Ans: task_struct is the kernel’s internal data structure that represents each process.
    It contains details like:
    PID (Process ID)
    Scheduling policy (CFS, FIFO, etc.)
    Priority
    CPU registers
    Memory info
    The scheduler uses this structure to make decisions.

    6.What is context switching in Linux?

    Ans: Context switching happens when the scheduler pauses one process and starts another.
    The kernel saves the state (CPU registers, stack, program counter) of the current process and loads the state of the next one. This allows multitasking without processes interfering.

    7.How does Linux scheduler handle real-time tasks?

    Ans: Real-time tasks use SCHED_FIFO or SCHED_RR.
    They always run before normal CFS tasks if ready.
    Highest-priority real-time process gets CPU time until it blocks or finishes.
    This ensures deterministic response for critical applications like audio/video processing or robotics.

    8.Can I control process scheduling from user space?

    Ans: Yes You can influence scheduling from user space using system calls like:
    sched_setscheduler() → set scheduling policy.
    nice() → adjust process priority (for normal tasks).
    chrt command → change real-time priorities.
    However, full control is only possible in kernel space.

    9.What is the difference between CFS and Real-time scheduling?

    Ans: CFS (Completely Fair Scheduler) → Tries to share CPU time fairly among all tasks.
    Real-time (FIFO/RR) → Always prioritizes the most important tasks, fairness is secondary.

    10.Why is Linux scheduler important?

    Ans: The Linux scheduler is important because it ensures:
    Efficient CPU utilization
    Fairness among processes
    Responsiveness for real-time apps
    Smooth multitasking
    Without it, processes would starve or the system would freeze under load.