#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <math.h>

int cycles = 0;
pid_t child_pid;
pid_t parent_pid;

int
main(int argc, char **argv)
{
    struct sigaction sa;
    sigset_t blockem;
    extern void be_the_parent(), be_the_child();
    extern void parent_terminate(), child_terminate();
    extern void null_handler();

    parent_pid = getpid();
    sigemptyset(&blockem);
    sigaddset(&blockem, SIGUSR1);
    sigprocmask(SIG_BLOCK, &blockem, NULL);

    sigfillset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = parent_terminate;
    if(sigaction(SIGALRM, &sa, NULL)) {
        perror("sigaction SIGALARM");
        exit(1);
    }

    sa.sa_handler = null_handler;
    if(sigaction(SIGUSR1, &sa, NULL) < 0) {
        perror("sigaction SIGUSR1");
        exit(1);
    }

    sa.sa_handler = child_terminate;
    sigfillset(&sa.sa_mask);
    if(sigaction(SIGUSR2, &sa, NULL)) {
        perror("sigaction SIGUSR2");
        exit(1);
    }

    switch(child_pid = fork()) {
        case -1:
            perror("fork");
            exit(2);
            break;
        case 0:
            be_the_child();
            exit(0);
            break;
        default:
            be_the_parent();
            exit(0);
            break;
    }
    fprintf(stderr,"Unexpected exit from program!\n");
    exit(3);
}

void
be_the_parent()
{
    sigset_t sigset;
    double x = 4.0;
    double y = 3.0;
    double z = 8.0;

    sigemptyset(&sigset);
    alarm(5);
    while(1) {
         if(kill(child_pid, SIGUSR1) < 0) {
            perror("kill");
            return;
        }
        if(cycles & 1) {
            x = x * y;
        } else {
            x = x * z;
        }
        cycles++;
        sigsuspend(&sigset);
    }
}

void
be_the_child()
{
    sigset_t sigset;
    double x = 4.0;
    double y = 3.0;
    double z = 8.0;

    sigemptyset(&sigset);
    while(1) {
        sigsuspend(&sigset);
        if(kill(parent_pid, SIGUSR1) < 0) {
            perror("kill");
            return;
        }
        if(cycles & 1) {
            x = x * y;
        } else {
            x = x * z;
        }
        cycles++;
    }
}

void
null_handler() {
    ;
}

void
parent_terminate()
{
    printf("%d multiplications using math library made.\n", cycles);
    kill(child_pid, SIGUSR2);
	wait(NULL);
    exit(0);
}

void
child_terminate()
{
    exit(0);
}

