Loading content...
We've learned that the status integer from wait() and waitpid() is not a simple exit code—it's an encoded bitfield containing multiple pieces of information. POSIX defines a set of status macros that decode this information correctly and portably.
These macros are your essential tools for understanding exactly how a child process ended:
This page provides definitive, exhaustive coverage of every status macro, their semantics, and complete examples for all termination scenarios.
By the end of this page, you will master all POSIX status macros, understand the complete taxonomy of process termination, know how to handle every possible child state (exited, signaled, stopped, continued), and be able to write robust status handling code.
The status macros are defined in <sys/wait.h>. They come in pairs: test macros that return a boolean, and extraction macros that return values. The test macros must be called first—extraction macros are only valid when the corresponding test returns true.
| Macro | Type | Purpose | Valid When |
|---|---|---|---|
WIFEXITED(status) | Test | True if child exited normally (via exit() or return) | Always |
WEXITSTATUS(status) | Extract | Get exit code (0-255) | WIFEXITED() is true |
WIFSIGNALED(status) | Test | True if child was killed by a signal | Always |
WTERMSIG(status) | Extract | Get the signal number that killed the child | WIFSIGNALED() is true |
WCOREDUMP(status) | Test | True if a core dump was generated | WIFSIGNALED() is true |
WIFSTOPPED(status) | Test | True if child is stopped (not terminated) | WUNTRACED was used |
WSTOPSIG(status) | Extract | Get the signal that stopped the child | WIFSTOPPED() is true |
WIFCONTINUED(status) | Test | True if child was continued after stop | WCONTINUED was used |
Important Distinctions:
Terminated vs. Stopped: A terminated process is gone forever. A stopped process is paused and can be continued.
Exited vs. Signaled: Exited means the process called exit(), _exit(), or returned from main(). Signaled means an external signal killed it.
WCOREDUMP is not POSIX: While widely available, WCOREDUMP is not strictly POSIX and may need feature test macros on some systems.
Order of tests matters: Always test WIFEXITED and WIFSIGNALED before WIFSTOPPED, as stopped processes are a special case that requires WUNTRACED.
Never call WEXITSTATUS without first confirming WIFEXITED is true. Never call WTERMSIG without confirming WIFSIGNALED is true. Calling extraction macros when their test returns false yields undefined behavior.
WIFEXITED(status) returns true if the child terminated normally—meaning it called exit(), _exit(), _Exit(), or returned from main(). This is the "clean" termination path.
WEXITSTATUS(status) extracts the exit code passed to exit() or returned from main(). This is an 8-bit value (0-255).
Exit Code Semantics:
| Exit Code | Conventional Meaning | Example |
|---|---|---|
0 | Success — operation completed normally | exit(0); or return 0; |
1 | General failure — something went wrong | exit(1); |
2 | Misuse — incorrect command-line arguments | Invalid flags to CLI tool |
126 | Cannot execute — permission denied | Non-executable script |
127 | Command not found — file doesn't exist | Typo in command name |
255 | Exit code overflow (or explicit 255) | exit(-1); wraps to 255 |
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h> /** * Demonstrates WIFEXITED and WEXITSTATUS */void check_exit_status(int status) { if (WIFEXITED(status)) { int exit_code = WEXITSTATUS(status); printf(" Normal exit with code: %d\n", exit_code); // Interpret common codes switch (exit_code) { case 0: printf(" Meaning: SUCCESS\n"); break; case 1: printf(" Meaning: GENERAL FAILURE\n"); break; case 2: printf(" Meaning: MISUSE (bad arguments)\n"); break; case 126: printf(" Meaning: CANNOT EXECUTE\n"); break; case 127: printf(" Meaning: COMMAND NOT FOUND\n"); break; default: printf(" Meaning: Application-specific error\n"); break; } } else { printf(" NOT a normal exit\n"); }} int main() { int pids[4]; int exits[] = {0, 1, 42, 255}; printf("Testing various exit codes...\n\n"); for (int i = 0; i < 4; i++) { pids[i] = fork(); if (pids[i] == 0) { exit(exits[i]); } } // Also test return from main vs exit() int pid5 = fork(); if (pid5 == 0) { return 100; // Return from main } // Collect all for (int i = 0; i < 5; i++) { int status; pid_t pid = wait(&status); printf("Child %d:\n", pid); check_exit_status(status); printf("\n"); } return 0;} /* * Expected Output (PIDs will vary): * Child 1234: * Normal exit with code: 0 * Meaning: SUCCESS * * Child 1235: * Normal exit with code: 1 * Meaning: GENERAL FAILURE * * Child 1236: * Normal exit with code: 42 * Meaning: Application-specific error * * Child 1237: * Normal exit with code: 255 * Meaning: Application-specific error * * Child 1238: * Normal exit with code: 100 * Meaning: Application-specific error */Key Points:
8-bit truncation: Only the low 8 bits of the exit code are preserved
exit(256); // Becomes 0 (256 & 0xFF = 0)
exit(-1); // Becomes 255 (0xFF)
exit(1000); // Becomes 232 (1000 & 0xFF)
Return from main() equals exit(): Both produce identical status
return 5; // Same as exit(5)
_exit() skips cleanup: _exit() or _Exit() produce the same status as exit(), but skip atexit() handlers and buffer flushing
Stick to exit codes 0-125 for portability. Codes 126+ have conventional meanings. Shells often add 128 to signal numbers when reporting signal deaths. Using codes above 125 can cause confusion with signal-based exits.
WIFSIGNALED(status) returns true if the child was terminated by a signal—meaning it didn't exit voluntarily but was killed by an external or internal signal (SIGSEGV, SIGKILL, SIGTERM, etc.).
WTERMSIG(status) extracts the signal number that caused termination.
WCOREDUMP(status) returns true if the process generated a core dump file (for post-mortem debugging). Note: Not strictly POSIX, but widely available.
Common Termination Signals:
| Signal | Number (typical) | Cause | Core Dump? |
|---|---|---|---|
SIGTERM | 15 | Polite termination request | No |
SIGKILL | 9 | Forceful kill (cannot be caught) | No |
SIGINT | 2 | Ctrl+C interrupt | No |
SIGQUIT | 3 | Ctrl+\ quit | Yes (usually) |
SIGSEGV | 11 | Segmentation fault (invalid memory) | Yes (usually) |
SIGBUS | 7 or 10 | Bus error (memory alignment) | Yes (usually) |
SIGFPE | 8 | Floating point exception | Yes (usually) |
SIGABRT | 6 | abort() called (assertion failure) | Yes (usually) |
SIGPIPE | 13 | Write to broken pipe | No |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <sys/wait.h>#include <string.h> /** * Demonstrates WIFSIGNALED, WTERMSIG, and WCOREDUMP */ const char* signal_name(int sig) { // strsignal() provides a description // For portable code, handle common signals explicitly switch (sig) { case SIGTERM: return "SIGTERM (Termination)"; case SIGKILL: return "SIGKILL (Forced kill)"; case SIGINT: return "SIGINT (Interrupt)"; case SIGQUIT: return "SIGQUIT (Quit)"; case SIGSEGV: return "SIGSEGV (Segmentation fault)"; case SIGBUS: return "SIGBUS (Bus error)"; case SIGFPE: return "SIGFPE (Floating point exception)"; case SIGABRT: return "SIGABRT (Abort)"; case SIGPIPE: return "SIGPIPE (Broken pipe)"; default: return strsignal(sig); }} void check_signal_status(int status) { if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); printf(" Killed by signal: %d (%s)\n", sig, signal_name(sig)); #ifdef WCOREDUMP if (WCOREDUMP(status)) { printf(" Core dump: YES\n"); } else { printf(" Core dump: No\n"); } #else printf(" Core dump: Unknown (WCOREDUMP not available)\n"); #endif // Shell-style exit code printf(" Shell exit code would be: %d\n", 128 + sig); } else { printf(" NOT killed by signal\n"); }} int main() { // Test 1: SIGTERM (external, no core) pid_t pid1 = fork(); if (pid1 == 0) { pause(); // Wait forever _exit(0); } usleep(10000); kill(pid1, SIGTERM); // Test 2: SIGKILL (forceful, no core) pid_t pid2 = fork(); if (pid2 == 0) { pause(); _exit(0); } usleep(10000); kill(pid2, SIGKILL); // Test 3: SIGSEGV (internal crash, usually cores) pid_t pid3 = fork(); if (pid3 == 0) { // Cause a segfault int *p = NULL; *p = 42; _exit(0); } // Test 4: SIGABRT (abort, usually cores) pid_t pid4 = fork(); if (pid4 == 0) { abort(); // Calls raise(SIGABRT) _exit(0); } // Collect all char *test_names[] = {"SIGTERM", "SIGKILL", "SIGSEGV", "SIGABRT"}; for (int i = 0; i < 4; i++) { int status; pid_t pid = wait(&status); printf("\nTest %s (PID %d):\n", test_names[i], pid); check_signal_status(status); } return 0;} /* * Expected Output: * * Test SIGTERM (PID 1234): * Killed by signal: 15 (SIGTERM (Termination)) * Core dump: No * Shell exit code would be: 143 * * Test SIGKILL (PID 1235): * Killed by signal: 9 (SIGKILL (Forced kill)) * Core dump: No * Shell exit code would be: 137 * * Test SIGSEGV (PID 1236): * Killed by signal: 11 (SIGSEGV (Segmentation fault)) * Core dump: YES * Shell exit code would be: 139 * * Test SIGABRT (PID 1237): * Killed by signal: 6 (SIGABRT (Abort)) * Core dump: YES * Shell exit code would be: 134 */Debugging with Core Dumps:
When WCOREDUMP(status) is true, a core dump file was generated. To debug:
# Find the core file (location varies by system)
$ ls -la core.*
# Load in debugger
$ gdb /path/to/program core.12345
(gdb) bt # Show backtrace at crash
(gdb) info registers # Show CPU state at crash
Note on Core Dumps:
Core dumps may be disabled by:
ulimit -c 0 (shell limit)/proc/sys/kernel/core_pattern)Even when WCOREDUMP() returns true, the file might not exist if limits prevent creation.
Signals like SIGSEGV, SIGBUS, SIGFPE usually indicate bugs—the process crashed. Signals like SIGTERM, SIGKILL, SIGINT usually indicate requested termination (user or system). Your error handling should distinguish these cases: a SIGSEGV is a bug to investigate, while a SIGTERM might be normal shutdown.
A stopped process is fundamentally different from a terminated process:
Stopped processes are used for job control—the ability to suspend and resume processes (Ctrl+Z in shells).
WIFSTOPPED(status) returns true if the child is stopped (not terminated). This requires waiting with the WUNTRACED flag.
WSTOPSIG(status) extracts the signal that caused the stop.
Signals That Stop Processes:
| Signal | Number | Cause | Can Be Caught? |
|---|---|---|---|
SIGSTOP | 19 (typically) | Unconditional stop (like SIGKILL for stopping) | No |
SIGTSTP | 20 (typically) | Terminal stop (Ctrl+Z) | Yes |
SIGTTIN | 21 (typically) | Background process tried to read from terminal | Yes |
SIGTTOU | 22 (typically) | Background process tried to write to terminal | Yes |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <sys/wait.h> /** * Demonstrates WIFSTOPPED and WSTOPSIG * * Key: Must use WUNTRACED flag to be notified of stopped children! */ const char* stop_signal_name(int sig) { switch (sig) { case SIGSTOP: return "SIGSTOP (Unconditional stop)"; case SIGTSTP: return "SIGTSTP (Terminal stop)"; case SIGTTIN: return "SIGTTIN (Background read)"; case SIGTTOU: return "SIGTTOU (Background write)"; default: return "Unknown stop signal"; }} void check_all_status(int status) { if (WIFEXITED(status)) { printf(" State: EXITED (normal)\n"); printf(" Exit code: %d\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf(" State: SIGNALED (killed)\n"); printf(" Signal: %d\n", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { int sig = WSTOPSIG(status); printf(" State: STOPPED (not terminated!)\n"); printf(" Stop signal: %d (%s)\n", sig, stop_signal_name(sig)); printf(" Child can be continued with SIGCONT\n"); } else if (WIFCONTINUED(status)) { printf(" State: CONTINUED (was stopped, now running)\n"); } else { printf(" State: UNKNOWN\n"); }} int main() { pid_t child = fork(); if (child == 0) { // Child: will be stopped and continued printf("Child: Running...\n"); for (int i = 0; i < 10; i++) { printf("Child: Iteration %d\n", i); sleep(1); } printf("Child: Exiting normally\n"); exit(0); } printf("Parent: Created child %d\n", child); sleep(2); // Let child run a bit // Stop the child printf("\nParent: Sending SIGSTOP to child...\n"); kill(child, SIGSTOP); // Wait with WUNTRACED to detect stopped state int status; pid_t result = waitpid(child, &status, WUNTRACED); printf("waitpid returned %d:\n", result); check_all_status(status); sleep(2); // Pause while child is stopped // Continue the child printf("\nParent: Sending SIGCONT to child...\n"); kill(child, SIGCONT); // Wait with WCONTINUED to detect continued state result = waitpid(child, &status, WCONTINUED); printf("waitpid returned %d:\n", result); check_all_status(status); // Now wait for final termination printf("\nParent: Waiting for child to exit...\n"); result = waitpid(child, &status, 0); printf("waitpid returned %d:\n", result); check_all_status(status); return 0;} /* * Expected Output: * Parent: Created child 1234 * Child: Running... * Child: Iteration 0 * Child: Iteration 1 * * Parent: Sending SIGSTOP to child... * waitpid returned 1234: * State: STOPPED (not terminated!) * Stop signal: 19 (SIGSTOP (Unconditional stop)) * Child can be continued with SIGCONT * * Parent: Sending SIGCONT to child... * waitpid returned 1234: * State: CONTINUED (was stopped, now running) * Child: Iteration 2 * ... (child continues running) * * Parent: Waiting for child to exit... * Child: Iteration 9 * Child: Exiting normally * waitpid returned 1234: * State: EXITED (normal) * Exit code: 0 */By default, waitpid() only returns for terminated children. To be notified when a child stops, you MUST include WUNTRACED in the options: waitpid(pid, &status, WUNTRACED). Without this flag, stopped children won't cause waitpid() to return.
Job Control Use Case:
Shells implement job control using these primitives:
$ sleep 1000 & # Start in background
[1] 12345
$ fg # Bring to foreground
sleep 1000
^Z # Ctrl+Z sends SIGTSTP
[1]+ Stopped sleep 1000
$ bg # Resume in background (SIGCONT)
[1]+ sleep 1000 &
$ kill %1 # Terminate (SIGTERM)
The shell uses WIFSTOPPED to detect when jobs are suspended and update the prompt accordingly.
WIFCONTINUED(status) returns true if a stopped child has been resumed by SIGCONT. This requires waiting with the WCONTINUED flag.
This is used for complete job control tracking—knowing not just when jobs stop, but also when they resume.
Complete Job State Tracking:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <sys/wait.h>#include <errno.h> /** * Complete job state tracking * * Tracks all states: running, stopped, continued, terminated */ typedef enum { JOB_RUNNING, JOB_STOPPED, JOB_TERMINATED, JOB_FAILED} JobState; typedef struct { pid_t pid; JobState state; int exit_code; int stop_signal; int term_signal;} Job; void update_job_status(Job *job) { int status; pid_t result = waitpid(job->pid, &status, WUNTRACED | WCONTINUED | WNOHANG); if (result == 0) { // No state change return; } if (result < 0) { if (errno == ECHILD) { job->state = JOB_TERMINATED; } return; } if (WIFEXITED(status)) { job->state = JOB_TERMINATED; job->exit_code = WEXITSTATUS(status); printf("[Job %d] Exited with code %d\n", job->pid, job->exit_code); } else if (WIFSIGNALED(status)) { job->state = JOB_FAILED; job->term_signal = WTERMSIG(status); printf("[Job %d] Killed by signal %d\n", job->pid, job->term_signal); } else if (WIFSTOPPED(status)) { job->state = JOB_STOPPED; job->stop_signal = WSTOPSIG(status); printf("[Job %d] Stopped by signal %d\n", job->pid, job->stop_signal); } else if (WIFCONTINUED(status)) { job->state = JOB_RUNNING; printf("[Job %d] Continued\n", job->pid); }} const char* state_name(JobState s) { switch (s) { case JOB_RUNNING: return "Running"; case JOB_STOPPED: return "Stopped"; case JOB_TERMINATED: return "Terminated"; case JOB_FAILED: return "Failed"; default: return "Unknown"; }} int main() { Job job = {0}; job.state = JOB_RUNNING; job.pid = fork(); if (job.pid == 0) { // Simulate a job for (int i = 0; i < 20; i++) { printf("Working... %d\n", i); sleep(1); } exit(0); } printf("Started job %d\n\n", job.pid); sleep(2); // Stop the job printf("Stopping job...\n"); kill(job.pid, SIGSTOP); update_job_status(&job); printf("State: %s\n\n", state_name(job.state)); sleep(2); // Continue the job printf("Continuing job...\n"); kill(job.pid, SIGCONT); update_job_status(&job); printf("State: %s\n\n", state_name(job.state)); sleep(2); // Terminate the job printf("Terminating job...\n"); kill(job.pid, SIGTERM); update_job_status(&job); printf("Final state: %s\n", state_name(job.state)); return 0;}When to Use WCONTINUED:
WCONTINUED is primarily useful for:
Most applications don't need WCONTINUED—it's specialized for job control scenarios.
WCONTINUED was added in POSIX.1-2001 and may not be available on older systems. Check for its presence before using, especially in portable code.
Here's the definitive pattern for handling every possible child status. Use this as your reference implementation:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <signal.h>#include <sys/wait.h>#include <errno.h> /** * Definitive child status handler * * Handles ALL possible outcomes from waitpid(). * Use this as your reference implementation. */ typedef enum { CHILD_EXITED_SUCCESS, // Normal exit, code 0 CHILD_EXITED_FAILURE, // Normal exit, code != 0 CHILD_KILLED_BY_SIGNAL, // Killed by signal (crash or kill) CHILD_STOPPED, // Stopped, can be continued CHILD_CONTINUED, // Was stopped, now running CHILD_UNKNOWN // Unexpected status} ChildOutcome; typedef struct { ChildOutcome outcome; int exit_code; // Valid if EXITED_* int signal_num; // Valid if KILLED or STOPPED int core_dumped; // Valid if KILLED const char *description; // Human-readable description} StatusResult; /** * Comprehensive status decoder * * @param status The status value from wait()/waitpid() * @return Fully decoded status result */StatusResult decode_status(int status) { StatusResult result = {0}; char desc[256]; if (WIFEXITED(status)) { // Child called exit() or returned from main() result.exit_code = WEXITSTATUS(status); if (result.exit_code == 0) { result.outcome = CHILD_EXITED_SUCCESS; snprintf(desc, sizeof(desc), "Exited normally with success (code 0)"); } else { result.outcome = CHILD_EXITED_FAILURE; snprintf(desc, sizeof(desc), "Exited normally with failure (code %d)", result.exit_code); } } else if (WIFSIGNALED(status)) { // Child was killed by a signal result.outcome = CHILD_KILLED_BY_SIGNAL; result.signal_num = WTERMSIG(status); #ifdef WCOREDUMP result.core_dumped = WCOREDUMP(status); #else result.core_dumped = 0; #endif snprintf(desc, sizeof(desc), "Killed by signal %d (%s)%s", result.signal_num, strsignal(result.signal_num), result.core_dumped ? " - core dumped" : ""); } else if (WIFSTOPPED(status)) { // Child was stopped (not terminated) result.outcome = CHILD_STOPPED; result.signal_num = WSTOPSIG(status); snprintf(desc, sizeof(desc), "Stopped by signal %d (%s) - can be continued", result.signal_num, strsignal(result.signal_num)); } else if (WIFCONTINUED(status)) { // Child was continued after being stopped result.outcome = CHILD_CONTINUED; snprintf(desc, sizeof(desc), "Continued after being stopped"); } else { // Should never happen result.outcome = CHILD_UNKNOWN; snprintf(desc, sizeof(desc), "Unknown status: 0x%08X", status); } // Allocate and copy description result.description = strdup(desc); return result;} /** * Wait for any child with full status handling * * @param options waitpid options (WNOHANG, WUNTRACED, WCONTINUED) * @param result Output: decoded status * @return Child PID, 0 (WNOHANG, no change), or -1 (error) */pid_t wait_with_handling(int options, StatusResult *result) { int status; pid_t pid; // Retry on EINTR do { pid = waitpid(-1, &status, options); } while (pid < 0 && errno == EINTR); if (pid <= 0) { // Error or no children changed (WNOHANG) result->outcome = CHILD_UNKNOWN; result->description = (pid == 0) ? "No child ready" : strerror(errno); return pid; } *result = decode_status(status); return pid;} /** * Action recommendations based on outcome */void recommend_action(ChildOutcome outcome) { switch (outcome) { case CHILD_EXITED_SUCCESS: printf(" Action: Process completed successfully. No action needed.\n"); break; case CHILD_EXITED_FAILURE: printf(" Action: Check logs/output for error details.\n"); break; case CHILD_KILLED_BY_SIGNAL: printf(" Action: Investigate crash. Check core dump if available.\n"); printf(" Action: Consider adding signal handlers or fixing bugs.\n"); break; case CHILD_STOPPED: printf(" Action: Process is paused. Send SIGCONT to resume.\n"); break; case CHILD_CONTINUED: printf(" Action: Process resumed. Monitor for completion.\n"); break; default: printf(" Action: Unexpected status. Debug waitpid usage.\n"); }} // Demonstrationint main() { printf("=== Complete Status Handling Demo ===\n\n"); // Create various children pid_t children[4]; // Child 1: Exit success children[0] = fork(); if (children[0] == 0) { exit(0); } // Child 2: Exit failure children[1] = fork(); if (children[1] == 0) { exit(42); } // Child 3: Crash children[2] = fork(); if (children[2] == 0) { int *p = NULL; *p = 1; exit(0); } // Child 4: Will be stopped children[3] = fork(); if (children[3] == 0) { while(1) { sleep(1); } } // Wait for first three for (int i = 0; i < 3; i++) { StatusResult result; pid_t pid = wait_with_handling(0, &result); printf("Child %d (PID %d):\n", i + 1, pid); printf(" Status: %s\n", result.description); recommend_action(result.outcome); printf("\n"); } // Stop child 4 printf("Stopping child 4...\n"); kill(children[3], SIGSTOP); StatusResult result; wait_with_handling(WUNTRACED, &result); printf("Child 4:\n"); printf(" Status: %s\n", result.description); recommend_action(result.outcome); // Clean up kill(children[3], SIGKILL); wait(NULL); return 0;}This page has provided definitive coverage of all POSIX status macros—the essential tools for understanding how child processes terminate.
| Scenario | Test Macro | Extract Macro | waitpid Flag Needed |
|---|---|---|---|
| Normal exit | WIFEXITED | WEXITSTATUS | None |
| Killed by signal | WIFSIGNALED | WTERMSIG | None |
| Core dump | WCOREDUMP | — | None (but check availability) |
| Stopped | WIFSTOPPED | WSTOPSIG | WUNTRACED |
| Continued | WIFCONTINUED | — | WCONTINUED |
Module Complete!
You have now completed the comprehensive study of wait() and waitpid(). You understand:
wait() and waitpid()With this knowledge, you can build robust process management into any Unix/Linux application—from simple scripts to complex servers and process supervisors.
Congratulations! You've mastered the wait() and waitpid() system calls. You now have the complete toolkit for parent-child process synchronization, from basic waiting to complex multi-process management with full status decoding.