Mastering Linux Process Creation: fork, exec, wait, and Exit Explained
This comprehensive guide walks through Linux process creation with fork, explains its return values and copy‑on‑write behavior, covers normal and abnormal termination using return, exit and _exit, details waiting with wait/waitpid, and demonstrates program replacement via exec functions and a simple custom shell.
Process Creation
In Linux, fork creates a new child process; it returns 0 in the child, the child's PID in the parent, and –1 on failure.
Allocate new memory and kernel structures for the child.
Copy part of the parent’s data structures to the child.
Add the child to the system process list.
Return to user space and let the scheduler run the child.
After fork, parent and child share code and data until a write occurs. An example shows that "Before" prints once (parent) while "After" prints twice (parent and child).
fork Return Values
Why does fork return 0 to the child and the child's PID to the parent?
The parent needs the child's PID to manage it, while the child does not need to know the parent’s PID.
Why are there two return values?
Both processes continue executing after fork; each executes its own return statement, so both need a value.
Copy‑On‑Write
When a child is first created, parent and child share the same physical pages. Only when either process writes to a page does the kernel copy that page for the writer, preserving isolation.
Reasons for copy‑on‑write:
Process independence – modifications in the child must not affect the parent.
Efficiency – avoid copying data that may never be written.
Only code that is replaced (e.g., during exec) triggers a copy.
Typical fork Usage
A process creates a child to handle a separate task (e.g., a server spawning a handler).
The child may call an exec function to run a different program.
fork Failure Reasons
System has too many processes or insufficient memory.
User‑level process limit is reached.
Process Termination
Exit Codes
The main function returns an integer that becomes the process exit code; 0 indicates success, non‑zero indicates an error.
Commands such as ls or pwd also return 0 on success and non‑zero on failure.
return, exit, and _exit
returnfrom main is equivalent to calling exit. exit runs user‑registered cleanup functions, flushes buffers, closes streams, and then invokes _exit. _exit terminates the process immediately without any cleanup.
#include <stdio.h>
int main(){
printf("Hello
");
return 0; // same as exit(0)
}Process Waiting
The parent must reap the child to avoid zombie processes. The kernel provides wait and waitpid, both returning a status integer that encodes exit information.
The low 16 bits of status contain:
High 8 bits – exit code (if the process exited normally).
Low 7 bits – terminating signal number (if killed by a signal).
Bit 7 – core‑dump flag.
int exitCode = (status >> 8) & 0xFF; // exit code
int exitSignal = status & 0x7F; // signal numberMacros simplify extraction: WIFEXITED(status) – true if the child exited normally. WEXITSTATUS(status) – retrieves the exit code.
wait
Prototype: pid_t wait(int *status); – blocks until any child terminates.
waitpid
Prototype: pid_t waitpid(pid_t pid, int *status, int options); – can wait for a specific child or use WNOHANG for non‑blocking polling.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(){
pid_t id = fork();
if(id==0){
// child
for(int i=0;i<10;i++){
printf("I am child… PID:%d PPID:%d
", getpid(), getppid());
sleep(1);
}
exit(0);
}
int status=0;
pid_t ret = waitpid(id,&status,0);
if(ret>0 && WIFEXITED(status))
printf("child exited with code %d
", WEXITSTATUS(status));
return 0;
}Non‑Blocking Polling
Using waitpid with WNOHANG lets the parent perform other work while the child runs.
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(){
pid_t id = fork();
if(id==0){
// child work
sleep(3);
exit(0);
}
while(1){
int status=0;
pid_t ret = waitpid(id,&status,WNOHANG);
if(ret>0){
printf("child finished, exit %d
", WEXITSTATUS(status));
break;
}else if(ret==0){
printf("parent doing other work...
");
sleep(1);
}else{
perror("waitpid");
break;
}
}
return 0;
}Program Replacement (exec)
The exec family replaces the current process image with a new program. Six variants exist: execl – list of arguments, explicit path. execlp – list, searches PATH. execle – list with custom environment. execv – vector (array) of arguments, explicit path. execvp – vector, searches PATH. execve – vector with custom environment; the only true system call.
All return only on error (‑1). Example of execl:
execl("/usr/bin/ls", "ls", "-a", "-l", NULL);Only execve directly invokes the kernel; the other five are thin wrappers.
Simple Shell Example
A minimal shell reads a command line, tokenises it, forks, calls execvp in the child, waits for the child, and prints the exit code.
#include <stdio.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define LEN 1024
#define NUM 32
int main(){
char cmd[LEN];
char *argv[NUM];
while(1){
printf("$ ");
if(!fgets(cmd, LEN, stdin)) break;
cmd[strlen(cmd)-1]='\0';
argv[0]=strtok(cmd, " ");
int i=1;
while((argv[i]=strtok(NULL," "))) i++;
pid_t pid=fork();
if(pid==0){
execvp(argv[0], argv);
exit(1);
}
int status=0;
waitpid(pid,&status,0);
printf("exit code:%d
", WEXITSTATUS(status));
}
return 0;
}Running the custom shell shows the child’s exit code, distinguishing it from the system’s default shell.
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.
Open Source Linux
Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.
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.
