DevOpsInterviews logo
← Linux, Networking & Scripting / 15
mediumRed HatGoogleMeta

Explain how a new process comes into existence on Linux. What do fork and exec each contribute?

The two-syscall duet behind every process on the box. The follow-ups live in what survives the transition, and candidates who skip that fail the next question.

Grounded in researched DevOps, SRE and platform engineering interview loops, written to a senior-engineer editorial bar, and never padded to hit a word count.

TL;DR: fork duplicates the calling process cheaply through copy-on-write and hands the child a new PID plus inherited file descriptors. exec replaces the program image with a new binary while keeping PID and descriptors. Shells combine them: fork, exec in the child, waitpid in the parent.

How to approach it

Treat it as two phases: duplication, then replacement. After the mechanics, be ready to say what survives exec and what happens to a dead child nobody waits for. Those two follow-ups arrive almost every time, so build the answer to survive them.

A strong answer

fork returns twice. In the child it returns 0; in the parent it returns the child's PID; on failure, -1 with EAGAIN when you have hit RLIMIT_NPROC, a pids cgroup ceiling, or pid_max. The child is not a full copy: pages are shared copy-on-write, mapped read-only until either side writes, at which point the kernel faults in a private page one page at a time. The real cost of fork is copying page tables, and the size of that structure is what makes it measurable rather than free. A process mapping 10 GB with 4 KiB pages has about 10 × 1024 × 1024 / 4 = 2,621,440 page-table entries, and at roughly 8 bytes each that is around 2,621,440 × 8 / 1024 / 1024 = 20 MB of tables the kernel walks and copies while the parent is stopped. That is why a Redis parent holding 10 GB pays tens of milliseconds per fork for BGSAVE, why the cost scales with mapped memory rather than with resident data, and why the latency spike lands exactly during persistence.

exec swaps the image. The exec family loads an ELF binary, replaces text, data, heap and stack, and starts at the entry point with fresh argv and envp. PID stays. Open file descriptors stay unless they carry FD_CLOEXEC, which is how libraries stop children from inheriting internal sockets. Current directory, umask and signal mask carry over, but installed handlers reset to default, because the handler code no longer exists.

A shell builds a pipeline mechanically: call pipe() first, fork one child per stage, dup2() each pipe end onto fd 0 or fd 1, then exec the command. The parent keeps the other ends closed and sits in waitpid() collecting exit statuses. A terminated child that was never waited for is a zombie: it holds a PID table slot until reaped. An orphaned but live child gets reparented to init, or to the nearest subreaper, which is why zombie accumulation in containers points straight at a PID 1 that does not reap.

shell (pid 400)
   |--- fork() -------------------> child (pid 500, COW copy of shell)
   |                                    |--- dup2(pipe_w, fd 1)
   |                                    |--- execve("/usr/bin/ps")
   |                                          (image replaced, pid unchanged)
   |--- waitpid(500) <------------- exit(status): zombie until reaped
MechanismShares or copiesTypical caller
forkCOW address space, copied fdsshells, supervisors
clone with flagsselectable sharing: CLONE_VM, CLONE_FILES, CLONE_SIGHANDthread libraries
posix_spawnfused fork-plus-exec pathlibc internals, runtimes

Threads are clone calls sharing memory and file tables rather than copying them; separate processes can still share open file descriptions, shared-memory mappings and other kernel objects. posix_spawn exists because most callers want fork-then-exec without paying for a page-table copy they immediately abandon.

In containers the same story gains limits: a pids cgroup turns a fork bomb into a stream of EAGAIN errors instead of a frozen host, which is worth saying out loud in interviews.

How a new process comes into existence on Linux FORK: ALMOST NO COPYING EXEC: NEW PROGRAM, SAME PID 1 Parent calls fork() one call, two returns 2 Page tables copied the real cost of a fork 3 Pages shared, copy-on-write read-only until one writes 4 0 to child, PID to parent or -1, with EAGAIN 5 Child rearranges its fds dup2 onto 0 and 1 6 Child calls exec() the image is replaced 7 PID stays, handlers reset the handler code is gone 8 Parent waits waitpid collects the status 9 Unreaped: a zombie holding a PID table slot Not the memory: the page tables. Which is why a Redis parent holding 10GB pays tens of milliseconds per fork for BGSAVE while it keeps mutating memory, and why that latency spike lands exactly during persistence. Open descriptors survive exec unless they carry FD_CLOEXEC, which is how a library stops a child inheriting its internal sockets. Working directory, umask and signal mask carry over too. An orphan that is still alive gets reparented to init, or to the nearest subreaper, so zombies accumulating in a container point straight at a PID 1 that does not reap.

What interviewers probe next

"What survives exec?" PID, open descriptors unless FD_CLOEXEC, cwd, umask, signal mask. Handlers do not survive; they revert to default.

"How do you clean up zombies?" for a nonblocking reaper, loop on waitpid(-1, ..., WNOHANG) while it returns a positive PID; zero means no exited child is ready and ECHILD means none remain, or fix PID 1 to reap, since the parent owns the corpse and init only helps after the parent exits.

"Why would fork fail on a healthy box?" RLIMIT_NPROC, pids cgroup limit, or ENOMEM from allocation/commit constraints. Verify errno rather than treating free RAM as proof all limits allow fork.

Common mistakes

Saying fork copies all memory eagerly. Copy-on-write is the entire design point and the follow-up questions hang off it.

Claiming exec creates a new process. It re-dresses the existing one; the PID is the tell.

Forgetting that caught signals reset to default across exec, then wondering why a child ignores SIGTERM handling inherited from its parent.

References

Linux fork and inheritance.

That one was free, and so are 18 answers per topic without an account. Signing in doubles that to 28, keeps your bookmarks, and tracks which topics you keep getting wrong.one Google click · no card · nothing to cancel
HOW DID IT GO?
0
UP NEXT ON YOUR JOURNEY
NOTES & DISCUSSION · 0

Nothing here yet. Say how you would answer it.