/*
 * Copyright (C) 2000 TimeSys Corporation
 *
 * This is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */
/* routines for the threads */
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <rk/rk.h>
#include <rk/rk_error.h>
#include "process.h"

#define NS_PER_MS	1000000

extern long long reservation;
extern long long period;
extern long long era, RKera;
extern int enf_mode, rep_mode;

volatile int running = 0;
static struct timespec spec[MAXTH];
static struct timespec RKamt[MAXTH];
static struct timespec RKperiod[MAXTH];
static rk_resource_set_t rs[MAXTH];
static cpu_reserve_attr_data_t attr[MAXTH];
static rk_reserve_t	cpu_rsv[MAXTH];
static pthread_t th[MAXTH];
static int pID[MAXTH + 1], i;
static char* rs_name[] = {"Larry", "Moe", "Curly"};
static long milla = 2000;
static int check[] = {0, 0, 0, 0, 0, 0};

static void create_cpu_sets(int);
static void thread_routine1();
static void thread_routine2();
static void thread_routine3();
static void thread_routine4();
static void thread_routine5();
static void thread_routine6();

#define	RAJ	1

void create_threads()
{
	doit = 1;
	stopit = 0;
	running = 0;
	for(i = 0; i < MAXTH; i++)
	{
		spec[i].tv_sec  = 0;		
    		spec[i].tv_nsec = 1 * milla;
	}

	pthread_create(&th[0], NULL, (void *)(thread_routine1), 0);
	while(running == 0) {};
	pthread_create(&th[1], NULL, (void *)(thread_routine2), 0);
	while(running == 1) {};
	pthread_create(&th[2], NULL, (void *)(thread_routine3), 0);
	while(running == 2) {};
	pthread_create(&th[3], NULL, (void *)(thread_routine4), 0);
	while(running == 3) {};
	pthread_create(&th[4], NULL, (void *)(thread_routine5), 0);
	while(running == 4) {};
	pthread_create(&th[5], NULL, (void *)(thread_routine6), 0);
	while(running == 5) {};
	g_print("\n\nRESOURCE SETS: %d \n\n", rk_cpu_reserves_get_num());
}

void destroy_threads()
{

	for(i = 0; i < MAXTH; i++)
	{
		pthread_kill(th[i], 0);	
		g_print("Thread %d killed \n", i);
	}
}
void thread_routine1()
{
	pID[1] = getpid();
	g_print("Thread one: %d \n", pID[1]);
	create_cpu_sets(0);
	running++;
	while(running < 2) {};
	while(doit)
	{
		nanosleep(&spec[0], NULL);
		if (xp[0] == right) ch[0] = -1;
		if ((xp[0] == 0) || (xp[0] == (xp[1] + rad))) ch[0] = 1;
		if (xp[1] == 0) ch[1] = 1;
		if ((xp[1] == right) || (xp[0] == (xp[1] + rad))) ch[1] = -1;
		xp[0] += ch[0];
		check[0] = 0;
	}
	rk_resource_set_destroy(rs[0]);
	g_print("Resource set rs[0] destroyed\n");
	stopit++;
}
void thread_routine2()
{
	pID[2] = getpid();
	g_print("Thread two: %d \n", pID[2]);
	create_cpu_sets(1);
	running++;
	while(running < 2) {};
	while(doit)
	{
		nanosleep(&spec[1], NULL);
		if(check[1] == 5)
		{
			if (xp[0] == right) ch[0] = -1;
			if ((xp[0] == 0) || (xp[0] == (xp[1] + rad))) ch[0] = 1;
			if (xp[1] == 0) ch[1] = 1;
			if ((xp[1] == right) || (xp[0] == (xp[1] + rad))) ch[1] = -1;
			xp[1] += ch[1];
			check[1] = 0;
		}
		check[1]++;
	}
	rk_resource_set_destroy(rs[1]);
	g_print("Resource set rs[1] destroyed\n");
	stopit++;
}
void thread_routine3()
{
	
	pID[3] = getpid();
	g_print("Thread three: %d \n", pID[3]);
	create_cpu_sets(2);
	running++;
	while(running < 2) {};
	while(doit)
	{
		nanosleep(&spec[2], NULL);
		if (xp[2] == right) ch[2] = -1;
		if ((xp[2] == 0) || (xp[2] == (xp[3] + rad))) ch[2] = 1;
		if (xp[3] == 0) ch[3] = 1;
		if ((xp[3] == right) || (xp[2] == (xp[3] + rad))) ch[3] = -1;
		xp[2] += ch[2];
		check[2] = 0;
	}

	rk_resource_set_destroy(rs[2]);
	g_print("Resource set rs[2] destroyed\n");
	stopit++;
}
void thread_routine4()
{
	pID[4] = getpid();
	g_print("Thread four: %d \n", pID[4]);
	running++;
	while(doit)
	{
		nanosleep(&spec[3], NULL);
		if (xp[2] == right) ch[2] = -1;
		if ((xp[2] == 0) || (xp[2] == (xp[3] + rad))) ch[2] = 1;
		if (xp[3] == 0) ch[3] = 1;
		if ((xp[3] == right) || (xp[2] == (xp[3] + rad))) ch[3] = -1;
		xp[3] += ch[3];
		check[3] = 0;
	}

}

