428 lines
11 KiB
C
428 lines
11 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000, Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
The file contains the READ_WRITE_LOCK definition which allows
|
||
|
multiple-reader/single-writer. This implementation DOES NOT
|
||
|
starve a thread trying to acquire write accesss if there are
|
||
|
a large number of threads interested in acquiring read access.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
mohitt, sachins, Apr 23 2000, Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "pcheapol.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: CreateReadWriteLock
|
||
|
//
|
||
|
// Initializes a multiple-reader/single-writer lock object
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DWORD
|
||
|
CreateReadWriteLock(
|
||
|
PREAD_WRITE_LOCK pRWL,
|
||
|
PCHAR szName
|
||
|
)
|
||
|
{
|
||
|
|
||
|
sprintf(pRWL->RWL_Name, "%.3s", szName);
|
||
|
|
||
|
pRWL->RWL_ReaderCount = 0;
|
||
|
|
||
|
__try {
|
||
|
InitializeCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
pRWL->RWL_ReaderDoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||
|
if (pRWL->RWL_ReaderDoneEvent != NULL) {
|
||
|
return GetLastError();
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: DeleteReadWriteLock
|
||
|
//
|
||
|
// Frees resources used by a multiple-reader/single-writer lock object
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
DeleteReadWriteLock(
|
||
|
PREAD_WRITE_LOCK pRWL
|
||
|
)
|
||
|
{
|
||
|
|
||
|
CloseHandle(pRWL->RWL_ReaderDoneEvent);
|
||
|
pRWL->RWL_ReaderDoneEvent = NULL;
|
||
|
DeleteCriticalSection(&pRWL->RWL_ReadWriteBlock);
|
||
|
pRWL->RWL_ReaderCount = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: AcquireReadLock
|
||
|
//
|
||
|
// Secures shared ownership of the lock object for the caller.
|
||
|
//
|
||
|
// readers enter the read-write critical section, increment the count,
|
||
|
// and leave the critical section
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
AcquireReadLock(
|
||
|
PREAD_WRITE_LOCK pRWL
|
||
|
)
|
||
|
{
|
||
|
|
||
|
EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
|
||
|
InterlockedIncrement(&pRWL->RWL_ReaderCount);
|
||
|
LeaveCriticalSection(&pRWL->RWL_ReadWriteBlock);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: ReleaseReadLock
|
||
|
//
|
||
|
// Relinquishes shared ownership of the lock object.
|
||
|
//
|
||
|
// the last reader sets the event to wake any waiting writers
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
ReleaseReadLock(
|
||
|
PREAD_WRITE_LOCK pRWL
|
||
|
)
|
||
|
{
|
||
|
|
||
|
if (InterlockedDecrement(&pRWL->RWL_ReaderCount) < 0) {
|
||
|
SetEvent(pRWL->RWL_ReaderDoneEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: AcquireWriteLock
|
||
|
//
|
||
|
// Secures exclusive ownership of the lock object.
|
||
|
//
|
||
|
// the writer blocks other threads by entering the ReadWriteBlock section,
|
||
|
// and then waits for any thread(s) owning the lock to finish
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
AcquireWriteLock(
|
||
|
PREAD_WRITE_LOCK pRWL
|
||
|
)
|
||
|
{
|
||
|
|
||
|
EnterCriticalSection(&pRWL->RWL_ReadWriteBlock);
|
||
|
if (InterlockedDecrement(&pRWL->RWL_ReaderCount) >= 0) {
|
||
|
WaitForSingleObject(pRWL->RWL_ReaderDoneEvent, INFINITE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Function: ReleaseWriteLock
|
||
|
//
|
||
|
// Relinquishes exclusive ownership of the lock object.
|
||
|
//
|
||
|
// the writer releases the lock by setting the count to zero
|
||
|
// and then leaving the ReadWriteBlock critical section
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
ReleaseWriteLock(
|
||
|
PREAD_WRITE_LOCK pRWL
|
||
|
)
|
||
|
{
|
||
|
|
||
|
InterlockedIncrement(&pRWL->RWL_ReaderCount);
|
||
|
LeaveCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// InitializeDynamicLocksStore
|
||
|
//
|
||
|
// Initialize the structure from which dynamic readwrite locks are allocated.
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DWORD
|
||
|
InitializeDynamicLocksStore (
|
||
|
PDYNAMIC_LOCKS_STORE pStore,
|
||
|
HANDLE hHeap,
|
||
|
PCHAR szName
|
||
|
)
|
||
|
{
|
||
|
|
||
|
sprintf(pStore->szName, "%.3s", szName);
|
||
|
|
||
|
// initialize the heap from where dynamic locks are allocated
|
||
|
pStore->hHeap = hHeap;
|
||
|
|
||
|
INITIALIZE_LOCKED_LIST(&pStore->llFreeLocksList, szName);
|
||
|
if (!LOCKED_LIST_INITIALIZED(&pStore->llFreeLocksList))
|
||
|
return GetLastError();
|
||
|
|
||
|
// initialize the count of the number of free and allocated locks
|
||
|
pStore->ulCountAllocated = pStore->ulCountFree = 0;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// DeInitializeDynamicLocksStore
|
||
|
//
|
||
|
// Fail if any allocated locks have not been freed.
|
||
|
// Delete the free locks and the FreeLocksList.
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DWORD
|
||
|
DeInitializeDynamicLocksStore (
|
||
|
PDYNAMIC_LOCKS_STORE pStore
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PDYNAMIC_READWRITE_LOCK pLock;
|
||
|
PLIST_ENTRY pleHead, ple;
|
||
|
|
||
|
// can't complete if any locks are still allocated!!!
|
||
|
if (pStore->ulCountAllocated)
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
|
||
|
// deinitialize the count of the number of free and allocated locks
|
||
|
pStore->ulCountAllocated = pStore->ulCountFree = 0;
|
||
|
|
||
|
// deinitialize the FreeLocksList
|
||
|
pStore->llFreeLocksList.created = 0;
|
||
|
|
||
|
// delete all dynamic readwrite locks and free the memory.
|
||
|
pleHead = &(pStore->llFreeLocksList.head);
|
||
|
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
|
||
|
{
|
||
|
pLock = CONTAINING_RECORD(ple, DYNAMIC_READWRITE_LOCK, leLink);
|
||
|
DELETE_READ_WRITE_LOCK(&pLock->rwlLock);
|
||
|
HeapFree(pStore->hHeap, 0, pLock);
|
||
|
}
|
||
|
|
||
|
DeleteCriticalSection(&(pStore->llFreeLocksList.lock));
|
||
|
|
||
|
// deinitialize the heap from where dynamic locks are allocated
|
||
|
pStore->hHeap = NULL;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// GetDynamicReadwriteLock
|
||
|
//
|
||
|
// Return a free dynamic readwrite lock, if one is available.
|
||
|
// Else allocate a new dynamic readwrite lock.
|
||
|
// Assumes pStore->llFreeLocksList is locked.
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
PDYNAMIC_READWRITE_LOCK
|
||
|
GetDynamicReadwriteLock (
|
||
|
PDYNAMIC_LOCKS_STORE pStore
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PDYNAMIC_READWRITE_LOCK pLock;
|
||
|
PLIST_ENTRY pleHead, ple;
|
||
|
|
||
|
do // breakout loop
|
||
|
{
|
||
|
// a free dynamic lock is available. Return it
|
||
|
pleHead = &(pStore->llFreeLocksList.head);
|
||
|
if (!IsListEmpty(pleHead))
|
||
|
{
|
||
|
pStore->ulCountFree--;
|
||
|
ple = RemoveHeadList(pleHead);
|
||
|
pLock = CONTAINING_RECORD(ple, DYNAMIC_READWRITE_LOCK, leLink);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// allocate memory for a new dynamic lock
|
||
|
pLock = HeapAlloc(pStore->hHeap, 0, sizeof(DYNAMIC_READWRITE_LOCK));
|
||
|
if (pLock == NULL)
|
||
|
break;
|
||
|
|
||
|
// initialize the fields
|
||
|
CREATE_READ_WRITE_LOCK(&(pLock->rwlLock), pStore->szName);
|
||
|
if (!READ_WRITE_LOCK_CREATED(&(pLock->rwlLock)))
|
||
|
{
|
||
|
HeapFree(pStore->hHeap, 0, pLock);
|
||
|
pLock = NULL;
|
||
|
break;
|
||
|
}
|
||
|
} while (FALSE);
|
||
|
|
||
|
if (pLock != NULL)
|
||
|
{
|
||
|
pStore->ulCountAllocated++;
|
||
|
pLock->ulCount = 0;
|
||
|
}
|
||
|
|
||
|
return pLock;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// FreeDynamicReadwriteLock
|
||
|
//
|
||
|
// Accepts a released dynamic readwrite lock.
|
||
|
// Frees it if there are too many dynamic readwrite locks.
|
||
|
// Assumes pStore->llFreeLocksList is locked.
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
FreeDynamicReadwriteLock (
|
||
|
PDYNAMIC_READWRITE_LOCK pLock,
|
||
|
PDYNAMIC_LOCKS_STORE pStore
|
||
|
)
|
||
|
{
|
||
|
|
||
|
PLIST_ENTRY pleHead;
|
||
|
|
||
|
|
||
|
// decrement count of allocated locks
|
||
|
pStore->ulCountAllocated--;
|
||
|
|
||
|
// if there are too many dynamic readwrite locks, then free this lock
|
||
|
if ((pStore->ulCountAllocated + pStore->ulCountFree + 1) >
|
||
|
DYNAMIC_LOCKS_HIGH_THRESHOLD)
|
||
|
{
|
||
|
DELETE_READ_WRITE_LOCK(&pLock->rwlLock);
|
||
|
HeapFree(pStore->hHeap, 0, pLock);
|
||
|
}
|
||
|
else // insert into the list of free locks
|
||
|
{
|
||
|
pleHead = &(pStore->llFreeLocksList.head);
|
||
|
InsertHeadList(pleHead, &pLock->leLink);
|
||
|
pStore->ulCountFree++;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// AcquireDynamicLock
|
||
|
//
|
||
|
// Locks the FreeLocksList.
|
||
|
// Allocates a new dynamic lock if required.
|
||
|
// Increments the count.
|
||
|
// Unlocks the FreeLocksList.
|
||
|
// Acquires the dynamic lock.
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DWORD
|
||
|
AcquireDynamicReadwriteLock (
|
||
|
PDYNAMIC_READWRITE_LOCK *ppLock,
|
||
|
LOCK_MODE lmMode,
|
||
|
PDYNAMIC_LOCKS_STORE pStore
|
||
|
)
|
||
|
{
|
||
|
|
||
|
// acquire the lock for the free locks list
|
||
|
AcquireListLock(&pStore->llFreeLocksList);
|
||
|
|
||
|
// if it does not already exist, allocate a new dynamic lock
|
||
|
if (*ppLock == NULL)
|
||
|
{
|
||
|
*ppLock = GetDynamicReadwriteLock(pStore);
|
||
|
|
||
|
// if could not get a lock we are in serious trouble
|
||
|
if (*ppLock == NULL)
|
||
|
{
|
||
|
ReleaseListLock(&pStore->llFreeLocksList);
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// increment count in the dynamic lock
|
||
|
(*ppLock)->ulCount++;
|
||
|
|
||
|
// release the lock for the free locks list
|
||
|
ReleaseListLock(&pStore->llFreeLocksList);
|
||
|
|
||
|
// acquire dynamic lock
|
||
|
if (lmMode == READ_MODE)
|
||
|
AcquireReadLock(&(*ppLock)->rwlLock);
|
||
|
else
|
||
|
AcquireWriteLock(&(*ppLock)->rwlLock);
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// ReleaseDynamicReadwriteLock
|
||
|
//
|
||
|
// Locks the FreeLocksList.
|
||
|
// Releases the dynamic lock.
|
||
|
// Decrements the count.
|
||
|
// Free the dynamic lock if count becomes 0.
|
||
|
// Unlocks the FreeLocksList.
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
ReleaseDynamicReadwriteLock (
|
||
|
PDYNAMIC_READWRITE_LOCK *ppLock,
|
||
|
LOCK_MODE lmMode,
|
||
|
PDYNAMIC_LOCKS_STORE pStore
|
||
|
)
|
||
|
{
|
||
|
|
||
|
// acquire the lock for the free locks list
|
||
|
AcquireListLock(&pStore->llFreeLocksList);
|
||
|
|
||
|
// release the dynamic readwrite lock
|
||
|
if (lmMode == READ_MODE)
|
||
|
ReleaseReadLock(&(*ppLock)->rwlLock);
|
||
|
else
|
||
|
ReleaseWriteLock(&(*ppLock)->rwlLock);
|
||
|
|
||
|
// decrement count in the dynamic lock, free it if count becomes 0
|
||
|
(*ppLock)->ulCount--;
|
||
|
if ((*ppLock)->ulCount is 0)
|
||
|
{
|
||
|
FreeDynamicReadwriteLock(*ppLock, pStore);
|
||
|
*ppLock = NULL; // so it is known that it doesn't exist
|
||
|
}
|
||
|
|
||
|
// release the lock for the free locks list
|
||
|
ReleaseListLock(&pStore->llFreeLocksList);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
#endif
|