#define _NIMLIB_
#include<windows.h>
#include<sync.h>
#include<assert.h>
#define LOCK_OPEN 0
#define LOCK_READING 1
#define LOCK_WRITING 2
KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock)
{
pLock->locks = 0;
pLock->status = LOCK_OPEN;
InitializeCriticalSection(&(pLock->cs));
pLock->writewx = CreateEvent(NULL,
FALSE,
TRUE,
NULL);
pLock->readwx = CreateEvent(NULL,
TRUE,
TRUE,
NULL);
}
KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock)
{
EnterCriticalSection(&pLock->cs);
CloseHandle(pLock->readwx);
CloseHandle(pLock->writewx);
pLock->readwx = NULL;
pLock->writewx = NULL;
LeaveCriticalSection(&pLock->cs);
DeleteCriticalSection(&(pLock->cs));
}
KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock)
{
while(1) {
WaitForSingleObject(pLock->readwx, INFINITE);
EnterCriticalSection(&pLock->cs);
if(pLock->status == LOCK_WRITING) {
LeaveCriticalSection(&(pLock->cs));
continue;
} else
break;
}
pLock->locks ++;
pLock->status = LOCK_READING;
ResetEvent(pLock->writewx);
LeaveCriticalSection(&(pLock->cs));
}
KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock)
{
EnterCriticalSection(&(pLock->cs));
assert(pLock->status == LOCK_READING);
pLock->locks--;
if(!pLock->locks) {
pLock->status = LOCK_OPEN;
SetEvent(pLock->readwx);
SetEvent(pLock->writewx);
}
LeaveCriticalSection(&(pLock->cs));
}
KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock)
{
EnterCriticalSection(&(pLock->cs));
if(pLock->status == LOCK_WRITING &&
pLock->writer == GetCurrentThreadId()) {
pLock->locks++;
LeaveCriticalSection(&(pLock->cs));
return;
}
LeaveCriticalSection(&(pLock->cs));
while(1) {
WaitForSingleObject(pLock->writewx, INFINITE);
EnterCriticalSection(&(pLock->cs));
if(pLock->status == LOCK_OPEN)
break;
LeaveCriticalSection(&(pLock->cs));
}
pLock->status = LOCK_WRITING;
pLock->locks++;
pLock->writer = GetCurrentThreadId();
ResetEvent(pLock->readwx);
ResetEvent(pLock->writewx);
LeaveCriticalSection(&(pLock->cs));
}
KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock)
{
EnterCriticalSection(&(pLock->cs));
assert(pLock->status == LOCK_WRITING);
pLock->locks--;
if(!pLock->locks) {
pLock->status = LOCK_OPEN;
pLock->writer = 0;
SetEvent(pLock->readwx);
SetEvent(pLock->writewx);
}
LeaveCriticalSection(&(pLock->cs));
}