#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <values.h>
#include "../../include/rt_fix.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;
    rt_fix x = rt_fix_0, y = rt_fix_0;
	rt_fix z = rt_fix_1;

    sigemptyset(&sigset);
    alarm(5);
    while(1) {
         if(kill(child_pid, SIGUSR1) < 0) {
            perror("kill");
            return;
        }
        rt_fix_init_i(&y, (int) (65536 * ((double) rand() / (double) RAND_MAX)));
        if(cycles & 1) {
            x = rt_fix_log2(y);
        } else {
            x = rt_fix_log2(rt_fix_div(z, y));
        }
        cycles++;
        sigsuspend(&sigset);
    }
}

void
be_the_child()
{
    sigset_t sigset;
    rt_fix x = rt_fix_0, y = rt_fix_0;
	rt_fix z = rt_fix_1;

    rt_fix_init_i(&z, 1);
    sigemptyset(&sigset);
    while(1) {
        sigsuspend(&sigset);
        if(kill(parent_pid, SIGUSR1) < 0) {
            perror("kill");
            return;
        }
        rt_fix_init_i(&y, (int) (65536 * ((double) rand() / (double) RAND_MAX)));
        if(cycles & 1) {
            x = rt_fix_log2(y);
        } else {
            x = rt_fix_log2(rt_fix_div(z, y));
        }
        cycles++;
    }
}

void
null_handler() {
    ;
}

void
parent_terminate()
{
    printf("%d log2(x) (logarithm to the base of two) calculations using rt_fix library made.\n", cycles);
    kill(child_pid, SIGUSR2);
	wait(NULL);
    exit(0);
}

void
child_terminate()
{
    exit(0);
}

