/**********************************************************************
 
	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	"utils.h"
#include	"task.h"

extern SEM utils_lock;

void
_waitsync_ack(WAITSYNC_CLIENT * c,WAITSYNC_SERVER * s,int type)
{
WAITSYNC_NODE * n;
	for ( n = c->list ; n ; n = n->client_next ) {
		if ( n->server == s )
			return;
	}
	if ( type == WST_FORCE_STOP )
		s->wait_type = type;
	n = d_alloc(sizeof(*n));
	n->server = s;
	n->client = c;
	n->client_next = c->list;
	c->list = n;
	n->server_next = s->list;
	s->list = n;
	c->count ++;
}

void
_waitsync_wakeup(WAITSYNC_SERVER * s)
{
WAITSYNC_NODE * n, * n2, ** np;
WAITSYNC_CLIENT * c;
	for ( n = s->list ; n ; n = n2 ) {
		n2 = n->server_next;
		c = n->client;
		np = &c->list;
		for ( ; *np && *np != n ; np = &(*np)->client_next );
		if ( *np == 0 )
			er_panic("_waitsync_wakeup");
		*np = n->client_next;
		d_f_ree(n);
		if ( c->list == 0 )
			wakeup_task((int)c);
	}
	s->list = 0;
	s->wait_type = WST_WAIT;
}

void
_waitsync_clear(WAITSYNC_CLIENT * c)
{
WAITSYNC_NODE * n, * n2, ** np;
WAITSYNC_SERVER * s;
	for ( n = c->list ; n ; n = n2 ) {
		n2 = n->client_next;
		s = n->server;
		np = &s->list;
		for ( ; *np && *np != n ; np = &(*np)->server_next );
		if ( *np == 0 )
			er_panic("_waitsync_clear");
		*np = n->server_next;
		d_f_ree(n);
	}
	c->list = 0;
	c->count = 0;
}


int
_waitsync_sleep(WAITSYNC_CLIENT * c)
{
int ret;
	ret = 0;
	for ( ; c->list ; ) {
		sleep_task((int)c,utils_lock);
		lock_task(utils_lock);
		ret = 1;
	}
	return ret;
}


void
waitsync_ack(WAITSYNC_CLIENT * c,WAITSYNC_SERVER * s,int type)
{
	lock_task(utils_lock);
if ( s->list && ((unsigned int)s->list) < 0x1000 )
er_panic("1");
	_waitsync_ack(c,s,type);
if ( s->list && ((unsigned int)s->list) < 0x1000 )
er_panic("1-1");
	unlock_task(utils_lock,"waitsync");
}


void
waitsync_wakeup(WAITSYNC_SERVER * s)
{
	lock_task(utils_lock);
if ( s->list && ((unsigned int)s->list) < 0x1000 )
er_panic("2");
	_waitsync_wakeup(s);
	unlock_task(utils_lock,"waitsync");
}

int
waitsync_sleep(WAITSYNC_CLIENT * c)
{
int ret;
	lock_task(utils_lock);
	ret = _waitsync_sleep(c);
	unlock_task(utils_lock,"waitsync");
	return ret;
}


void
waitsync_clear(WAITSYNC_CLIENT * c)
{
	lock_task(utils_lock);
	_waitsync_clear(c);
	unlock_task(utils_lock,"waitsync");
}

