/*
 * POSIX.1 timers example program
 *
 * Written by J. Vidal
 * Copyright (C) Dec, 2002 OCERA Consortium.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2.
 *
 * Simple example program implementing huge quantity of recursive calculations.
 * A timer is armed to expire when an amount of time has passed. If the timer doesn't
 * kills the thread a stack overflow will occur.
 *
 */

#include <rtl.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>

pthread_t t2;
timer_t timer;
#define MY_CLOCK CLOCK_REALTIME

struct rec_square { unsigned int square,diff; };
struct rec_square squares(unsigned int n);

static void signal_handler(int signal){
  rtl_printf("Signal handler called for signal %d - BEFORE DIEING\n",signal);
  pthread_exit(NULL);
}

void * t2_routine(void *arg)
{
	struct sched_param p;
	struct sigaction sa;
	rtl_sigset_t set;
	struct itimerspec new_setting;
	int err;
	unsigned int i=0,j,sum=0;

	p . sched_priority = 1;
	pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);

	rtl_sigfillset(&set);
	rtl_sigdelset(&set,RTL_SIGUSR1);
	// Block all thread user signals
	pthread_sigmask(SIG_BLOCK,&set,NULL);

	sa.sa_handler=signal_handler;
	if ((err=sigaction(RTL_SIGUSR1,&sa,NULL))<0 ){
	    rtl_printf("sigaction(RTL_SIGUSR1,&sa,NULL) FAILING, err:%d.\n",err);
	}

	new_setting.it_interval.tv_sec=0;
	new_setting.it_interval.tv_nsec=0;
	new_setting.it_value.tv_sec=0;
	new_setting.it_value.tv_nsec=10*1000*1000;
  
	err=timer_settime(timer,0,&new_setting,NULL);
	rtl_printf("timer_settime(timer,0,&new_setting,&old_setting) returns %d\n",err);
	
	/* o some usefull work. If the timer expiration won't kill
	  those recursive calculations, a stack overflow will occur. */
	while (++i){
	    sum=0;
	    for (j=0;j<= squares(i).square; j++){
	      sum+=squares(j).square;
	    }
	    rtl_printf("Sumatory of all squares until %d is %d\n",squares(i).square,sum);	  
	    usleep(500);
	  }
	
	return 0;
}


int init_module(void) {
    sigevent_t signal; 
    int ret;

    signal.sigev_notify=SIGEV_SIGNAL;
    signal.sigev_signo=RTL_SIGUSR1;
    ret=timer_create(MY_CLOCK,&signal,&timer);
    
    if (!ret) rtl_printf("Timer created succesfully\n");
    else {
      rtl_printf("Error creating timer. errno=%d\n",errno);
      return -1;
    }

    return pthread_create (&t2, NULL, t2_routine, 0);

}

void cleanup_module(void) {
        timer_delete(timer);
	pthread_delete_np (t2);
}


struct rec_square squares(unsigned int n){
    struct rec_square rsquare;

    switch (n) {
	case 0:
	    rsquare.square=0;
	    rsquare.diff=0;
	    break;
	case 1:
	    rsquare.square=1;
	    rsquare.diff=1;
	    break;
	default:
	    rsquare=squares(n-1);
	    rsquare.diff+=2;
	    rsquare.square+=rsquare.diff;
	    break;
  }
    return rsquare;
}
