#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "csapp.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 <pid>" in gdb,
 * where pid is the process id.
 *
 * @author Godmar Back <godmar@gmail.com>
 * Written for CS 3214 Fall 2009, Virginia Tech
 *
 * Updated by Dave O'Hallaron to use the sio functions
 * Fall, 2015
 */
#define DEADLOCK 1

#define MAXN 128

static void
catch_child(int signo)
{
#if DEADLOCK
    /* this call may reenter printf/puts! Bad! */
    puts("Child exited!\n");
#else
    /* This version is async-signal-safe */
    sio_puts("Child exited!\n");
#endif

    /* reap all children */
    while (waitpid(-1, NULL, WNOHANG) > 0)
        continue;
}

int
main(void)
{
    struct sigaction sa;

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = catch_child;
    if (sigaction(SIGCHLD, &sa, 0) != 0)
      unix_error("signal error");

    long i, j;
    for (i = 0; i < 1000000; i++) {
        if (fork() == 0)
            exit(0);

#if DEADLOCK
        puts("Child started\n");
#else
        sio_puts("Child started\n");
#endif

        for (j=0; j<10; j++) {
#if DEADLOCK
            /* Make each printf does a lot of work */
            char buf[128];
            sprintf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld ",
                    i, i, i, i, i, i, i, i);
            puts(buf);
#else
            sio_putl(i);
            sio_putl(i);
            sio_putl(i);
            sio_putl(i);
            sio_putl(i);
            sio_putl(i);
            sio_putl(i);
            sio_putl(i);
#endif
        }
    }
    return 0;
}
