Understanding Linux Processes: From Program to Process Control Block
An in‑depth guide explains what a program and a process are, details the Linux task_struct fields, describes process states, creation functions like fork, vfork, clone, kthread_create, the do_fork core, copy‑on‑write, termination methods, and the roles of zombie, orphan, and init processes.
Program and Process Basics
A program is an executable file containing CPU instructions and static data. A process is a running instance of a program, comprising the executable code, user stack, data segment, kernel stack, heap, and other execution context. Processes are the basic unit of resource allocation (memory, CPU time) and enable multitasking via context switching and scheduling.
Process Control Block (task_struct)
The Linux kernel represents each process with a task_struct structure. Key fields include:
State – current state bits (e.g., TASK_RUNNING, TASK_INTERRUPTIBLE, TASK_UNINTERRUPTIBLE, __TASK_STOPPED, __TASK_TRACED, EXIT_DEAD, EXIT_ZOMBIE).
Scheduling information – policy, priority, static and dynamic priorities, real‑time priority, and pointers to scheduling entities ( struct sched_entity, struct sched_rt_entity, struct sched_dl_entity).
PID / TGID – unique process identifier ( pid) and thread‑group ID ( tgid).
Stack – pointer to the kernel stack ( void *stack).
Reference count – refcount_t usage tracks how many references hold the task.
Flags – status bits ( unsigned int flags).
SMP fields – used on multi‑processor systems (e.g., on_cpu, wake_entry, wake_cpu).
Family relationships – pointers to parent, real parent, children list, sibling list, and group leader.
Process States
Linux defines five high‑level states:
New – process is being created.
Ready – placed on the run queue, waiting for CPU.
Running – currently executing on a CPU.
Blocked – waiting for an event (I/O, semaphore, etc.).
Terminated – execution finished; the task_struct remains until reaped.
Viewing a Process State
static void show_task(struct task_struct *volatile tsk)
{
unsigned int p_state = READ_ONCE(tsk->__state);
char state;
state = (p_state == TASK_RUNNING) ? 'R' :
(p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
(p_state & TASK_STOPPED) ? 'T' :
(p_state & TASK_TRACED) ? 'C' :
(tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
(tsk->exit_state & EXIT_DEAD) ? 'E' :
(p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
printf("%16px %16lx %16px %6d %6d %c %2d %s
", tsk,
tsk->thread.ksp, tsk->thread.regs,
tsk->pid, rcu_dereference(tsk->parent)->pid,
state, task_cpu(tsk), tsk->comm);
}Process Creation Functions
fork
#include <unistd.h>
pid_t fork(void);Creates a child that is a copy of the parent. Returns child PID to the parent, 0 to the child, or –1 on error.
vfork
#include <unistd.h>
pid_t vfork(void);Similar to fork but the child runs first and shares the address space (flags CLONE_VFORK and CLONE_VM) until it calls execve or _exit.
clone
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack, int flags,
void *arg, ... /* pid_t *ptid, unsigned long newtls, pid_t *ctid */);Creates a thread or process with fine‑grained control over shared resources via flags (e.g., CLONE_VM, CLONE_FILES).
kthread_create
struct task_struct *kthread_create(int (*threadfn)(void *data),
void *data,
const char namefmt[], ...);Creates a kernel thread that runs in kernel space.
do_fork (internal)
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
{
return _do_fork(clone_flags, stack_start, stack_size,
parent_tidptr, child_tidptr, 0);
}All the above user‑level creation calls eventually invoke do_fork with appropriate clone_flags.
Resources Not Inherited by Child
PID (child receives a new PID).
PPID (set to the creating parent’s PID).
Signal handlers.
File locks.
Timers.
Shared memory segments and semaphores.
Resource limits (rlimit values).
execve
Replaces the current process image with a new program.
int execve(const char *pathname, char *const argv[], char *const envp[]);On success the call does not return; on failure it returns –1.
Copy‑On‑Write (COW)
Modern kernels use COW when creating a child process: only the page tables are duplicated and pages are shared read‑only. When either process writes to a shared page, a page‑fault triggers a private copy, minimizing memory usage.
Process Termination
Explicit call to exit or _exit.
Reception of a terminating signal (e.g., SIGKILL, SIGTERM).
Kernel exception or unrecoverable fault.
Unhandleable signal.
Zombie and Orphan Processes
Zombie : a terminated process whose parent has not yet performed wait() to read its exit status. It occupies a slot in the process table but no other resources.
Orphan : a process whose parent has exited. The init process (PID 1) adopts it and becomes its new parent.
PID 0 (Swapper) and PID 1 (init)
PID 0 is the kernel thread that runs the scheduler and core services; it exists from boot and never terminates.
PID 1 is the first user‑space process ( init). It performs system initialization, reaps zombies, and adopts orphans. Sample early‑kernel initialization code (Linux 0.11) illustrates the creation of PID 0 and PID 1:
struct task_struct init_task __aligned(L1_CACHE_BYTES) = {
.__state = 0,
.stack = init_stack,
.usage = REFCOUNT_INIT(2),
.flags = PF_KTHREAD,
.prio = MAX_PRIO - 20,
.static_prio = MAX_PRIO - 20,
.normal_prio = MAX_PRIO - 20,
.policy = SCHED_NORMAL,
.cpus_ptr = &init_task.cpus_mask,
.user_cpus_ptr = NULL,
.cpus_mask = CPU_MASK_ALL,
.nr_cpus_allowed = NR_CPUS,
.mm = NULL,
.active_mm = &init_mm,
.restart_block = { .fn = do_no_restart_syscall },
.se = { .group_node = LIST_HEAD_INIT(init_task.se.group_node) },
.rt = { .run_list = LIST_HEAD_INIT(init_task.rt.run_list), .time_slice = RR_TIMESLICE },
.tasks = LIST_HEAD_INIT(init_task.tasks),
.ptraced = LIST_HEAD_INIT(init_task.ptraced),
.real_parent = &init_task,
.parent = &init_task,
.children = LIST_HEAD_INIT(init_task.children),
.sibling = LIST_HEAD_INIT(init_task.sibling),
.group_leader = &init_task,
.comm = INIT_TASK_COMM,
.thread = INIT_THREAD,
.fs = &init_fs,
.files = &init_files,
.signal = &init_signals,
.sighand = &init_sighand,
.nsproxy = &init_nsproxy,
.pending = { .list = LIST_HEAD_INIT(init_task.pending.list), .signal = {{0}} },
.blocked = {{0}},
.alloc_lock = __SPIN_LOCK_UNLOCKED(init_task.alloc_lock),
.timer_slack_ns = 50000,
.thread_pid = &init_struct_pid,
.pi_lock = __RAW_SPIN_LOCK_UNLOCKED(init_task.pi_lock),
/* ... other fields omitted for brevity ... */
};
EXPORT_SYMBOL(init_task);Early main routine creates PID 0, performs hardware initialization, then forks to create PID 1 ( init) which launches the first user‑space shell and enters the classic init loop.
void main(void)
{
mem_init(main_memory_start, memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init();
sched_init(); /* creates PID 0 */
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
sti(); /* enable interrupts */
move_to_user_mode();
if (!fork()) {
init(); /* child becomes PID 1 */
}
}
void init(void)
{
/* system initialization, run /etc/rc, then spawn a shell */
if (!(pid = fork())) {
close(0);
if (open("/etc/rc", O_RDONLY, 0))
_exit(1);
execve("/bin/sh", argv_rc, envp_rc);
_exit(2);
}
while (pid != wait(&i))
;
for (;;) {
if ((pid = fork()) < 0) {
printf("Fork failed in init
");
continue;
}
if (!pid) {
close(0); close(1); close(2);
setsid();
(void)open("/dev/tty0", O_RDWR, 0);
(void)dup(0);
(void)dup(0);
_exit(execve("/bin/sh", argv, envp));
}
while (pid != wait(&i))
;
printf("
\rchild %d died with code %04x
\r", pid, i);
sync();
}
_exit(0);
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
