The Story That Explains Schedulers & PCB
The hospital uses three levels of decision-makers: the reception (admits new patients), the triage nurse (decides the next patient the doctor sees), and the ward manager (temporarily moves stable patients out to make room).
Each patient also has a file at the foot of the bed — name, age, medicines given, current vitals, doctor assigned. Without that file, a shift-change would be chaos.
In an operating system, the three decision-makers are the three types of schedulers, and the file at the foot of the bed is the Process Control Block (PCB).
A modern computer runs hundreds of processes but has only a few CPU cores. The operating system must decide which process runs, when, and for how long. It also needs a place to remember everything about every process the moment it is paused. Galvin's textbook calls these two ideas the heart of process management.
Schedulers answer "which process runs next?". The Process Control Block answers "how do we remember exactly where a paused process was?". Together they make multitasking possible on a single CPU.
Foundation — Process States (Quick Recap)
Before understanding schedulers, you need to know the five states a process moves through during its lifetime. Schedulers move processes between these states.
Animated Process State Diagram
The glowing token is process P1. Watch it get admitted (NEW → READY), dispatched (→ RUNNING), interrupted, blocked on I/O, resumed, then terminated. The current state pulses gold.
Process Control Block (PCB) — What & Why
Every process in the system is represented by a Process Control Block, also called a Task Control Block. Galvin describes it as the data structure that fully identifies a process. When the OS pauses process A to run process B, it saves the entire "state" of A into A's PCB and loads B's state from B's PCB.
A PCB is a per-process record kept by the kernel that stores everything needed to pause a process now and resume it later exactly where it left off — as if it never stopped.
Why the PCB Matters
fork()).
Fields Inside a PCB
Galvin lists the following fields as the minimum information every PCB must carry. Real OSes (Linux task_struct, Windows EPROCESS) extend this significantly.
| Field | Purpose | Example Value |
|---|---|---|
| Process ID (PID) | Unique integer identifier | 1247 |
| Process State | NEW, READY, RUNNING, WAITING, TERMINATED | READY |
| Program Counter | Next instruction address | 0x7F3A2C10 |
| CPU Registers | All general-purpose & index registers | RAX, RBX, RCX... |
| CPU Scheduling Info | Priority, pointers to scheduling queues, scheduling policy | priority=15 |
| Memory Management Info | Base & limit registers, page tables, segment tables | base=0x1000000 |
| Accounting Info | CPU time used, real time elapsed, time limits | 2.7 sec |
| I/O Status Info | List of open files, allocated I/O devices | fd=[0,1,2,7] |
| Parent PID (PPID) | PID of process that created this one | 1023 |
Animated Anatomy of a PCB
The gold scanner sweeps down the PCB, highlighting each field. CPU-time and process-state values tick live to show these fields update while the process runs.
Types of Schedulers — The Three Levels
Operating systems use up to three schedulers, each operating at a different frequency and making a different decision. Galvin classifies them by how often they run and which state transition they control.
As you move from Long-Term → Short-Term, execution frequency increases and per-decision time budget decreases. Short-term schedulers must complete in microseconds; long-term schedulers can take milliseconds.
Animated — Relative Frequencies of the Three Schedulers
Every dot is one scheduler invocation. Short-term speeds by like a metronome; long-term crawls along; medium-term punches in occasionally.
Long-Term Scheduler (Job Scheduler)
That ticket counter is the long-term scheduler.
If the long-term scheduler admits only CPU-bound processes, the ready queue starves I/O devices. Admit only I/O-bound and the CPU sits idle. A good mix is the single biggest win of a long-term scheduler.
Short-Term Scheduler (CPU Scheduler)
The short-term scheduler — also called the CPU scheduler or dispatcher — is invoked every time the CPU becomes free. That happens on every clock interrupt (typically 10 ms), every I/O wait, and every process exit.
If short-term scheduling takes 10 ms per decision and the OS schedules every 100 ms, then 10% of CPU time is lost to scheduling itself. Real kernels finish this in microseconds.
Common CPU-Scheduling Algorithms
| Algorithm | Selects | Preemptive? | Typical Use |
|---|---|---|---|
| FCFS (First-Come-First-Served) | Oldest process in queue | No | Batch systems |
| SJF (Shortest Job First) | Process with shortest burst | Optional | Batch, theory |
| Priority Scheduling | Highest-priority process | Optional | Real-time systems |
| Round Robin (RR) | Next in queue, time-slice enforced | Yes | Time-sharing (UNIX, Windows) |
| Multilevel Queue | Highest non-empty queue | Yes | Systems with many process classes |
Animated Round-Robin — Time-Slice In Action
The gold token orbits the queue → CPU → queue, giving each process its 10 ms slice. The right-hand timeline shows the same story as a Gantt chart.
Medium-Term Scheduler (Swapper)
That's swapping. The stable patient never lost their file (PCB); they just moved location temporarily.
The medium-term scheduler performs swapping: temporarily moving a partially-executed process from main memory to secondary storage, then bringing it back later. This reduces the degree of multiprogramming when memory pressure spikes.
Animated Swap-Out & Swap-In
P3's box drifts from RAM to disk (swap-out), sits there while another process runs, then drifts back (swap-in) — its PCB stayed in the kernel the entire time.
Moving a process image to disk and back costs milliseconds — much slower than a context switch. Modern OSes prefer paging (moving individual pages) instead of full-process swapping, but the medium-term scheduler concept still applies.
Animated — All Three Schedulers Working Together
Every dot is a process. The green scheduler admits; the amber scheduler dispatches; the purple scheduler swaps. The pipeline never stops.
Comparison — All Three Schedulers
| Property | Long-Term | Short-Term | Medium-Term |
|---|---|---|---|
| Also called | Job Scheduler | CPU Scheduler / Dispatcher | Swapper |
| Speed of execution | Slowest | Fastest | Medium |
| Frequency of invocation | Seconds–minutes | Milliseconds | Occasional |
| State transition controlled | NEW → READY | READY → RUNNING | READY ↔ SUSPENDED |
| Controls degree of multiprogramming | Yes | No | Yes |
| Present in time-sharing OS? | Rarely | Always | Sometimes |
| Decision goal | Good process mix | Max CPU utilisation, low latency | Relieve memory pressure |
Animated — Context Switching With PCB
Read the status line at the bottom to follow the four-step dance: run → save PCB(P1) → load PCB(P2) → continue P2.
No user work is done during a context switch. On modern hardware it costs 1–10 microseconds. Choosing a shorter time-quantum in Round Robin gives snappier response but more overhead — a classic throughput vs latency tradeoff.
Practical Example — Modelling a PCB in C
Here is a simplified PCB structure showing what a real kernel writes. This is close to the classical Galvin form.
/* pcb.h - Simplified Process Control Block */
#include <stdint.h>
typedef enum {
STATE_NEW,
STATE_READY,
STATE_RUNNING,
STATE_WAITING,
STATE_TERMINATED
} ProcessState;
typedef struct {
/* --- Identification --- */
uint32_t pid; // unique process ID
uint32_t ppid; // parent PID
uint32_t uid; // owner user ID
/* --- Process State --- */
ProcessState state;
/* --- CPU Context (saved on preemption) --- */
uint64_t program_counter;
uint64_t stack_pointer;
uint64_t registers[16]; // RAX..R15 on x86-64
uint64_t flags;
/* --- Scheduling Info --- */
int priority; // 0 = highest
uint64_t time_slice_remaining; // for Round Robin
struct PCB *next_in_queue; // linked-list pointer
/* --- Memory Management --- */
uint64_t base_register;
uint64_t limit_register;
void *page_table;
/* --- Accounting --- */
uint64_t cpu_time_used_us; // microseconds
uint64_t creation_time;
/* --- I/O Status --- */
int open_files[32]; // file descriptor table
int num_open;
} PCB;
Simulating a Round-Robin Short-Term Scheduler
/* Very simplified RR scheduler over a ready-queue of PCBs */
#define QUANTUM_US 10000 // 10 ms time quantum
PCB *ready_head = NULL; // front of ready queue
PCB *running = NULL; // currently on CPU
void enqueue_ready(PCB *p) {
p->state = STATE_READY;
p->next_in_queue = NULL;
if (!ready_head) { ready_head = p; return; }
PCB *t = ready_head;
while (t->next_in_queue) t = t->next_in_queue;
t->next_in_queue = p;
}
void context_switch(PCB *from, PCB *to) {
// 1. Save current CPU state into 'from' PCB
if (from) {
from->program_counter = cpu_get_pc();
cpu_save_registers(from->registers);
from->state = STATE_READY;
enqueue_ready(from);
}
// 2. Load 'to' PCB into CPU
cpu_load_registers(to->registers);
cpu_set_pc(to->program_counter);
to->state = STATE_RUNNING;
to->time_slice_remaining = QUANTUM_US;
running = to;
}
/* Called on every timer interrupt (every 1 ms, say) */
void timer_tick(uint64_t elapsed_us) {
if (!running) return;
running->cpu_time_used_us += elapsed_us;
running->time_slice_remaining -= elapsed_us;
if (running->time_slice_remaining <= 0) {
// Time-slice expired -> preempt
PCB *next = ready_head;
if (next) {
ready_head = next->next_in_queue;
context_switch(running, next);
}
}
}
The PCB is what makes context_switch() possible. Without saving/restoring PC and registers, resuming a paused process would be like re-reading a book from page 1 every time you put it down.
Real-World — Linux's task_struct
Linux's PCB is called task_struct and lives in <linux/sched.h>. It has over 100 fields, but the classical Galvin subset is clearly visible.
/* Excerpt from Linux kernel (simplified) */
struct task_struct {
/* Identification */
pid_t pid;
pid_t tgid; // thread group id
struct task_struct *parent;
kuid_t uid;
/* State & scheduling */
long state; // TASK_RUNNING, TASK_INTERRUPTIBLE...
int prio; // current priority
int static_prio; // nice value based
struct sched_entity se; // CFS scheduling entity
unsigned int policy; // SCHED_NORMAL, SCHED_FIFO...
/* CPU context — saved in thread_struct */
struct thread_struct thread;
/* Memory management */
struct mm_struct *mm;
/* Open files */
struct files_struct *files;
/* Accounting */
u64 utime, stime; // user/system CPU time
u64 start_time;
};
Every Galvin field maps to a Linux field: PID → pid, State → state, CPU context → thread_struct, Memory info → mm_struct, Open files → files_struct, Priority → prio. The textbook is not academic fluff — it is exactly what real kernels implement.