
#include <signal.h> // for signal()
#include <unistd.h> // for alarm()
#include <sys/types.h>  // for wait()
#include <sys/wait.h>  // for wait()
#include <assert.h> // for assert()
#include <iostream> // for cout, cerr and <<
using namespace std;

void
sigchild_handler(int signo)
{
    cout << "sigchild_handler called, my pid = " << getpid() << endl;
    cout << "calling wait() for this child" << endl;
    int child_return_value;
    pid_t child_pid = wait(&child_return_value);
    assert(child_pid > 0);

    cout << "after wait(), child<" << child_pid 
         << "> returned <" << WEXITSTATUS(child_return_value)
         << "> calling exit(0)" << endl;
    exit(0);
}

int 
main()
{
    pid_t child_pid = fork();

    if (child_pid < 0)
    {
        perror("fork() failed");
        exit(1);
    }

    if (child_pid == 0)
    {
        cout << "child is alive, pid = " << getpid() << endl;
        cout << "child is going to sleep" << endl;
        sleep(3);
        cout << "child is calling exit(42)" << endl;
        exit(42);
    }

    cout << "parent after fork(), pid = " << getpid() << endl;


    // if this is commented out, parent completes the following loop
    // if this is NOT commented out, parent recvs signal and exits before
    //    finishing the following loop
    if (signal(SIGCHLD, sigchild_handler) == SIG_ERR)
    {
        perror("call to signal() failed");
        exit(1);
    }

    for (int i = 0; i < 10; i++)
    {
        cout << "parent sleeping # " << i << endl;
        sleep(1);
    }

    int child_return_value;
    pid_t wait_child_pid = wait(&child_return_value);
    assert(wait_child_pid > 0);
    cout << "parent after wait(), child<" << wait_child_pid 
         << "> returned <" << WEXITSTATUS(child_return_value)
         << "> calling exit(0)" << endl;
    exit(0);
}

