#include #include #include #include #include #include #include "safe_printf.h" /* * This program demonstrates that calling 'printf' (or puts, for that * matter, which is what gcc quietly changes the call to) is not safe * from within a signal handler that's invoked asynchronously (like * SIGCHLD's is). * * Start the program, and you'll see it "get stuck" * after a while. Attach gdb to it (gdb ./signaldeadlock) * "attach " in gdb, where pid is the process id. * * @author Godmar Back * Written for CS 3214 Fall 2009, Virginia Tech * * Updated by Dave O'Hallaron with the safe_printf() function * Fall, 2010 */ #define DEADLOCK 0 #define MAXN 128 static void catch_child(int signo) { #if DEADLOCK /* this call may reenter printf/puts! Bad! */ printf("Child exited!\n"); #else /* This version is async-signal-safe */ safe_printf("Child exited!\n"); #endif /* reap all children */ while (waitpid(-1, NULL, WNOHANG) > 0) continue; } int main() { signal(SIGCHLD, catch_child); int i; for (i = 0; i < 1000000; i++) { if (fork() == 0) exit(0); /* the child is running, it may exit * any time.... SIGCHLD may arrive * while in printf/puts * (this outputs character by character * to increase the chance for the deadlock * to occur so we don't have to wait long.) */ char *p; for (p = "Child started\n"; *p; p++) printf("%c", *p); } return 0; }