Module 2 · Unit 3 · Lesson 2 of 5
Process States
A process does not simply "run" — it occupies one of several well-defined states at every moment. This lesson examines the state model, the transitions between states, and why the model is the foundation for everything the scheduler does.
01 Introduction
A running program is not always running. It might be waiting for input from a user, blocked on a disk read, or simply queued behind another program that currently has the CPU. From the process's point of view, time passes without progress; from the operating system's point of view, the process is in a specific state that determines what can happen to it next.
The state model is the operating system's way of classifying every process in the system at every moment. It is the vocabulary the scheduler uses to decide which process runs next. It is the vocabulary the memory manager uses to decide which pages can be swapped out. It is the vocabulary you will use for the rest of the course when reasoning about what a program is doing.
This lesson presents the five-state model that describes almost every process on a modern general-purpose operating system. More elaborate models exist — the seven-state model adds Suspended states for processes swapped out to disk — but the five-state model captures the essential structure and is what the course will use throughout. By the end you will be able to read a state diagram, identify the transition that caused any particular state change, and observe process states directly on a live Linux system.
02 Learning objectives
By the end of this lesson you will be able to
- Describe process states.
- Explain state transitions.
- Interpret state diagrams.
- Analyse process behaviour.
- Relate states to scheduling.
This lesson contributes to U3.2 and to course learning outcomes CLO2 and CLO6.
03 Required reading
- Operating System Concepts — Chapter 3, Section 3.2 (Process States). The formal presentation of the five-state model and its transitions.
- OSTEP — Chapter 4, the discussion of process states and the OS's decision about which process to run. Pay particular attention to the diagram showing how a process moves between states during its lifetime.
-
Linux man pages:
man 1 ps(see the PROCESS STATE CODES section),man 5 proc(thestatfile and its state field),man 2 wait(the blocking behaviour that produces the Blocked state). - Love, R. — Linux Kernel Development, 3rd ed., Chapter 3, the section on process state. How Linux concretely implements the state model and what the state flags mean.
Reading strategy
Read Silberschatz Section 3.2 first for the formal model, then
the OSTEP chapter for the practical framing. Keep
man 1 ps open as you read section 4.7 — the
Linux state codes are a concrete realisation of the abstract
states, and seeing them side by side will make both clearer.
04 Core content
4.1 The five states
At any moment, a process is in exactly one of five states.
- New
-
The process is being created. The kernel has allocated a
process control block (PCB) but has not yet admitted the
process to the set of runnable processes. In some systems,
the program image is being loaded from disk. On Linux, this
state exists only briefly, during the few microseconds of
forkbefore the child is ready to run. - Ready
- The process is able to run. All resources it needs for immediate execution are available, but the CPU is currently serving another process. A ready process is waiting in a queue for its turn. On a system with a single CPU core, only one process can be Running at a time; every other runnable process is Ready.
- Running
- The process has the CPU and its instructions are being executed. On a system with N CPUs, at most N processes can be Running at any instant — but many more may be Ready, waiting for a core.
- Blocked
- The process cannot proceed until some event occurs — typically the completion of an I/O operation, the arrival of a signal, or the acquisition of a lock. Even if a CPU were available, the process would not be able to use it. Blocked is sometimes called "waiting" or "sleeping" in different textbooks and in Linux itself.
- Terminated
- The process has finished executing. Its exit status may be held for the parent, but it will never run again. On Linux, this corresponds to the "zombie" state from Lesson 3.1 — the process has terminated but its parent has not yet reaped it.
The distinction between Ready and Blocked is subtle but fundamental. A Ready process could run if the scheduler chose it. A Blocked process could not, no matter what the scheduler chose. This is why the two states have different queues and are managed by different parts of the kernel. It is the single most important conceptual distinction in the model.
4.2 The state diagram
The relationships between states are conventionally drawn as a directed graph. Each state is a node; each transition is an arrow labelled with the event that triggers it.
4.3 The seven transitions
The model defines exactly seven transitions. Each is triggered by a specific event, and each requires the kernel to update the process's PCB and its position in the relevant queue.
| Transition | Trigger | Initiated by |
|---|---|---|
| New → Ready | The process has been fully created and admitted | Kernel (long-term scheduler) |
| Ready → Running | The scheduler selects this process for the CPU | Kernel (short-term scheduler) |
| Running → Ready | The process is preempted (time slice expires, higher-priority process arrives) | Kernel |
| Running → Blocked | The process issues a blocking system call or waits on a lock | The process itself (voluntary) |
| Blocked → Ready | The awaited event occurs (I/O completes, lock acquired, signal arrives) | Kernel (upon interrupt or signal) |
| Running → Terminated | The process exits or is killed | Process or kernel |
| Blocked → Terminated | The process is killed while waiting (some systems) | Kernel |
Not every transition is allowed
A Blocked process cannot be dispatched directly to Running. It must first return to Ready. Similarly, a process cannot go from Ready to Blocked — a process can only block while it is actually executing, since blocking is a request from the running code. These constraints are important when reasoning about what the kernel can and cannot do. If you see a diagram in which Blocked → Running is drawn as a single arrow, it is a simplification, not a correct state model.
4.4 Voluntary versus involuntary transitions
The transitions differ in who initiates them. This distinction matters because it determines whether the OS can guarantee fairness.
- Voluntary transitions
-
The process itself gives up the CPU. Running → Blocked is
the clearest example: the process calls
read, orwait, or tries to acquire a lock that is held. The process is saying "I cannot proceed right now." Cooperative multitasking and early time-sharing systems relied entirely on voluntary yielding; if a process never yielded, the system stopped. - Involuntary transitions
- The kernel takes the CPU away from a process that would prefer to keep running. Running → Ready is the primary example: a timer interrupt fires, or a higher-priority process becomes ready. This is preemption, and it is what makes modern systems responsive.
The transition Running → Ready is the only one that requires preemption. Without it, a process that never issues a blocking call and never exits could monopolise the CPU indefinitely. A hardware timer is therefore essential: it lets the kernel interrupt any running process at a known maximum interval and reclaim control. This is why the timer interrupt appeared as a prerequisite in the historical discussion in Lesson 1.2 — it is what makes preemptive multitasking possible.
4.5 Queues associated with states
The kernel maintains a queue for every state that can hold multiple processes simultaneously. Understanding the queues clarifies what "moving a process from state A to state B" actually means operationally: the kernel removes the process from one queue and inserts it into another.
-
Job queue. All processes in the system,
including those in New and Terminated. On Linux, this is not
a single literal queue but the collection of all
task_structs the kernel maintains. - Ready queue. Processes in the Ready state, waiting for the CPU. On Linux, this is a per-CPU run queue, implemented as a red-black tree of runnable tasks keyed by their virtual runtime.
- Device queues. Processes blocked on each device or on other events. Linux maintains wait queues per event: one per open file, one per socket, one per lock, and so on. When the event occurs, the kernel walks the corresponding wait queue and wakes the blocked processes.
When a process changes state, the kernel moves it from one queue to another. On a busy system, these moves happen hundreds or thousands of times per second. The efficiency of the queue operations therefore matters directly to system performance; this is one reason the kernel uses data structures such as red-black trees and per-CPU queues rather than a single global list.
4.6 Why the Ready/Blocked distinction is fundamental
The most important conceptual takeaway from this lesson is the distinction between Ready and Blocked. It is worth restating in concrete terms.
Consider two processes on the same machine. Process A is
CPU-bound: it is running a long computation with no I/O, and
the scheduler has just preempted it. Process B has just called
read on a file and is waiting for the disk to
respond.
If the scheduler were forced to choose between these two — say, because the currently running process has just exited — it would be absurd to consider B. B cannot run until the disk responds; dispatching B would be a wasted context switch and the CPU would be idle for the duration of the disk operation. Process A, on the other hand, is perfectly ready: it can resume immediately.
This is exactly what the Ready queue encodes. It is the set of processes that could actually make progress if given the CPU. Blocked processes are not in it, because they cannot. The distinction is not a classification of convenience; it reflects the physical reality that a process waiting on a device cannot use a CPU even if one is offered.
4.7 Process states on Linux
Linux implements the five-state model but with additional
detail. The STAT column of ps and
the state field in /proc/<pid>/stat encode
the current state of each process. The common codes are:
| Code | Name | Corresponds to | Description |
|---|---|---|---|
R |
Running or runnable | Running or Ready | The process is executing or is on the run queue, ready to execute. |
S |
Interruptible sleep | Blocked | Waiting on an event; can be woken by a signal. The most common state for ordinary processes. |
D |
Uninterruptible sleep | Blocked | Waiting on I/O, and cannot be woken by a signal. Usually short-lived; processes in D cannot be killed until the I/O completes. |
T |
Stopped | — | Suspended by a job-control signal (Ctrl+Z or SIGSTOP). Not one of the five canonical states; a form of suspension. |
Z |
Zombie | Terminated | The process has exited but the parent has not reaped it. |
I |
Idle kernel thread | — | An idle kernel thread; used only for kernel-internal threads on some systems. |
Note that Linux merges Running and Ready into a single
R code. This is because Linux's scheduler does not
maintain a strict distinction: a task on the run queue is
considered "running" from the kernel's point of view even if
it is currently not executing. The distinction that matters
for the scheduler — is it runnable, or is it blocked? — is
captured by the difference between R and
S/D.
Linux also distinguishes interruptible from uninterruptible
sleep. The former can be interrupted by a signal, allowing the
process to handle the signal and then continue or exit.
The latter — used for short periods during critical I/O
operations — cannot be interrupted by a signal, because doing
so would leave the kernel in an inconsistent state. Processes
in the D state are the ones that appear unkillable;
kill -9 has no effect until the I/O completes.
4.8 What the diagram does not show
The five-state model is a simplification. It omits several things that real systems do:
- Suspended states. A process that has been swapped out to disk, or is otherwise not in physical memory, is in a state the five-state model does not name. The seven-state model adds "Suspended Ready" and "Suspended Blocked" for these cases.
- Multiple blocked reasons. A process may be blocked waiting for one of several events; the model shows a single Blocked state regardless.
- Threads. A process in the five-state model is a single thread of control. Once we introduce threads in Unit 4, each thread has its own state, and a process may be Ready, Blocked, and Running simultaneously in its different threads.
- Real-time states. Real-time processes have additional scheduling states that the general model does not cover.
None of these omissions change the fundamentals. The five-state model is the right level of abstraction for reasoning about general-purpose process behaviour, and everything else is a refinement.
4.9 How a process moves between states: a concrete walkthrough
To make the model concrete, consider what happens to a single process — an instance of a text editor — as you use it:
-
You type
vim notes.txtat the shell. The shell forks a child. The child begins in the New state while its address space is being set up. - Admission. The kernel confirms the child has its resources. Transition: New → Ready. The process joins the ready queue behind any other runnable work.
- Dispatch. The scheduler selects the process. Transition: Ready → Running. The kernel performs a context switch and vim begins executing.
-
vim reads
notes.txt. It callsopen, which may or may not block (usually the directory and inode are in cache). Thenread. Assume the file is on disk and not cached. Thereadsystem call cannot return immediately. Transition: Running → Blocked. The process is moved to the wait queue for the storage device. - Timer preempts the editor? No — the process is Blocked, so no preemption is involved. It is simply not on the ready queue anymore.
- The disk completes. The device controller raises an interrupt. The kernel's interrupt handler moves the editor's process back to the Ready state. Transition: Blocked → Ready.
-
The editor is dispatched again. Transition:
Ready → Running. Its
readcall returns, and vim continues as if nothing had happened. -
You type a character. vim reads from its
terminal via
readon stdin, blocks again, and the cycle repeats. This pattern repeats hundreds of times per minute while you edit. -
You save and quit. vim writes the file with
writeand callsexit. Transition: Running → Terminated. The exit status is held for the shell. -
The shell reaps. It calls
wait, receives the exit status, and prints the next prompt.
If you were to watch this process with ps during
the run, you would see the STAT column changing
between S (when waiting for input), R
(during the brief bursts of processing the input), and
possibly D (during the initial file read). This
is what the state model looks like in practice.
Interactive programs spend most of their time blocked
The editor in the walkthrough spends almost all its time in the Blocked state — waiting for input, waiting for the disk, waiting for something. This is normal and healthy. It means the CPU was free to run other work while the editor waited. A process that spends most of its time Ready or Running is CPU-bound; a process that spends most of its time Blocked is I/O-bound. The distinction matters to the scheduler, as Lesson 3.4 will explain.
05 Worked example
A small program that drives a process through several states on demand, so that you can watch the transitions happen.
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
} else if (pid == 0) {
/* Child: block for a while, then exit */
printf("child: pid = %d — about to sleep\n", getpid());
sleep(30);
printf("child: waking up and exiting\n");
return 0;
} else {
/* Parent: sleep briefly, then check child's state */
printf("parent: pid = %d, child = %d\n", getpid(), pid);
sleep(2);
printf("parent: waking up, will wait for child\n");
wait(NULL);
printf("parent: child reaped, exiting\n");
}
return 0;
}
Following the child through states on a live system
-
Compile and run.
$ gcc -Wall -Wextra -g -o states states.c $ ./states & parent: pid = 1234, child = 1235 child: pid = 1235 — about to sleep parent: waking up, will wait for child # the shell prompt returns because we ran in background -
Check the child's state. Because the child
called
sleep(30), it is in the Blocked state. On Linux,sleepis implemented with a timer wait, so the child appears in interruptible sleep:
The$ ps -p 1235 -o pid,stat,cmd PID STAT CMD 1235 S ./statesSconfirms the child is blocked, not running. The parent is also sleeping, and would showSas well. -
Watch the state field directly. The kernel
writes the current state character to
/proc/<pid>/stat. The third field is the state:
The$ cat /proc/1235/stat | awk '{print "state:", $3}' state: SScharacter will remain until the sleep completes. -
Force a state change with a signal.
Send
SIGSTOPto the child:
The state is now$ kill -STOP 1235 $ ps -p 1235 -o pid,stat,cmd PID STAT CMD 1235 T ./statesT(stopped). The process is still in the system, still consuming a PID, but it is not competing for the CPU and itssleepwill not expire. -
Resume it.
The process returns to$ kill -CONT 1235 $ ps -p 1235 -o pid,stat,cmd PID STAT CMD 1235 S ./statesS, resuming its sleep where it left off. -
Watch the transition to termination. Wait
for the child's 30 seconds to expire (or send
SIGTERMto speed it up). The child exits and its parent reaps it. After reaping, the PID no longer exists:
The$ ps -p 1235 -o pid,stat,cmd PID STAT CMD # no output — the process is gonewaitin the parent collected the exit status, and the kernel removed the process-table entry. -
Observe a zombie (variant). Modify the
program so that the parent does not call
wait. Run it again and observe the child after it exits but before the parent exits:
The$ ps -p 1235 -o pid,stat,cmd PID STAT CMD 1235 Z [states] <defunct>Zconfirms the child is a zombie — the Terminated state in the five-state model, held until the parent reaps it.
The full lifecycle is: New (brief) → Ready (on the run queue)
→ Running (dispatched) → Blocked (called sleep) → Ready
(sleep expires) → Running (resumed) → Terminated (exited)
→ gone (reaped). The ps and /proc
observations correspond to whichever state the process was
in when you looked.
06 Interactive activity
Activity · observe process states on your VM
Open a terminal in your course VM and work through the following. The goal is to connect the abstract state model to the state codes you can see on a running system.
-
Read the state codes. Run
man psand search for the "PROCESS STATE CODES" section (press / and typePROCESS STATE, then Enter). Note the meaning of each code from the table in section 4.7. -
See a running process. In one terminal,
run
yes > /dev/null &. This is a pure CPU loop. In another terminal, runps aux | grep yesrepeatedly and watch theSTATcolumn. Is it alwaysR, or does it change? -
See a sleeping process. Kill the
yesprocess. Now runsleep 60 &. Watch it withps. It will be inSstate — interruptible sleep. -
See a stopped process. Start
sleep 300in the foreground in one terminal. In another, runkill -STOP <PID>. Checkps. The state will beT. Restart it withkill -CONT <PID>. -
See a zombie. Compile the variant from
the worked example in which the parent does not call
wait. Run it in the background. Useps aux | grep Zto find the zombie. What does theCMDcolumn say for it? -
Watch the state field directly. Pick any
process's PID and repeatedly read the state from
/proc:
Run this against a CPU-bound process and against a sleeping process. Does the state change? Why or why not?for i in $(seq 1 20); do awk '{print $3}' /proc/<PID>/stat sleep 0.1 done - Follow a process through its whole life. Write a script that forks a child, has the child do work for a few seconds, and has the parent watch the child's state change. Record the sequence of states you observe. (The worked example above is a good starting point.)
Reflect: which states were easiest to observe? Which were so brief that you could only catch them by luck? What does the difficulty of observing the Running state tell you about how much of a process's life is spent actually executing?
07 Knowledge check
Check your understanding
Question 1
A process is currently in the Blocked state. List every state it can transition to next, and describe the event that causes each transition.
Show answer
Question 2
Why is the Running → Ready transition impossible without hardware support?
Show answer
Question 3
Distinguish a Blocked process from a Ready process in one sentence, and explain why the distinction matters for the scheduler.
Show answer
Question 4
On Linux, what is the difference between the S and D state codes, and why does a process in the D state sometimes appear to be unkillable?
Show answer
S and D mean the process
is blocked, but they differ in whether a signal can
interrupt the wait. S is interruptible
sleep: a signal (such as SIGTERM) will wake
the process, letting it handle the signal and then
either continue or exit. D is
uninterruptible sleep: signals are held until the wait
completes. The D state is used during short critical
operations — typically hardware I/O that must complete
before the kernel can restore consistency — where
interrupting the wait would leave the kernel or the
device in an inconsistent state. A process in D will
respond to kill -9 only after the I/O
completes; until then it appears unkillable.
Question 5
In the five-state model, a process cannot transition from Ready directly to Blocked. Why not?
Show answer
read,
wait, pause, and so on) or
wait on a lock. Those are actions that only make sense
from code that is actually executing. A process that is
Ready is sitting on the run queue, not executing; it has
no opportunity to issue a blocking call, and the kernel
has no reason to move it to Blocked. The only way for a
ready process to become blocked would be if the kernel
itself decided to block it, which would be a
fundamentally different operation — and would model a
kernel-initiated suspension, not a process-initiated
wait.
08 Unit discussion
Discussion prompt
The five-state model assumes that a process is either interruptible or it is not — that once a process is blocked, it stays blocked until its event completes. Real systems complicate this: a process in interruptible sleep can be woken by a signal even before its I/O completes, and must handle that case explicitly.
Find an example of code that must handle interrupted blocking calls correctly. What happens if it does not? Support your answer with a concrete reference — a man page, a section of source, or a programming idiom you have seen. Then consider: does the need to handle signals break the state model, or does it merely refine what "Blocked" means?
Post your response to the Unit 3 discussion forum and reply to at least two classmates. Supports CLO2 and CLO6.
09 Practice exercise
This ungraded exercise consolidates the lesson and prepares you for the state-tracking aspects of Lab 2. Aim to spend 45–60 minutes on it.
- Draw the state model from memory. Without looking at Figure 3.2, draw the five-state model and label all seven transitions. Then check against the lesson. Which transitions did you miss, and why?
- Classify the transitions. For each of the seven transitions, decide whether it is voluntary (initiated by the process) or involuntary (initiated by the kernel). Are any ambiguous? Explain your reasoning.
-
Write a state-tracking program. Write a C
program that:
- Forks a child.
- Has the child print its own state by reading
/proc/self/statand extracting the third field. - Has the child enter a sleep and then wake, printing its state before and after.
- Has the child exit, and the parent wait and report the exit status.
strace -f -e trace=sleep,nanosleep,clone,wait4. Identify the system calls that trigger the state transitions. -
Trace a shell command. Run
strace -T -tt ls /tmp. Look for thereadandopenatcalls. Which of them blocked? The-Tflag shows the duration of each call; long durations indicate actual blocking. -
Observe a long-running process. Run a
background job that mixes CPU and I/O — for example,
find / -type f > /dev/null 2>&1 &. Poll the process's state every 100 milliseconds for 10 seconds using a loop that reads/proc/<PID>/stat. Record how many times the state wasR, how manyS, and how manyD. What does the distribution tell you about the workload? - Reflect. In your own words, describe one concrete situation in which a process that is Ready is not Running, and one in which a process that is Blocked would be a bad choice for the scheduler even though the CPU is idle. Use the two-process example from section 4.6 as a starting point.
10 Summary
- A process occupies one of five states at every moment: New, Ready, Running, Blocked, Terminated.
- Ready means "could run if given the CPU"; Blocked means "cannot proceed until an event occurs." The distinction is the most important in the model.
- Seven transitions connect the states. Of these, Running → Ready is the only one that requires preemption, and preemption requires hardware timer support.
- Transitions are either voluntary (the process gives up the CPU, e.g., Running → Blocked) or involuntary (the kernel takes the CPU away, e.g., Running → Ready).
- The kernel maintains queues for the multi-process states: the job queue (all processes), the ready queue (Ready processes), and device queues (blocked processes waiting on specific events).
-
On Linux, the state is exposed through the
STATcolumn ofpsand the third field of/proc/<pid>/stat. Common codes areR(running/runnable),S(interruptible sleep),D(uninterruptible sleep),T(stopped), andZ(zombie). - The five-state model omits some details — suspended states, multiple blocked reasons, per-thread states, and real-time extensions — but captures the essential structure that all of these refine.
Looking ahead
Lesson 3.3 examines the data structure the kernel uses to track each process's state — the process control block. The PCB is where the current state is recorded and where every other piece of process metadata lives.
11 References
- Silberschatz, A., Galvin, P. B., & Gagne, G. Operating System Concepts, 10th ed., Chapter 3, Section 3.2.
-
Arpaci-Dusseau, R. H., & Arpaci-Dusseau, A. C.
Operating Systems: Three Easy Pieces, Chapter 4.
Available online at
ostep.org. - Love, R. Linux Kernel Development, 3rd ed., Chapter 3 (Process Management), especially the process-state discussion. Addison-Wesley, 2010.
-
Linux man-pages:
man 1 ps(PROCESS STATE CODES),man 5 proc(the/proc/<pid>/statformat),man 2 wait,man 7 signal. - Bach, M. J. The Design of the UNIX Operating System, Chapter 6. Prentice Hall, 1986. (Classical presentation of the process state model.)