/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program 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.

**********************************************************************/


#include	"memory_debug.h"
#include	"xl.h"
#include	"gbacrp.h"
#include	"task.h"
#include	"pri_level.h"
#include	"lock_level.h"
#include	"mp.h"
#include	"machine/mp.h"
#include	"gbmp.h"

#define THRESH_HOLD	30

void mp_interval();
void hangup_watchdog();

SEM	tick_que_lock;
unsigned int startup_time;
extern int stab_status;
/*
int * task_flag;
*/
int * task_timer;
TICK_QUE ** task_target;
int * thread_id;
int cpu_nos;
extern int regist_time;
int regist_zero;

void set_idle_interval(float);
void idle_check_task();
int idle_cnt,idle_reset_time;

void
start_task()
{
int cpu;
int interval;

	interval = mp_counter();
	set_idle_interval(0);

	cpu_nos = cpu = sys_param.cpu;

	log_printf(LOG_SYSTEM,"management process (MP) is comming up : status = %c",
			stab_status);

/*
	task_flag = d_alloc((cpu+1)*sizeof(int));
*/
	task_timer = d_alloc((cpu+1)*sizeof(int));
	task_target = d_alloc((cpu+1)*sizeof(TICK_QUE*));
	thread_id = d_alloc((cpu+1)*sizeof(int));

	for ( ; cpu ; cpu -- ) {
/*
		task_flag[cpu] = 0;
*/
		task_timer[cpu] = 0;
		task_target[cpu] = 0;
		create_task(mp_interval,cpu,PRI_FETCH);
	}

	create_task(hangup_watchdog,cpu,PRI_FETCH);
	create_task(idle_check_task,0,PRI_FETCH);

	trace_mapping();
	insert_tick_que(interval*4,0,TQT_MPC,TQL_NORMAL);
	startup_time = get_xltime();

	insert_tick_que(20,0,TQT_LGC,TQL_NORMAL);
}


void
idle_check_task()
{
unsigned int t;
float p;
int check_interval;
extern int idle_interval;
	idle_reset_time = get_xltime();
	idle_cnt = 0;
	check_interval = 10;
	for ( ; ; ) {
		if ( get_xltime() - idle_reset_time
				>= check_interval ) {
			p = (float)idle_cnt 
				/ (get_xltime() - idle_reset_time);
			set_idle_interval(p);
			idle_reset_time = get_xltime();
			idle_cnt = 0;

			check_interval *= 2;
			if ( check_interval > MAPPING_IDLE_CHECK_INTERVAL )
				check_interval = MAPPING_IDLE_CHECK_INTERVAL;
		}
		t = get_comesoon();
/*
printf("idle %i %i\n",t - get_xltime(),idle_interval);
*/
		if ( (t - get_xltime()) >= MAPPING_PING_INTERVAL_UNIT )
			idle_cnt ++;
		sleep_sec(1);
	}
}


int
mp_live()
{

	if ( startup_time == 0 )
		return 0;
	if ( get_xltime() - startup_time < MP_LIVE_MAX )
		return 0;
	lock_task(tick_que_lock);
	cpu_nos --;
	if ( cpu_nos <= 0 ) {
		unlock_task(tick_que_lock,"mp_live");
		exit_stabilizer('r');
		exit(0);
	}
	unlock_task(tick_que_lock,"mp_live");
	return 1;
}

void
hangup_watchdog()
{
int i;
unsigned int t,tt;
XL_INTERPRETER * xli;
TICK_QUE * tq;

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	for ( ; ; ) {
		t = tt = get_xltime();
		tq = 0;
		for ( i = 1 ; i <= cpu_nos ; i ++ ) 
			if ( task_timer[i] && task_timer[i] < t ) {
				t = task_timer[i];
				tq = task_target[i];
			}
		if ( t <= tt - MP_TASK_HANGUP_LIMIT ) {
			gc_push(0,0,"hangup_watchdog");
			log_printf(LOG_DEBUG,"MP hangup!!");
			ss_printf("MP hangup!!");
			if ( tq ) {
				if ( tq->filename )
					log_printf(LOG_DEBUG,
						"n:%s t:%i tid:%i\n",
						n_string(std_cm,tq->filename),
						tq->type,
						get_tid());
				else
					log_printf(LOG_DEBUG,
						"n:0 t:%i tid:%i\n",
						tq->type,
						get_tid());
			}
			gc_pop(0,0);
			exit_stabilizer('r');
{
char buffer[50];
	sprintf(buffer,"gcore %i\n",getpid());
	system(buffer);
}
er_panic("HANGUP");
			exit(1);
		}

		sleep_sec(t + MP_TASK_HANGUP_LIMIT - tt);
	}
}


