Introduction
fork, exec, wait, and exit describe the basic Unix-style process flow used by shells. They show how a program can create another process, run a new program inside it, and collect its result after it finishes.
The core idea is simple: fork creates, exec replaces, wait collects, and exit terminates. Together, these calls explain how commands like ls can run without replacing the shell itself.
Why These System Calls Are Needed
A shell must run a command while staying alive. If the shell itself became the ls program, the prompt would disappear after the command finished.
Unix-like systems solve this by separating process creation from program replacement. The shell creates a child process, the child becomes the command, and the parent shell waits until the child finishes.
Meaning of fork, exec, wait and exit
fork: Creates a child process by duplicating the calling processexec: Replaces the current process with a new programwait: Lets the parent collect the child's termination statusexit: Terminates the current process with an exit status
These calls work together, but they do different jobs.
fork Behavior
fork() creates a child process. After fork, both parent and child continue running from the same point in the code, but they receive different return values.
The return values are:
pid == 0: This path is running in the child process.pid > 0: This path is running in the parent process, and the value is the child's PID.pid < 0: Process creation failed.
A compact view is:
pid_t pid = fork();if (pid == 0) { // Child process child_path();}else if (pid > 0) { // Parent process parent_path();}else { // fork() failed fork_failed();}The parent and child are separate processes. The child initially looks like a copy of the parent, but both have separate process identities and separate memory spaces.
fork and exec Behavior
exec Behavior
exec replaces the current process image with a new program. The same process continues to exist, but its old program code, stack, and heap are replaced by the new program.
Important points about exec are:
It does not create a new process: It changes the program inside the current process.
The PID usually stays the same: The process identity remains.
The new program starts fresh: Execution begins from the new program's entry point.
It does not return on success: If old code continues after
exec, the replacement failed.Some file descriptors may remain open: Unless they are marked close-on-exec.
This is why shells usually call exec in the child process, not in the parent shell.
Shell Command Flow
Suppose the user types ls. The shell should run ls, wait for it if it is a foreground command, and then show the prompt again.
A simplified shell flow is:
pid_t pid = fork();if (pid == 0) { // Child: replace itself with the ls program exec("ls"); // Reached only if exec() fails exit(1);}else if (pid > 0) { // Parent: wait for the child to finish wait(pid);}else { // fork() failed handle_fork_failure();}The runtime idea is:
Shell runs: The shell waits for a user command.
Shell calls
fork: A child process is created.Child calls
exec: The child becomes thelsprogram.Child runs
ls: The command performs its work.Child calls
exit: The command finishes with a status.Parent calls
wait: The shell collects the child's status.Shell continues: The prompt returns.
The parent shell remains alive because only the child is replaced by the command.
Shell Command Flow
exit, wait and Cleanup
exit(status) terminates the current process and stores an exit status. That status is meant to be collected by the parent process.
wait() lets the parent wait for a child to terminate and collect its status. Once the status is collected, the kernel can clean the remaining child metadata.
If a child finishes but the parent never collects its status, the child can become a zombie process. A zombie is no longer executing, but some process table information remains so the parent can still read its termination status.
Common Confusions
A common confusion is thinking that fork directly runs a new program. It does not. fork only creates a child process that starts as a copy of the parent. The new program is loaded through exec.
Another common mistake is thinking that exec creates a new process. It does not. It replaces the current process image, usually keeping the same PID.
Summary
fork, exec, wait, and exit form the usual Unix-style process control flow. fork creates a child, exec replaces the child with a new program, exit ends the child with a status, and wait lets the parent collect that status.
For a command like ls, the shell forks a child, the child execs ls, the command finishes with exit, and the parent shell waits before showing the prompt again. This keeps the shell alive while still allowing it to run separate programs.
Be the first to add a comment.