/* $Header: lock.c,v 1.1 87/03/11 15:58:49 mikew Exp $ */
/* $Source: /afs/andrew.cmu.edu/usr7/kazar/afs/lwp/RCS/lock.c,v $ */

#ifndef lint
static char *rcsid = "$Header: lock.c,v 1.1 87/03/11 15:58:49 mikew Exp $";
#endif

/*
 * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1987
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */

/*******************************************************************\
* 								    *
* 	Information Technology Center				    *
* 	Carnegie-Mellon University				    *
* 								    *
* 								    *
* 								    *
\*******************************************************************/


/*
	Locking routines for Vice.

*/

#include "lwp.h"
#include "lock.h"

#define FALSE	0
#define TRUE	1

Lock_Init(lock)
    register struct Lock *lock;
{
    lock -> readers_reading = 0;
    lock -> excl_locked = 0;
    lock -> wait_states = 0;
    lock -> num_waiting = 0;
}

Lock_Obtain(lock, how)
    register struct Lock *lock;
    int how;
{
    switch (how) {

	case READ_LOCK:		lock->num_waiting++;
				do {
				    lock -> wait_states |= READ_LOCK;
				    LWP_WaitProcess(&lock->readers_reading);
				} while (lock->excl_locked & WRITE_LOCK);
				lock->num_waiting--;
				lock->readers_reading++;
				break;

	case WRITE_LOCK:	lock->num_waiting++;
				do {
				    lock -> wait_states |= WRITE_LOCK;
				    LWP_WaitProcess(&lock->excl_locked);
				} while (lock->excl_locked || lock->readers_reading);
				lock->num_waiting--;
				lock->excl_locked = WRITE_LOCK;
				break;

	case SHARED_LOCK:	lock->num_waiting++;
				do {
				    lock->wait_states |= SHARED_LOCK;
				    LWP_WaitProcess(&lock->excl_locked);
				} while (lock->excl_locked);
				lock->num_waiting--;
				lock->excl_locked = SHARED_LOCK;
				break;

	case BOOSTED_LOCK:	lock->num_waiting++;
				do {
				    lock->wait_states |= WRITE_LOCK;
				    LWP_WaitProcess(&lock->excl_locked);
				} while (lock->readers_reading);
				lock->num_waiting--;
				lock->excl_locked = WRITE_LOCK;
				break;

	default:		printf("Can't happen, bad LOCK type: %d\n", how);
				abort();
    }
}

/* release a lock, giving preference to new readers */
Lock_ReleaseR(lock)
    register struct Lock *lock;
{
    if (lock->wait_states & READ_LOCK) {
	lock->wait_states &= ~READ_LOCK;
	LWP_NoYieldSignal(&lock->readers_reading);
    }
    else {
	lock->wait_states &= ~EXCL_LOCKS;
	LWP_NoYieldSignal(&lock->excl_locked);
    }
}

/* release a lock, giving preference to new writers */
Lock_ReleaseW(lock)
    register struct Lock *lock;
{
    if (lock->wait_states & EXCL_LOCKS) {
	lock->wait_states &= ~EXCL_LOCKS;
	LWP_NoYieldSignal(&lock->excl_locked);
    }
    else {
	lock->wait_states &= ~READ_LOCK;
	LWP_NoYieldSignal(&lock->readers_reading);
    }
}