void thread_routine5()
{
	
	pID[5] = getpid();
	g_print("Thread five: %d \n", pID[5]);
	running++;
	while(doit)
	{
		nanosleep(&spec[4], NULL);
		if (xp[4] == right) ch[4] = -1;
		if ((xp[4] == 0) || (xp[4] == (xp[5] + rad))) ch[4] = 1;
		if (xp[5] == 0) ch[5] = 1;
		if ((xp[5] == right) || (xp[4] == (xp[5] + rad))) ch[5] = -1;
		xp[4] += ch[4];
		check[4] = 0;
	}
}
void thread_routine6()
{
	pID[6] = getpid();
	g_print("Thread six: %d \n", pID[6]);
	running++;
	while(doit)
	{
		nanosleep(&spec[5], NULL);
		if (xp[4] == right) ch[4] = -1;
		if ((xp[4] == 0) || (xp[4] == (xp[5] + rad))) ch[4] = 1;
		if (xp[5] == 0) ch[5] = 1;
		if ((xp[5] == right) || (xp[4] == (xp[5] + rad))) ch[5] = -1;
		xp[5] += ch[5];	
		check[5] = 0;
	}
}



static void create_cpu_sets(int i)
{
	
	int done; 
	pid_t pid;
	
	pid = getpid();
#ifdef RAJ
	g_print("----------------------------\n");	
	if((rs[i] = rk_resource_set_create(rs_name[i])) == NULL)
	{
		g_print("COULD NOT CREATE RESOURCE SET \n");
		g_print("----------------------------\n");
		exit(1);
	}
	else  g_print("created resource set for '%s' (%d)\n", rs_name[i], pid);
	
	if((done = rk_resource_set_attach_process(rs[i], pid)) != 0)
	{
		g_print("COULD NOT ATTACH RESOURCE SET \n");
		g_print("----------------------------\n");
		exit(1);
	}
	else g_print("attached resource set to '%s'(%d)\n", rs_name[i], pid);
#endif RAJ
	

	
	attr[i].start_time.tv_sec = 0;
	attr[i].start_time.tv_nsec = 0;

	attr[i].compute_time.tv_sec = 0;
	attr[i].compute_time.tv_nsec = RKera * reservation;

	attr[i].period.tv_sec = 0;
	attr[i].period.tv_nsec = period;

	attr[i].deadline.tv_sec = 0;
	attr[i].deadline.tv_nsec = period;

	attr[i].blocking_time.tv_sec = 0;
	attr[i].blocking_time.tv_nsec = 0;

	attr[i].reserve_type.enf_mode = rep_mode;
	attr[i].reserve_type.rep_mode = RSV_SOFT;
	attr[i].reserve_type.sch_mode = RSV_SOFT;

#ifdef RAJ
	cpu_rsv[i] = rk_cpu_reserve_create(rs[i], &attr[i]);
#endif RAJ
	
	
	if (cpu_rsv[i] == NULL_RESERVE) g_print("CANNOT CREATE RESERVE FOR PROCESS %d\n", pid);
	else
	{
		 g_print("created reserve for process '%s' (%d)\n", rs_name[i], pid);
		g_print("----------------------------\n");
	}	
	
	

	
	
}

int change_cpu_sets(int res, int per)
{
	
	int tell_me, i;
	if(res != -1)
	{	
		for(i = 0; i < 3; i++)
			attr[i].compute_time.tv_nsec = res * NS_PER_MS;
	}
	if(per != -1)
	{
	    	for(i = 0; i < 3; i++)
	   	{	
			attr[i].period.tv_nsec = per * NS_PER_MS;
			attr[i].deadline.tv_nsec = per * NS_PER_MS;
	   	}
	}
	for(i = 0; i < 3; i++)
		tell_me = rk_cpu_reserve_ctl(rs[i], &attr[i]);
	return(tell_me);
}
	
