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

// mori
int mseq_flag;
int mseq_flag2;

SEM mseq_que_lock;
MS_INFO * ms_info_head[PRI_MAX];
MS_INFO * ms_info_tail[PRI_MAX];
int loop_task_id;

void
init_msequence()
{
int i;

	loop_task_id = get_tid();
	mseq_que_lock = new_lock(LL_MSEQUENCE);
	for ( i = 0; i < PRI_MAX ; i ++ ) {
		ms_info_head[i] = 0;
		ms_info_tail[i] = 0;
	}
	mseq_flag = 1;
}



void
ms_loop()
{
MS_INFO * ms;
int pri;
	mseq_flag2 = 1;
	for ( ; ; ) {
		lock_task(mseq_que_lock);
		for ( pri = PRI_MAX-1 ; pri >= 0 ; pri -- )
			if ( ms_info_head[pri] )
				break;
		if ( pri < 0 ) {
			sleep_task((int)&mseq_que_lock,
				mseq_que_lock);
			continue;
		}
		ms = ms_info_head[pri];
		ms_info_head[pri] = ms->next;
		if ( ms_info_head[pri] == 0 )
			ms_info_tail[pri] = 0;
		unlock_task(mseq_que_lock, "ms_loop");
/*
printf("do1 %s\n",ms->str);
*/
		ms->result = (*ms->func)(ms->arg);
		wakeup_task((int)ms);
/*
printf("do1 %s end\n",ms->str);
*/
	}
}


static void
ms_put_func(MS_INFO * ms)
{
int h;
int pri;

	pri = get_pri(0);
	ms->next = 0;
	if ( ms_info_tail[pri] == 0 ) {
		ms_info_tail[pri] = ms_info_head[pri] = ms;
	}
	else {
		ms_info_tail[pri]->next = ms;
		ms_info_tail[pri] = ms;
	}
}


int
ms_do(int (*func)(), void * arg, char str[])
{
MS_INFO ms;
int ret;
	if ( mseq_flag == 0 ) {
		er_panic("????\n");
		exit(1);
	}
	if ( loop_task_id == get_tid() || mseq_flag2 == 0 )
		return  (*func)(arg);
	ms.func = func;
	ms.arg = arg;
	strcpy(ms.str,str);

	lock_task(mseq_que_lock);
	ms_put_func(&ms);
	wakeup_task((int)&mseq_que_lock);
	sleep_task((int)&ms,mseq_que_lock);

	return ms.result;
}

