/*
 * Copyright (C) 1997 by the University of Kansas Center for Research,
 * Inc.  This software was developed by the Information and
 * Telecommunication Technology Center (ITTC) at the University of
 * Kansas.  Partial funding for this project was provided by Sprint. This
 * software may be used and distributed according to the terms of the GNU
 * Public License, incorporated herein by reference.  Neither ITTC nor
 * Sprint accept any liability whatsoever for this product.
 *
 * This project was developed under the direction of Dr. Douglas Niehaus.
 *
 * Authors: Shyam Pather, Balaji Srinivasan 
 *
 * Please send bug-reports/suggestions/comments to posix@ittc.ukans.edu
 *
 * Further details about this project can be obtained at
 *    http://hegel.ittc.ukans.edu/projects/posix/
 */

/* 2timer_test.c
 * 
 * This program demonstrates the use of POSIX.4 interval timers without 
 * queued signals. It simply creates a POSIX.4 interval timer that sends
 * a normal signal when it expires. The handler for this signal prints
 * a message, and increments a count. When the count reaches MAX_EXPIRATIONS,
 * the timer is deleted, and the program exits. 
 */

/* Modified by J. Vidal to test RTLinux POSIX.4 interval timers 22-09-2002 */ 

#include <rtl.h>
#include <rtl_sched.h>
#include <time.h>
#include <signal.h>
#include "utils.h"

#define printf rtl_printf
#define TIMER1_SIGNAL RTL_SIGRTMAX
#define TIMER2_SIGNAL RTL_SIGRTMIN
#define DATA_VAL 17
#define MAX_EXPIRATIONS 10
#define MAX_SIGNALS 30

#define MAXTASKS 10
#define NTASKS 1

struct params {
  clockid_t clock;
  int of1,in1,of2,in2;
} param ;

pthread_t th[MAXTASKS];
int expirations;
timer_t t1, t2;
rtl_sigset_t set;

void *thread_code(void *arg);

#define sigprocmask pthread_sigmask

static void init_param(struct params *p,clockid_t cl,int of1,int in1,int of2,int in2) {
       p->clock=cl;
       p->of1=of1;
       p->in1=in1;
       p->of2=of2;
       p->in2=in2;
}

void timer1_handler(int signo)
{
	printf("handler timer1 expired: signal %d\n",signo);
	expirations++;
}

void timer2_handler(int signo)
{
  printf("handler timer2 expired: signal %d\n",signo);
}


int init_module(void){
	sigevent_t sig1, sig2;
	int i;

	expirations = 0;

#if 0
        printf("Using CLOCK_REALTIME \n");
        init_param(&param,CLOCK_REALTIME,12345678L,20000000L,10000000L,10000000L);
        printf("Using CLOCK_MONOTONIC \n");
        init_param(&param,CLOCK_MONOTONIC,12345678L,20000000L,10000000L,10000000L);
#endif
        printf("Using CLOCK_REALTIME\n");
        init_param(&param,CLOCK_REALTIME,552345678L,20000L,10000000L,16000L);
        
	
	/* 
	 * Set up the signal event that will occur when the timer 
	 * expires. 
	 */	

	sig1.sigev_notify = SIGEV_SIGNAL;
	sig1.sigev_signo = TIMER1_SIGNAL;
	sig1.sigev_value.sival_ptr = &t1;
	
	sig2.sigev_notify = SIGEV_SIGNAL;
	sig2.sigev_signo = TIMER2_SIGNAL;
	sig2.sigev_value.sival_ptr = &t2;
		
	/*
	 * Create and set the timer.
	 */

	timer_create(CLOCK_REALTIME, &sig1, &t1);
	timer_create(CLOCK_REALTIME, &sig2, &t2);


	for (i=0 ; i < NTASKS ; i++)
	  pthread_create(&th[i],NULL,thread_code,(int *) i);

	return 0;
}

void cleanup_module(void){
  int i;
	/* 
	 * Delete the timer.
	 */	
	timer_delete(t1); 
	timer_delete(t2);
	sigprocmask(SIG_UNBLOCK, &set, NULL);

  	for (i=0;i<NTASKS;i++)
	  pthread_delete_np(th[i]);
}


void *thread_code(void *arg){
	struct itimerspec new_setting1, new_setting2, remaining;
	struct sigaction sa;
	int err=0;

	/*
	 * Initialize the timer setting structure.
	 */
	new_setting1.it_value.tv_sec = 0L;
	new_setting1.it_value.tv_nsec = param.of1;
	new_setting1.it_interval.tv_sec = 0L;
	new_setting1.it_interval.tv_nsec = param.in1;
	timespec_normalize(&new_setting1.it_value);
	timespec_normalize(&new_setting1.it_interval);

	new_setting2.it_value.tv_sec = 0L;
	new_setting2.it_value.tv_nsec = param.of2;
	new_setting2.it_interval.tv_sec = 0L;
	new_setting2.it_interval.tv_nsec = param.in2;
	timespec_normalize(&new_setting2.it_value);
	timespec_normalize(&new_setting2.it_interval);

	/* 
	 * Set up and install a signal handler for the signal that 
	 * the timer will send. 
	 */

	sa.sa_handler = timer1_handler;
	sa.sa_flags = 0;

	rtl_sigemptyset(&sa.sa_mask);

	if ((err=sigaction(TIMER1_SIGNAL, &sa, NULL))<0){
	  rtl_printf("Error while sigaction(TIMER1_SIGNAL,..)\n");
	  pthread_exit(NULL);
	}

	sa.sa_handler = timer2_handler;
	sa.sa_flags = 0;

	rtl_sigemptyset(&sa.sa_mask);

	if ((err=sigaction(TIMER2_SIGNAL, &sa, NULL))<0){
	  rtl_printf("Error while sigaction(TIMER2_SIGNAL,..)\n");
	  pthread_exit(NULL);
	}

	rtl_sigemptyset(&set);
	rtl_sigaddset(&set, TIMER1_SIGNAL);
	rtl_sigaddset(&set, TIMER2_SIGNAL);

	sigprocmask(SIG_BLOCK, &set, NULL);

	timer_settime(t1, 0, &new_setting1, NULL); 
	timer_gettime(t1, &remaining);
	printf("timer id %d: it_value=%ld.%09ld, it_interval=%ld.%09ld\n",
               t1->id,
	       remaining.it_value.tv_sec,
	       remaining.it_value.tv_nsec,
	       remaining.it_interval.tv_sec,
	       remaining.it_interval.tv_nsec);
	timer_settime(t2, 0, &new_setting2, NULL); 

	timer_gettime(t2, &remaining);
	printf("timer id %d: it_value=%ld.%09ld, it_interval=%ld.%09ld\n",
               t2->id,
	       remaining.it_value.tv_sec,
	       remaining.it_value.tv_nsec,
	       remaining.it_interval.tv_sec,
	       remaining.it_interval.tv_nsec);

	/* 
	 * Busy wait until the timer expires MAX_EXPIRATIONS number 
	 * of times.
	 */
	rtl_sigfillset(&set);
	rtl_sigdelset(&set, TIMER1_SIGNAL);
	rtl_sigdelset(&set, TIMER2_SIGNAL);
	while ((expirations < MAX_EXPIRATIONS)) {
	  sigsuspend(&set);
	}

	rtl_printf(SETCOLOR_SUCCESS"TEST SUCCESSFULLY PASSED !"SETCOLOR_NORMAL);
	return 0;
}













