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


#include <lock.h>


/*
 * 割り込み禁止処理。
 */
// eflagsを保存して割り込み禁止にする。
void enterCli(int *eflag)
{
	asm volatile(
		"pushfl\n"
		"popl	%%eax\n"
		"movl	%%eax,(%%edx)\n"
		"cli"
		::"d"(eflag)
	);
}

// 保存していたeflagsを戻す。
void exitCli(int *eflag)
{
	asm volatile(
		"movl	(%%edx),%%eax\n"
		"pushl	%%eax\n"
		"popfl"
		::"d"(eflag)
	);
}


/*
 * 更新処理の間だけ参照処理をロックするし、参照中は更新処理をロックする。
 */
// 更新処理のロック
void lockModify(MODIFY_LOCK *modifyLock)
{
	enter_spinlock(&modifyLock->gate);
	{
		// 更新中の設定
		for (;;){
			if (modifyLock->count == 0){
				modifyLock->count = UINT_MAX;
				break;
			}
		}
	}
	exit_spinlock(&modifyLock->gate);
}

// 更新処理のロック解除
void unlockModify(MODIFY_LOCK *modifyLock)
{
	modifyLock->count = 0;
}

// 参照処理のカウントアップ
void countUpModify(MODIFY_LOCK *modifyLock)
{
	enter_spinlock(&modifyLock->gate);
	{
		// 参照カウントアップ
		for (;;){
			if (modifyLock->count != UINT_MAX){
				++modifyLock->count;
				break;
			}
		}
	}
	exit_spinlock(&modifyLock->gate);
}

// 参照処理のカウントダウン
void countDownModify(MODIFY_LOCK *modifyLock)
{
	--modifyLock->count;
}
