/**********************************************************************
 
	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	"task.h"
#include	"utils.h"
#include	"lock_level.h"
#include	"pri_level.h"
#include	"init.h"
#include	"u_file.h"
#include	"memory_debug.h"

SEM utils_lock;
SEM utils_lock2;
SEM dummy_lock;
void _calc_ctl_pri(PRI_CTL * target);

void (*upper_layer_lock_tracer)(int *);


SEM ____sem_null;

int
lock_up_test(SEM s)
{
	if ( s.so == 0 )
		return 0;
	return 1;
}

SEM
_i_new_lock(int ll,char * f,int ln)
{
SEM ret;
	ret.so = malloc(sizeof(SEM_ORG));
	ret.so->d_sem = xx_new_lock(ll,f,ln);
	ret.so->pri = 0;
	return ret;
}

void
close_lock(SEM s)
{
	xx_close_lock(s.so->d_sem);
	free(s.so);
}


void
_i_lock_task(SEM s,char* f,int ln)
{
int pri;
	pri = push_pri(PRI_LOCK);
	_lock_task(s.so->d_sem,f,ln);
	s.so->pri = pri;
}

void
_i_unlock_task(SEM s,char* str,char * f,int ln)
{
int pri;
	pri = s.so->pri;
	s.so->pri = 0;
	_unlock_task(s.so->d_sem,str,f,ln);
	change_pri(0,pri);
}


void 
_i_sleep_task(unsigned int key,SEM s,char *file,int line)
{
	if ( s.so == 0 )
		_sleep_task(key,0,file,line);
	else	_sleep_task(key,s.so->d_sem,file,line);
}


void
init_utils()
{
	utils_lock = new_lock(LL_UTILS);
	utils_lock2 = new_lock(LL_UTILS2);
	dummy_lock = new_lock(LL_DUMMY);
	init_blacklist();
	set_sys_param();
}

void
force_scheduling()
{
int pri;
	pri = get_pri(0);
	change_pri(0,pri);
}


int push_pri(int pri)
{
int prev;
	prev = get_pri(0);
	if ( prev < pri )
		change_pri(0,pri);
	return prev;
}

int push_pri_pctl(PRI_CTL * target)
{
	if ( target->ctl_pri < target->base_pri )
		target->ctl_pri = target->base_pri;
	return push_pri(target->ctl_pri);
}



void
_calc_ctl_pri(PRI_CTL * target)
{
int c_pri;
PRI_CTL_THREAD * t;
	c_pri = target->base_pri+1;
	for ( t = target->threads ; t ; t = t->next )
		if ( c_pri < t->pri )
			c_pri = t->pri;
	if ( c_pri == 0 )
		target->ctl_pri = 0;
	else	target->ctl_pri = c_pri-1;
}

void
enter_pri_ctl(PRI_CTL * target,PRI_CTL_THREAD * t)
{
	lock_task(utils_lock2);
	t->pri = get_pri(0);
	t->tid = get_tid();
	t->next = target->threads;
	target->threads = t;
	_calc_ctl_pri(target);
	unlock_task(utils_lock2,"push_pri_ctl");
}

void
exit_pri_ctl(PRI_CTL * target)
{
int tid;
PRI_CTL_THREAD ** tp,* t;
	tid = get_tid();
	lock_task(utils_lock2);
	for ( tp = &target->threads ; *tp ; tp = &(*tp)->next ) {
		t = *tp;
		if ( t->tid != tid )
			continue;
		*tp = t->next;
		break;
	}
	_calc_ctl_pri(target);
	unlock_task(utils_lock2,"push_pri_ctl");
}


