/*
 * wait.c
 *
 * Copyright 2004, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 */


#include<types.h>
#include<proc.h>
#include<lib.h>
#include<lock.h>
#include<interrupt.h>
#include<time.h>
#include<wait.h>


/******************************************************************************************************
 *
 * セマフォウエイト
 *
 *******************************************************************************************************/


//================================== PRIVATE ============================================


/*
 * PROC_LINK構造体アドレスからPROCアドレスを得る。
 */
static inline PROC *waitLinkToProc(PROC_LINK *p)
{
	return (PROC*)((uint)p-(uint)&((PROC*)0)->wait_next);
}


//================================== PUBLIC =============================================


/*
 * parameters : Wait queue
 */
void waitSemaphore(WAIT_QUEUE *queue)
{
	PROC *proc;
	PROC_LINK *p,*wait;


	wait=(PROC_LINK*)&queue->wait_next;

	enter_spinlock(&queue->gate);
	if(queue->update==0)
	{
		queue->update=1;
		wait->next=wait->prev=wait;
		exit_spinlock(&queue->gate);

		return;
	}
	else
	{
		proc=get_current_task();
		p=(PROC_LINK*)&proc->wait_next;

		/* Add process to wait queue */
		p->next=wait;
		p->prev=wait->prev;
		wait->prev->next=p;
		wait->prev=p;

		exit_spinlock(&queue->gate);

		del_from_schedule(TASK_WAIT, PROC_SCHEDULE_DEL);
	}

	wait_task();
}


void wakeSemaphore(WAIT_QUEUE *queue)
{
	PROC_LINK *p,*wait;


	wait=(PROC_LINK*)&queue->wait_next;

	/* Delete process from wait queue */
	enter_spinlock(&queue->gate);
	{
		if(wait->next!=wait)
		{
			p=wait->next;
			wait->next=p->next;
			wait->next->prev=wait;

			/* Add process to schedule */
			add_to_schedule(waitLinkToProc(p), TASK_WAIT, NULL);
		}
		else queue->update=0;
	}
	exit_spinlock(&queue->gate);
}
