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

#define SW_HASH_SIZE	100
/*
typedef struct sw_hash {
	struct sw_hash *	next;
	unsigned int		key;
	int			cnt;
	sem_t			sem;
} SW_HASH;
*/
SEM sw_lock;


SW_HASH * sw_hash_table[SW_HASH_SIZE];

void
sw_init()
{
	sw_lock = new_lock(LL_SLEEP_WAKEUP);
}

void
sleep_task(unsigned int key,SEM s)
{
unsigned int kk;
SW_HASH * h;
	kk = key%SW_HASH_SIZE;
	lock_task(sw_lock);
	for ( h = sw_hash_table[kk]; h ; h = h->next )
		if ( h->key == key ) {
			h->cnt ++;
			unlock_task(sw_lock,"sleep_task(1)");
			goto last;
		}
//	unlock_task(sw_lock,"sleep_task(2)");

	h = d_alloc(sizeof(*h));
	h->key = key;
	h->cnt = 1;
	sem_init(&h->sem,0,1);
	sem_trywait(&h->sem);

//	lock_task(sw_lock);
	h->next = sw_hash_table[kk];
	sw_hash_table[kk] = h;
	unlock_task(sw_lock,"sleep_task(3)");
last:
	if ( s )
		unlock_task(s,"sleep_task(4)");

	sem_wait(&h->sem);

	lock_task(sw_lock);

	h->cnt --;
	if ( h->cnt == 0 ) {
		sem_destroy(&h->sem);
		d_f_ree(h);
	}
	unlock_task(sw_lock,"sleep_task(5)");
	return;
}

void
wakeup_task(unsigned int key)
{
unsigned int kk;
int i;
SW_HASH * h, ** hp;
	kk = key%SW_HASH_SIZE;
	lock_task(sw_lock);
	for ( hp = &sw_hash_table[kk] ; *hp ; hp = &(*hp)->next )
		if ( (*hp)->key == key )
			goto next;
	unlock_task(sw_lock,"wakeup_task(1)");
	return;
next:
	h = *hp;
	*hp = h->next;
	for ( i = h->cnt ; i ; i -- )
		sem_post(&h->sem);
	unlock_task(sw_lock,"wakeup_task(2)");
}

#ifdef WIN32

int sleep(int n)
{
	Sleep(n*1000);
	return 0;
}

int usleep(int n)
{
	Sleep(n);
	return 0;
}

#endif
