/*
 * 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
 */

#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 "thread.h"








static struct timespec spec[MAXTH];
static struct timespec RKamt[MAXTH];
static struct timespec RKperiod[MAXTH];
static rk_resource_set_t rs[MAXTH];
static int enf_mode = RSV_HARD, rep_mode = RSV_HARD;
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 cpu_reserve_attr_data_t attr[MAXTH];

static void create_cpu_sets(int);
static void thread_routine1();
static void thread_routine2();
static void thread_routine3();


void create_threads()
{
	int i;
	
	for(i = 0; i < 3; i++)	
	  RKera[i] = 1;	
	era = 1;
	milla = 2000000;



	spec[0].tv_sec  = 0;		
    	spec[0].tv_nsec = 1 * milla;
	spec[1].tv_sec  = 0;		
    	spec[1].tv_nsec = 1 * milla;
	spec[2].tv_sec  = 0;		
    	spec[2].tv_nsec = 1 * milla;
	running = 0;
	end_it_all = 1;	
	pthread_create(&th[0], NULL, (void *)(thread_routine1), 0);
	while(running < 1);
	pthread_create(&th[1], NULL, (void *)(thread_routine2), 0);
	while(running < 2);
	pthread_create(&th[2], NULL, (void *)(thread_routine3), 0);
}

void destroy_threads()
{

	for(i = 0; i < 3; i++)
	{
		pthread_kill(th[i], 0);	
		g_print("Thread %d killed \n", i);
	}
	end_it_all = 0;
	
}



static void thread_routine1()
{
	static int pop = 0;
	pID[1] = getpid();
	g_print("Thread one: %d \n", pID[1]);
	create_cpu_sets(0);
	running++;
	while(running != 3) {};
	while(doit)
	{
		int i;	
		nanosleep(&spec[0], NULL);
		if(pop++ == 4)
		{
			xp[0]++;
			pop = 0;
		}
		if(xp[0] == 790) { doit = 0; winner = 0; race_over = 1;}
	}
	cease = 0;
	rk_resource_set_destroy(rs[0]);
	g_print("Resource set rs[0] destroyed\n");
	stopit++;
}

static void thread_routine2()
{
	static int pop = 0;
	pID[2] = getpid();
	g_print("Thread two: %d \n", pID[2]);
	create_cpu_sets(1);
	running++;
	while(running != 3) {};
	while(doit)
	{
		nanosleep(&spec[1], NULL);
		if(pop++ == 4)
		{
			xp[1]++;
			pop = 0;
		}
		if(xp[1] == 790) {doit = 0; winner = 1; race_over = 1;}
	
	}
	cease = 0;
	rk_resource_set_destroy(rs[1]);
	g_print("Resource set rs[1] destroyed\n");
	stopit++;
}
static void thread_routine3()
{
	static int pop = 0;
	pID[3] = getpid();
	g_print("Thread three: %d \n", pID[3]);
	create_cpu_sets(2);
	running++;
	while(running != 3) {};
	while(doit)
	{
		nanosleep(&spec[2], NULL);
		if(pop++ == 4)
		{
			xp[2]++;
			pop = 0;
		}
		if(xp[2] == 790) {doit = 0; winner = 2; race_over = 1;}	
	}
	cease = 0;
	rk_resource_set_destroy(rs[2]);
	g_print("Resource set rs[2] destroyed\n");
	stopit++;
}


static void create_cpu_sets(int i)
{
	
	int done; 
	pid_t pid;
	
	pid = getpid();
	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);
	

	
	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 = 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 = RSV_HARD;
	attr[i].reserve_type.rep_mode = RSV_SOFT;
	attr[i].reserve_type.sch_mode = RSV_SOFT;

	cpu_rsv[i] = rk_cpu_reserve_create(rs[i], &attr[i]);
	
	
	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");
	}	
	
}	


void change_cpu_sets(int i, int jump)
{
	
	int tell_me;
	float total;
	RKera[i] += jump;
	attr[i].compute_time.tv_nsec = RKera[i] * reservation;
	cpu_amt[i] = ((RKera[i] * reservation) / (float)(era * period)) * 100.0;
	total = cpu_amt[0] + cpu_amt[1] + cpu_amt[2]; 
	if(total < 70)
	{
		tell_me = rk_cpu_reserve_ctl(rs[i], &attr[i]);
		g_print("TELL ME... %d \n", tell_me);
	}
	else
	{
		RKera[i] = 1;
		attr[i].compute_time.tv_nsec = RKera[i] * reservation;
		rk_cpu_reserve_ctl(rs[i], &attr[i]);
	}
}