/*
 *    Filename: signal.c
 * Description: 시그널 관련 함수.
 *
 *      Author: 비엽 aka. Cronan
 */
#define __LIBTHECORE__
#include "stdafx.h"

#ifdef __WIN32__
void signal_setup() {}
void signal_timer_disable() {}
void signal_timer_enable(int timeout_seconds) {}
/* ### LINUX-BLOCK-BEGIN (signal.c) ###################################### */
/* Linux shares this implementation with FreeBSD verbatim: waitpid(2),
 * signal(2), setitimer(ITIMER_VIRTUAL) and every signal number used below are
 * plain POSIX and behave identically on both.  Without adding __linux__ to
 * this branch the entire translation unit compiles to nothing on Linux, and
 * game/src/main.cpp and db/src/Main.cpp fail to link with undefined references
 * to signal_setup() / signal_timer_enable() / signal_timer_disable() (all three
 * are declared in ../include/signal.h).  The SIGCHLD reap()/waitpid() handler
 * that stops zombie children from accumulating lives here too.
 *
 * The original directive was "#elif __FreeBSD__"; adding __linux__ to it does
 * not change which code FreeBSD compiles.
 * ---------------------------------------------------------------------- */
#elif defined(__FreeBSD__) || defined(__linux__)
/* ### LINUX-BLOCK-END (signal.c) ######################################## */
#define RETSIGTYPE void

RETSIGTYPE reap(int sig)
{
    while (waitpid(-1, NULL, WNOHANG) > 0);
    signal(SIGCHLD, reap);
}


RETSIGTYPE checkpointing(int sig)
{
    if (!tics)
    {
	sys_err("CHECKPOINT shutdown: tics did not updated.");
	abort();
    }
    else
	tics = 0;
}


RETSIGTYPE hupsig(int sig)
{
    shutdowned = TRUE;
    sys_err("SIGHUP, SIGINT, SIGTERM signal has been received. shutting down.");
}

RETSIGTYPE usrsig(int sig)
{
    core_dump();
}

void signal_timer_disable(void)
{
    struct itimerval itime;
    struct timeval interval;

    interval.tv_sec	= 0;
    interval.tv_usec	= 0;

    itime.it_interval = interval;
    itime.it_value = interval;

    setitimer(ITIMER_VIRTUAL, &itime, NULL);
}

void signal_timer_enable(int sec)
{
    struct itimerval itime;
    struct timeval interval;

    interval.tv_sec	= sec;
    interval.tv_usec	= 0;

    itime.it_interval = interval;
    itime.it_value = interval;

    setitimer(ITIMER_VIRTUAL, &itime, NULL);
}

void signal_setup(void)
{
    signal_timer_enable(30);

    signal(SIGVTALRM, checkpointing);

    /* just to be on the safe side: */
    signal(SIGHUP, hupsig);
    signal(SIGCHLD, reap);
    signal(SIGINT, hupsig);
    signal(SIGTERM, hupsig);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGALRM, SIG_IGN);
    signal(SIGUSR1, usrsig);
}

#endif
