/*
 * CLOCK_*_ALARM test
 *
 * Compile with gcc wakeup.c -lrt
 */

#include <sys/select.h>
#include <sys/signalfd.h>

#include <signal.h>
#include <time.h>
#include <errno.h>

#include <stdio.h>


#define SET_TIMER(clock_id, seconds) set_timer(clock_id, clock_id##_ALARM, seconds)


int
set_timer(clockid_t clock_id, clockid_t alarm_clock_id, unsigned seconds)
{
	timer_t timer = {0,};
	struct itimerspec ts = {0,};

	if (timer_create(alarm_clock_id, NULL, &timer) != 0)
	{
		perror("timer_create");
		return -1;
	}

	if (clock_gettime(clock_id, &(ts.it_value)) != 0)
	{
		perror("timer_gettime");
		return -1;
	}

	ts.it_interval.tv_sec = 0;
	ts.it_interval.tv_nsec = 0;
	ts.it_value.tv_sec += seconds;
	ts.it_value.tv_nsec = 0;

	if (timer_settime(timer, 0, &ts, NULL) != 0)
	{
		perror("timer_settime");
		return -1;
	}

	return 0;
}


void
usage(const char *program)
{
	printf("Usage %s mode seconds\n", program);
	printf("Avaiable modes:\n");
	printf("\trelative\n");
	printf("\tabsolute\n");
}

int
main(int argc, char *argv[])
{
	int seconds = 0;
	int fd = -1;
	sigset_t signals;
	struct signalfd_siginfo info = {0,};

	if (argc != 3)
	{
		usage(argv[0]);
		return -1;
	}

	seconds = strtol(argv[2], NULL, 10);

	if (strcmp(argv[1], "relative") == 0)
	{
		if (SET_TIMER(CLOCK_BOOTTIME, seconds) == -1)
			return -1;
	}
	else if (strcmp(argv[1], "absolute") == 0)
	{
		if (SET_TIMER(CLOCK_REALTIME, seconds) == -1)
			return -1;
	}
	else
	{
		usage(argv[0]);
		return -1;
	}


	sigemptyset(&signals);
	sigaddset(&signals, SIGALRM);

	sigprocmask(SIG_BLOCK, &signals, NULL);

	if ((fd = signalfd(-1, &signals, 0)) < 0) {
		perror("signalfd");
		return -1;
	}

	read(fd, &info, sizeof(struct signalfd_siginfo));
	printf("Alarm!\n");

	close(fd);

	return 0;
}
