struct RwLock {
	Mutex     write_mutex;
	Semaphore writer_wait;
	
	enum { MVAL = 1000000 };

	Atomic    count;
	void DecReaders();

	void EnterRead();
	void LeaveRead();
	void EnterWrite();
	void LeaveWrite();

	RwLock() {
		count = MVAL;
	}
};

void RwLock::EnterWrite()
{
	ASSERT(count >= 0);
	LLOG("EnterWrite");
	write_mutex.Enter();
	if(AtomicXAdd(count, -MVAL) > MVAL)
		writer_wait.Wait();
	ASSERT(count >= 0);
}

void RwLock::LeaveWrite()
{
	ASSERT(count >= 0);
	LLOG("LeaveWrite");
	AtomicXAdd(count, MVAL);
	write_mutex.Leave();
	ASSERT(count >= 0);
	LLOG(".LeaveWrite");
}

void RwLock::DecReaders()
{
	ASSERT(count >= 0);
	if(AtomicDec(count) == 0)
		writer_wait.Release();
	ASSERT(count >= 0);
}

void RwLock::EnterRead()
{
	ASSERT(count >= 0);
	LLOG("EnterRead");
	if(AtomicInc(count) < MVAL) {
		DecReaders();
		write_mutex.Enter();
		AtomicInc(count);
		write_mutex.Leave();
	}
	ASSERT(count >= 0);
	LLOG(".EnterRead");
}

void RwLock::LeaveRead()
{
	LLOG("LeaveRead");
	DecReaders();
	LLOG(".LeaveRead");
}
