/**********************************************************************
 
	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	<signal.h>
#include	"task.h"
#include	"utils.h"
#include	"pri_level.h"
#include	"lock_level.h"
#include	"machine/fork_lock.h"

SEM fork_lock;
int flock_count;
FORK_LOCK_TBL * flock_list;
unsigned int tick_wakeup_time1,tick_wakeup_time2,wlock_sleep_time;

int tick_func_flag;

void
init_fork_lock()
{
	fork_lock = new_lock(LL_FORK);
}


static void
_rlock_fork(FORK_LOCK_TBL * t)
{
	if ( t == 0 )
		er_panic("_rlock_fork");
	for ( ; flock_count ; ) {
/*
		sleep_task((int)&flock_count,fork_lock);
		lock_task(fork_lock);
*/
		unlock_task(fork_lock,"loop");
		sleep_sec(1);
		lock_task(fork_lock);

	}
	t->next = flock_list;
	t->err = 0;
	t->tid = get_tid();
	flock_list = t;
}


static void
_runlock_fork(FORK_LOCK_TBL * t)
{
FORK_LOCK_TBL ** tp;
	for ( tp = &flock_list ; *tp && *tp != t ; tp = &(*tp)->next );
	if ( *tp == 0 )
		er_panic("_runlock_fork");
	*tp = t->next;
	wakeup_task((int)&flock_count);
}


static void
_wlock_tick()
{
int f;
FORK_LOCK_TBL * t;
	f = 0;
	if ( flock_count ) {
		for ( t = flock_list ; t ; t = t->next ) {
			t->err = FLE_FORK;
/*
			pthread_kill(get_hard_tid(t->tid),SIGUSR1);
*/
			throw_signal(t->tid,SIGUSR1);
			f ++;
		}
tick_wakeup_time1 = get_xltime();
		wakeup_task((int)&flock_count);
//		send_sw_trigger((int)&flock_count);
	}

}

void
wlock_tick()
{
	lock_task(fork_lock);
	_wlock_tick();
	unlock_task(fork_lock,"wlock_tick");
}

void
wlock_tick_task()
{
	for ( ; ; ) {
		wlock_tick();
		sleep_sec(2);
tick_wakeup_time2 = get_xltime();
	}
}


static void
_wlock_fork()
{
FORK_LOCK_TBL * t;
	flock_count ++;
	for ( t = flock_list ; t ; t = t->next ) {
		t->err = FLE_FORK;
/*
		pthread_kill((pthread_t)get_hard_tid(t->tid),SIGUSR1);
*/
		throw_signal(t->tid,SIGUSR1);
	}
	if ( tick_func_flag == 0 )
		create_task(wlock_tick_task,0,PRI_FETCH);
	tick_func_flag = 1;
	for ( ; flock_list ; ) {
		wakeup_task((int)&flock_count);
wlock_sleep_time = get_xltime();
/*
		sleep_task((int)&flock_count,fork_lock);
		lock_task(fork_lock);
*/
		unlock_task(fork_lock,"loop");
		sleep_sec(1);
		lock_task(fork_lock);

	}
}


static void
_wunlock_fork()
{
	flock_count --;
	wakeup_task((int)&flock_count);
}

void
x_rlock_fork(FORK_LOCK_TBL * t)
{
	lock_task(fork_lock);
	_rlock_fork(t);
	unlock_task(fork_lock,"fork_lock");
}

void
x_runlock_fork(FORK_LOCK_TBL * t)
{
	lock_task(fork_lock);
	_runlock_fork(t);
	unlock_task(fork_lock,"fork_lock");
}

void
x_wlock_fork()
{
	lock_task(fork_lock);
	_wlock_fork();
	unlock_task(fork_lock,"fork_lock");
}

void
x_wunlock_fork()
{
	lock_task(fork_lock);
	_wunlock_fork();
	unlock_task(fork_lock,"fork_lock");
}

