//
// 
//	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.
//
//

#if THREAD_DEBUG
#define THREAD_DEBUG_CUR
#endif

extern "C" {

#include	<stdlib.h>
#include	<errno.h>
#include	"memory_debug.h"
#include	"task.h"
#include	"lock_level.h"
#include	"LSimpleThread.h"
#include	"UThread.h"
#include	"save_global.h"
#include	"pri_level.h"
#include	"utils.h"

void* new_block();
void free_block(void * t);
void er_panic(char*);

#define SW_HASH_SIZE	127


D_SEM sw_lock;
SW_HASH * hash[SW_HASH_SIZE];

void
sw_init()
{
	sw_lock = xx_new_lock(LL_SLEEP_WAKEUP,__FILE__,__LINE__);
	for ( int i = 0;  i < SW_HASH_SIZE;  i++ ) {
		hash[i] = NULL;
	}

	SG_TITLE;
	sg("D_SEM",	"sw_lock",	&sw_lock);
	sg("SW_HASH*",	"hash",		&hash);
}

#ifdef THREAD_DEBUG_CUR
struct WAIT_INFO {
	int line;
	char file[256];
	int ticks;
};
#endif

void
_sleep_task(unsigned int key,D_SEM s,char *file,int line)
{
unsigned int kk;
SW_HASH * h;
extern void _unlock_task_f(D_SEM,bool);
int pri;

// SLEEP_WAIT_MORI
	pri = push_pri(PRI_SLEEP_WAIT);

	_lock_task(sw_lock,__FILE__,__LINE__);

	kk = key%SW_HASH_SIZE;
	h = (SW_HASH *)new_block();
	h->key = key;
	h->thread = (THREAD)LThread::GetCurrentThread();
	h->next = hash[kk];
	hash[kk] = h;
	if ( s )
		 _unlock_task_f(s,false);
	_unlock_task_f(sw_lock,false);
	change_pri(0,pri);
#ifdef THREAD_DEBUG_CUR
	WAIT_INFO wait_info;
	wait_info.line = line;
	strcpy(wait_info.file, file);
	wait_info.ticks = TickCount();
	memcpy(LThread::GetCurrentThread()->mWorkArea, &wait_info, sizeof(wait_info));
	extern int td_test;
	if ( td_test && td_test == get_tid() )
		printf("++td_test++ suspended at %s %d\n", file, line);
#endif
	try {
		h->thread->Suspend();
	} catch(...) {
		er_panic("Thread Suspend Failure");
	}

#ifdef THREAD_DEBUG_CUR
	if ( td_test && td_test == get_tid() )
		printf("++td_test++ awaken [%0.2f sec]\n", (TickCount()-wait_info.ticks)/60.0);
#endif
}


void
_wakeup_task(unsigned int key,char *file,int line)
{
unsigned int kk;
SW_HASH *h, *hp = NULL, *hn;
THREAD	thread;
int pri;

	kk = key%SW_HASH_SIZE;

// SLEEP_WAIT_MORI
	pri = push_pri(PRI_SLEEP_WAIT);

	_lock_task(sw_lock,file,line);
	for ( h = hash[kk];  h;  h = hn ) {
		hn = h->next;
		if ( h->key == key ) {
			if (hp)
				hp->next = hn;
			else
				hash[kk] = hn;
			thread = h->thread;
			free_block(h);
			try {
				thread->Resume();
			} catch(...) {
				printf("\a\n\n\n\n thread:%s[tid:%x] state:%d\n\n\n",
					thread->mName, thread, thread->GetState());
				er_panic("Thread Resume Failure\n");
			}
		} else {
			hp = h;
		}
	}
	_unlock_task(sw_lock,"wakeup_task",__FILE__,__LINE__);
	change_pri(0,pri);
} 

} //extern "C"