void
mp_interval(TKEY d)
{
TICK_QUE * t1;
int ses;
XL_INTERPRETER * xli;
int interval;
unsigned int tim;
int cpu;
int i;
int t,now;

	cpu = (int)GET_TKEY(d);

set_cpu_thr_type(cpu);

	thread_id[cpu] = get_tid();
	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);
	for ( ; ; ) {
		set_cpu_msg(0);

		t = get_comesoon();
		now = get_xltime();
		if ( t > 0 ) {
			t = t - now;
			if ( t < -THRESH_HOLD ) {
				if ( now - regist_zero > 5 ) {
					regist_time *= 0.8;
					if ( regist_time == 1 )
						regist_time = 0;
					regist_zero = now;
				}
				if ( regist_time < (-t-THRESH_HOLD)*2 )
					regist_time = (-t-THRESH_HOLD)*2;
			}
			else if ( regist_time > 0 ) {
				if ( now - regist_zero > 5 ) {
					regist_time *= 0.8;
					regist_zero = now;
				}
			}
		}
		else if ( regist_time > 0 ) {
			if ( now - regist_zero > 5 ) {
				regist_time *= 0.8;
				if ( regist_time == 1 )
					regist_time = 0;
				regist_zero = now;
			}
		}



		t1 = 0;

		task_timer[cpu] = 0;
		task_target[cpu] = 0;

		for ( i = 0 ; i < TQL_MAX ; i ++ ) {
			t1 = delete_tick_que(i);
			if ( t1 )
				break;
		}
		set_cpu_msg(1);
		if ( t1 == 0 ) {

			if ( mp_live() )
				return;

			sleep_sec(1);
/*
printf("loop\n");
*/
			continue;
		}
		set_cpu_msg(2);

		task_timer[cpu] = get_xltime();
		task_target[cpu] = t1;

if ( t1->filename )
log_printf(LOG_DEBUG,">>> %s %i %i\n",n_string(std_cm,t1->filename),t1->type,get_tid());
else
log_printf(LOG_DEBUG,">>> %i %i\n",t1->type,get_tid());
/*
if ( t1->filename )
ss_printf(">>> %s %i %i\n",n_string(std_cm,t1->filename),t1->type,get_tid());
else
ss_printf(">>> %i %i\n",t1->type,get_tid());
*/
		gc_push(0,0,"acrp_task");
		switch ( t1->type ) {
		case TQT_CRD:

			tim = get_xltime();
			check_my_acrp(ses,t1->filename);
			tick_lump(t1,tim);
			break;
		case TQT_LMP:
set_cpu_msg(4);
			check_my_lump(ses,t1->filename);
/*
printf("lmp end\n");
*/
			break;
		case TQT_MAP:
set_cpu_msg(5);
			interval = ping_mapping(ses,t1->filename,0);
			if ( interval < 0 )
{log_printf(LOG_DEBUG,"MP: -1 return %s",
n_string(std_cm,t1->filename));
				break;
}
set_cpu_msg(70);
			insert_tick_que(interval,t1->filename,TQT_MAP,
					TQL_NORMAL);
set_cpu_msg(71);
			break;
		case TQT_TMP:
set_cpu_msg(6);
			interval = ping_mapping(ses,t1->filename,1);
			if ( interval >= 0 )
				insert_tick_que(interval,t1->filename,
					TQT_MAP,TQL_NORMAL);
			break;
		case TQT_MPC:
set_cpu_msg(7);
			interval = mp_counter();
			trace_crd_mapping();
			insert_tick_que(interval,0,TQT_MPC,TQL_NORMAL);
			break;
		case TQT_DMAP:
set_cpu_msg(700001);
			ping_mapping(ses,t1->filename,3);
			break;
		case TQT_FMAP:
set_cpu_msg(700002);
			interval = ping_mapping(ses,t1->filename,1);
			if ( interval >= 0 ) {
				insert_tick_que(interval,t1->filename,
					TQT_MAP,TQL_NORMAL);
			}
			break;
		case TQT_LGC:
			interval = get_idle_interval();
			lump_gc_path(ses);
			insert_tick_que(
				interval,
				0,
				TQT_LGC,TQL_NORMAL);
			break;
		default:
			er_panic("mp_interval");
		}
set_cpu_msg(8);
		gc_pop(0,0);
		free_tick_que(t1);
set_cpu_msg(9);
	}
}

void
insert_all_files()
{
int p;
XL_SEXP * file_list;
XL_SEXP * t;
	gc_push(0,0,"insert_all_files");
	file_list = eval(gblisp_top_env1,
		List(get_symbol(l_string(std_cm,"MPrule")),-1));
	switch ( get_type(file_list) ) {
	case XLT_NULL:
		break;
	case XLT_ERROR:
		print_sexp(s_stderr,file_list,0);
		s_printf(s_stderr,"\n");
		er_panic("insert_all_files");
	case XLT_PAIR:
		break;
	default:
		fprintf(stderr,"type missmatch");
		fflush(stderr);
		print_sexp(s_stderr,file_list,0);
		er_panic("insert_all_files(2)");
	}
	for ( ; get_type(file_list) == XLT_PAIR ; file_list = cdr(file_list) ) {
		t = car(file_list);
		if ( get_type(t) != XLT_STRING ) {
			fprintf(stderr,"type missmatch");
			fflush(stderr);
			print_sexp(s_stderr,file_list,0);
			er_panic("insert_all_files(3)");
		}
		insert_tick_que(0,t->string.data,TQT_CRD,TQL_ACRP);
	}
	gc_pop(0,0);
}

