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

SEM fork_lock;
int flock_count;
FORK_LOCK_TBL * flock_list;


int tick_func_flag;

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


void
_rlock_fork(FORK_LOCK_TBL * t)
{
	for ( ; flock_count ; ) {
		sleep_task((int)&flock_count,fork_lock);
		lock_task(fork_lock);
	}
	t->next = flock_list;
	t->err = 0;
	t->tid = get_tid();
	flock_list = t;
}


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


void
_wlock_tick()
{
int f;
FORK_LOCK_TBL * t;
	f = 0;
	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 ++;
	}
	if ( f )
		wakeup_task((int)&flock_count);
}

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

void
_wlock_fork()
{
FORK_LOCK_TBL * t;
	flock_count ++;
	for ( t = flock_list ; t ; t = t->next ) {
		t->err = FLE_FORK;
		pthread_kill(get_hard_tid(t->tid),SIGUSR1);
	}
	if ( tick_func_flag == 0 )
		new_tick(wlock_tick,2);
	tick_func_flag = 1;
	for ( ; flock_list ; ) {
		wakeup_task((int)&flock_count);
		sleep_task((int)&flock_count,fork_lock);
		lock_task(fork_lock);
	}
}


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");
}

