外观
csapp/process_demo.c
配套源码,运行方法见同目录 README。返回实验总览。
c
/* Block SIGCHLD before fork, atomically unblock with sigsuspend, reap in main. */
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static volatile sig_atomic_t child_event = 0;
static void on_child(int signo) { (void)signo; child_event = 1; }
static void fail(const char *what) { perror(what); exit(1); }
int main(void) {
sigset_t blocked, oldmask, waitmask;
sigemptyset(&blocked);
sigaddset(&blocked, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &blocked, &oldmask) < 0) fail("sigprocmask");
struct sigaction action = {0};
action.sa_handler = on_child;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &action, NULL) < 0) fail("sigaction");
pid_t pid = fork();
if (pid < 0) fail("fork");
if (pid == 0) {
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) _exit(120);
_exit(42);
}
/* A shell would add pid to its job table here, still with SIGCHLD blocked. */
waitmask = oldmask;
sigdelset(&waitmask, SIGCHLD);
while (!child_event) sigsuspend(&waitmask);
int status;
pid_t got;
do { got = waitpid(pid, &status, 0); } while (got < 0 && errno == EINTR);
if (got < 0) fail("waitpid");
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) fail("restore mask");
assert(WIFEXITED(status) && WEXITSTATUS(status) == 42);
puts("process: child exit=42, reaped without lost wakeup");
return 0;
}