978 lines
24 KiB
C
978 lines
24 KiB
C
//============================================================================
|
|
// Copyright (c) 1996, Microsoft Corporation
|
|
// File: sync.c
|
|
//
|
|
// History:
|
|
// Abolade Gbadegesin
|
|
// K.S.Lokesh (added Dynamic locking)
|
|
//
|
|
// Synchronization routines used by IGMP.
|
|
//============================================================================
|
|
|
|
|
|
#include "pchigmp.h"
|
|
|
|
|
|
// for debugging, Set ids for each dynamic lock
|
|
|
|
#ifdef LOCK_DBG
|
|
DWORD DynamicCSLockId;
|
|
DWORD DynamicRWLockId;
|
|
#endif;
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: QueueIgmpWorker
|
|
//
|
|
// This function is called to queue a Igmp function in a safe fashion;
|
|
// if cleanup is in progress or if Igmp has stopped, this function
|
|
// discards the work-item.
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
QueueIgmpWorker(
|
|
LPTHREAD_START_ROUTINE pFunction,
|
|
PVOID pContext
|
|
) {
|
|
|
|
DWORD Error = NO_ERROR;
|
|
BOOL bSuccess;
|
|
|
|
|
|
EnterCriticalSection(&g_CS);
|
|
|
|
if (g_RunningStatus != IGMP_STATUS_RUNNING) {
|
|
|
|
//
|
|
// cannot queue a work function when Igmp has quit or is quitting
|
|
//
|
|
|
|
Error = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
else {
|
|
|
|
++g_ActivityCount;
|
|
bSuccess = QueueUserWorkItem(pFunction, pContext, 0);
|
|
|
|
if (!bSuccess) {
|
|
|
|
Error = GetLastError();
|
|
|
|
Trace1(ERR, "Error: Attempt to queue work item returned:%d",
|
|
Error);
|
|
IgmpAssertOnError(FALSE);
|
|
|
|
--g_ActivityCount;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_CS);
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: EnterIgmpAPI
|
|
//
|
|
// This function is called to when entering a Igmp api, as well as
|
|
// when entering the input thread and timer thread.
|
|
// It checks to see if Igmp has stopped, and if so it quits; otherwise
|
|
// it increments the count of active threads.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
EnterIgmpApi(
|
|
) {
|
|
|
|
BOOL bEntered;
|
|
|
|
EnterCriticalSection(&g_CS);
|
|
|
|
if (g_RunningStatus == IGMP_STATUS_RUNNING) {
|
|
|
|
//
|
|
// Igmp is running, so the API may continue
|
|
//
|
|
|
|
++g_ActivityCount;
|
|
|
|
bEntered = TRUE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Igmp is not running, so the API exits quietly
|
|
//
|
|
|
|
bEntered = FALSE;
|
|
}
|
|
|
|
LeaveCriticalSection(&g_CS);
|
|
|
|
return bEntered;
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: EnterIgmpWorker
|
|
//
|
|
// This function is called when entering a Igmp worker-function.
|
|
// Since there is a lapse between the time a worker-function is queued
|
|
// and the time the function is actually invoked by a worker thread,
|
|
// this function must check to see if Igmp has stopped or is stopping;
|
|
// if this is the case, then it decrements the activity count,
|
|
// releases the activity semaphore, and quits.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
EnterIgmpWorker(
|
|
) {
|
|
|
|
BOOL bEntered;
|
|
|
|
EnterCriticalSection(&g_CS);
|
|
|
|
if (g_RunningStatus == IGMP_STATUS_RUNNING) {
|
|
|
|
//
|
|
// Igmp is running, so the function may continue
|
|
//
|
|
|
|
bEntered = TRUE;
|
|
}
|
|
else
|
|
if (g_RunningStatus == IGMP_STATUS_STOPPING) {
|
|
|
|
//
|
|
// Igmp is not running, but it was, so the function must stop.
|
|
//
|
|
|
|
--g_ActivityCount;
|
|
|
|
ReleaseSemaphore(g_ActivitySemaphore, 1, NULL);
|
|
|
|
bEntered = FALSE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Igmp probably never started. quit quietly
|
|
//
|
|
|
|
bEntered = FALSE;
|
|
}
|
|
|
|
LeaveCriticalSection(&g_CS);
|
|
|
|
return bEntered;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: LeaveIgmpWorkApi
|
|
//
|
|
// This function is called when leaving a Igmp API.
|
|
// It in turn calls LeaveIgmpWorker
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
LeaveIgmpApi(
|
|
) {
|
|
LeaveIgmpWorker();
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: LeaveIgmpWorker
|
|
//
|
|
// This function is called when leaving a Igmp API or worker function.
|
|
// It decrements the activity count, and if it detects that Igmp has stopped
|
|
// or is stopping, it releases the activity semaphore.
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
LeaveIgmpWorker(
|
|
) {
|
|
|
|
EnterCriticalSection(&g_CS);
|
|
|
|
--g_ActivityCount;
|
|
|
|
if (g_RunningStatus == IGMP_STATUS_STOPPING) {
|
|
|
|
ReleaseSemaphore(g_ActivitySemaphore, 1, NULL);
|
|
}
|
|
|
|
LeaveCriticalSection(&g_CS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: CreateReadWriteLock
|
|
//
|
|
// Initializes a multiple-reader/single-writer lock object
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CreateReadWriteLock(
|
|
PREAD_WRITE_LOCK pRWL
|
|
) {
|
|
|
|
pRWL->RWL_ReaderCount = 0;
|
|
|
|
try {
|
|
InitializeCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
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
|
|
) {
|
|
|
|
pRWL->RWL_ReaderCount = 0;
|
|
LeaveCriticalSection(&(pRWL)->RWL_ReadWriteBlock);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _InitializeDynamicLocksStore
|
|
//
|
|
// Initialize the global struct from which dynamic CS or RW locks are allocated
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
InitializeDynamicLocksStore (
|
|
PDYNAMIC_LOCKS_STORE pDLStore //ptr to Dynamic CS Store
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
|
|
BEGIN_BREAKOUT_BLOCK1 {
|
|
|
|
//
|
|
// initialize the main CS lock which protects the list of free locks
|
|
//
|
|
|
|
try {
|
|
InitializeCriticalSection(&pDLStore->CS);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Error = GetExceptionCode();
|
|
Trace1(ERR, "Error initializing critical section in IGMPv2.dll",
|
|
Error);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr0(INIT_CRITSEC_FAILED, Error);
|
|
|
|
GOTO_END_BLOCK1;
|
|
}
|
|
|
|
|
|
// initialize list of free locks
|
|
|
|
InitializeListHead(&pDLStore->ListOfFreeLocks);
|
|
|
|
|
|
// initialize counts for number of locks free and allocated to 0.
|
|
|
|
pDLStore->CountAllocated = pDLStore->CountFree = 0;
|
|
|
|
|
|
} END_BREAKOUT_BLOCK1;
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _DeInitializeDynamicLocksStore
|
|
//
|
|
// Delete the main CS lock and the other free locks. Print warning if any
|
|
// locks have been allocated and not freed.
|
|
//------------------------------------------------------------------------------
|
|
VOID
|
|
DeInitializeDynamicLocksStore (
|
|
PDYNAMIC_LOCKS_STORE pDLStore,
|
|
LOCK_TYPE LockType //if True, then store of CS, else of RW locks
|
|
)
|
|
{
|
|
PDYNAMIC_CS_LOCK pDCSLock;
|
|
PDYNAMIC_RW_LOCK pDRWLock;
|
|
PLIST_ENTRY pHead, ple;
|
|
|
|
|
|
Trace0(ENTER1, "Entering _DeInitializeDynamicLocksStore()");
|
|
|
|
if (pDLStore==NULL)
|
|
return;
|
|
|
|
|
|
|
|
// delete the main CS lock
|
|
|
|
DeleteCriticalSection(&pDLStore->CS);
|
|
|
|
|
|
// print warning if any dynamic lock has not been freed
|
|
|
|
if (pDLStore->CountAllocated>0) {
|
|
Trace1(ERR,
|
|
"%d Dynamic locks have not been freed during Deinitialization",
|
|
pDLStore->CountAllocated);
|
|
IgmpAssertOnError(FALSE);
|
|
}
|
|
|
|
|
|
|
|
// delete all dynamic CS/RW locks. I dont free the memory (left to heapDestroy)
|
|
|
|
pHead = &pDLStore->ListOfFreeLocks;
|
|
for (ple=pHead->Flink; ple!=pHead; ) {
|
|
|
|
// if bCSLocks flag, then it is a store of CS locks
|
|
if (LockType==LOCK_TYPE_CS) {
|
|
|
|
pDCSLock = CONTAINING_RECORD(ple, DYNAMIC_CS_LOCK, Link);
|
|
ple = ple->Flink;
|
|
|
|
DeleteCriticalSection(&pDCSLock->CS);
|
|
IGMP_FREE(pDCSLock);
|
|
}
|
|
|
|
// delete the RW lock
|
|
else {
|
|
|
|
pDRWLock = CONTAINING_RECORD(ple, DYNAMIC_RW_LOCK, Link);
|
|
ple = ple->Flink;
|
|
|
|
DELETE_READ_WRITE_LOCK(&pDRWLock->RWL);
|
|
IGMP_FREE(pDRWLock);
|
|
}
|
|
}
|
|
|
|
Trace0(LEAVE1, "Leaving _DeInitializeDynamicLocksStore()");
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _AcquireDynamicCSLock
|
|
//
|
|
// Acquires the MainLock associated with the table, Acquires a new dynamic
|
|
// lock if required, increments the count, releases the MainLock and
|
|
// locks the LockedList.
|
|
//------------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
AcquireDynamicCSLock (
|
|
PDYNAMIC_CS_LOCK *ppDCSLock,
|
|
PDYNAMIC_LOCKS_STORE pDCSStore
|
|
)
|
|
{
|
|
// acquire the main lock for the Dynamic CS store
|
|
|
|
ENTER_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
|
|
"_AcquireDynamicCSLock");
|
|
|
|
|
|
//
|
|
// If it is not already locked then allocate a lock
|
|
//
|
|
if (*ppDCSLock==NULL) {
|
|
|
|
*ppDCSLock = GetDynamicCSLock(pDCSStore);
|
|
|
|
|
|
// if could not get a lock, then igmp is in serious trouble
|
|
|
|
if (*ppDCSLock==NULL) {
|
|
|
|
LEAVE_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
|
|
"_AcquireDynamicCSLock");
|
|
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
|
|
|
|
// increment Count in the Dynamic Lock
|
|
|
|
(*ppDCSLock)->Count++;
|
|
DYNAMIC_LOCK_CHECK_SIGNATURE_INCR(*ppDCSLock);
|
|
|
|
|
|
// leave main CS lock
|
|
|
|
LEAVE_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
|
|
"_AcquireDynamicCSLock");
|
|
|
|
|
|
//
|
|
// enter dynamic lock's CS lock
|
|
//
|
|
ENTER_CRITICAL_SECTION(&(*ppDCSLock)->CS, "pDynamicLock",
|
|
"_AcquireDynamicCSLock");
|
|
|
|
|
|
return NO_ERROR;
|
|
|
|
} //end _AcquireDynamicCSLock
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _GetDynamicCSLock
|
|
//
|
|
// If a free lock is available, returns it. Else allocates a new CS lock
|
|
// Lock: Assumes the DCSStore MainLock
|
|
//------------------------------------------------------------------------------
|
|
|
|
PDYNAMIC_CS_LOCK
|
|
GetDynamicCSLock (
|
|
PDYNAMIC_LOCKS_STORE pDCSStore
|
|
)
|
|
{
|
|
PDYNAMIC_CS_LOCK pDCSLock;
|
|
DWORD Error = NO_ERROR;
|
|
PLIST_ENTRY ple;
|
|
|
|
|
|
//
|
|
// free dynamic lock available. Return it
|
|
//
|
|
if (!IsListEmpty(&pDCSStore->ListOfFreeLocks)) {
|
|
|
|
pDCSStore->CountFree--;
|
|
pDCSStore->CountAllocated++;
|
|
|
|
ple = RemoveTailList(&pDCSStore->ListOfFreeLocks);
|
|
|
|
pDCSLock = CONTAINING_RECORD(ple, DYNAMIC_CS_LOCK, Link);
|
|
|
|
/*Trace1(LEAVE1, "Leaving GetDynamicCSLock.1(%d):reusing lock",
|
|
pDCSLock->Id);
|
|
*/
|
|
|
|
return pDCSLock;
|
|
}
|
|
|
|
|
|
// allocate memory for a new dynamic lock
|
|
|
|
pDCSLock = IGMP_ALLOC(sizeof(DYNAMIC_CS_LOCK), 0x20000,0);
|
|
|
|
PROCESS_ALLOC_FAILURE2(pDCSLock,
|
|
"error %d allocating %d bytes for dynamic CS lock",
|
|
Error, sizeof(DYNAMIC_CS_LOCK),
|
|
return NULL);
|
|
|
|
|
|
pDCSStore->CountAllocated++;
|
|
|
|
//
|
|
// initialize the fields
|
|
//
|
|
|
|
try {
|
|
InitializeCriticalSection(&pDCSLock->CS);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Error = GetExceptionCode();
|
|
Trace1(ERR,
|
|
"Error(%d) initializing critical section for dynamic CS lock",
|
|
Error);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr0(INIT_CRITSEC_FAILED, Error);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// no need to initialize the link field
|
|
//InitializeListEntry(&pDCSLock->List);
|
|
|
|
pDCSLock->Count = 0;
|
|
#ifdef LOCK_DBG
|
|
pDCSLock->Id = ++DynamicCSLockId;
|
|
#endif
|
|
DYNAMIC_LOCK_SET_SIGNATURE(pDCSLock);
|
|
|
|
|
|
//Trace1(LEAVE1, "Leaving _GetDynamicCSLock(%d:%d):new lock", DynamicCSLockId);
|
|
//Trace2(DYNLOCK, "CS: %d %d", pDCSLock->Id, DynamicCSLockId);
|
|
|
|
return pDCSLock;
|
|
|
|
} //end _GetDynamicCSLock
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _ReleaseDynamicCSLock
|
|
//
|
|
// Acquires the MainLock associated with the table, decrements the count,
|
|
// releases the DynamicLock if count becomes 0 and releases the MainLock.
|
|
//------------------------------------------------------------------------------
|
|
VOID
|
|
ReleaseDynamicCSLock (
|
|
PDYNAMIC_CS_LOCK *ppDCSLock,
|
|
PDYNAMIC_LOCKS_STORE pDCSStore
|
|
)
|
|
{
|
|
PDYNAMIC_CS_LOCK pDCSLock = *ppDCSLock;
|
|
|
|
|
|
// acquire the main lock for the Dynamic CS store
|
|
|
|
ENTER_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
|
|
"_ReleaseDynamicCSLock");
|
|
|
|
DYNAMIC_LOCK_CHECK_SIGNATURE_DECR(pDCSLock);
|
|
|
|
|
|
// leave the dynamic lock CS
|
|
|
|
LEAVE_CRITICAL_SECTION(&pDCSLock->CS, "pDynamicLock",
|
|
"_ReleaseDynamicCSLock");
|
|
|
|
|
|
|
|
// Decrement Count in the Dynamic Lock. Free the dynamic lock if count==0
|
|
|
|
if (--pDCSLock->Count==0) {
|
|
|
|
FreeDynamicCSLock(pDCSLock, pDCSStore);
|
|
|
|
// make the pDCSLock NULL so that it is known that it is not locked
|
|
*ppDCSLock = NULL;
|
|
|
|
}
|
|
|
|
|
|
// leave main CS lock
|
|
|
|
LEAVE_CRITICAL_SECTION(&pDCSStore->CS, "pDCSStore->CS",
|
|
"_ReleaseDynamicCSLock");
|
|
|
|
|
|
//Trace0(LEAVE1, "Leaving _ReleaseDynamicCSLock()");
|
|
|
|
return;
|
|
|
|
} //end _ReleaseDynamicCSLock
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _FreeDynamicCSLock
|
|
//------------------------------------------------------------------------------
|
|
VOID
|
|
FreeDynamicCSLock (
|
|
PDYNAMIC_CS_LOCK pDCSLock,
|
|
PDYNAMIC_LOCKS_STORE pDCSStore
|
|
)
|
|
{
|
|
// decrement count of allocated locks
|
|
|
|
pDCSStore->CountAllocated--;
|
|
|
|
// if there are too many dynamic CS locks, then free this lock
|
|
|
|
if (pDCSStore->CountFree+1
|
|
> DYNAMIC_LOCKS_HIGH_THRESHOLD)
|
|
{
|
|
DeleteCriticalSection(&pDCSLock->CS);
|
|
IGMP_FREE(pDCSLock);
|
|
}
|
|
|
|
// else put it into the list of free locks
|
|
|
|
else {
|
|
InsertHeadList(&pDCSStore->ListOfFreeLocks, &pDCSLock->Link);
|
|
pDCSStore->CountFree++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _AcquireDynamicRWLock
|
|
//
|
|
// Acquires the MainLock associated with the table, Acquires a new dynamic
|
|
// lock if required, increments the count, releases the MainLock and
|
|
// locks the LockedList.
|
|
//------------------------------------------------------------------------------
|
|
DWORD
|
|
AcquireDynamicRWLock (
|
|
PDYNAMIC_RW_LOCK *ppDRWLock,
|
|
LOCK_TYPE LockMode,
|
|
PDYNAMIC_LOCKS_STORE pDRWStore
|
|
)
|
|
{
|
|
//Trace0(ENTER1, "Entering _AcquireDynamicRWLock()");
|
|
|
|
|
|
// acquire the main lock for the Dynamic RW store
|
|
|
|
ENTER_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
|
|
"AcquireDynamicRWLock");
|
|
|
|
|
|
//
|
|
// If it is not already locked then allocate a lock
|
|
//
|
|
if (*ppDRWLock==NULL) {
|
|
|
|
*ppDRWLock = GetDynamicRWLock(pDRWStore);
|
|
|
|
//Trace1(DYNLOCK, "Acquired dynamicRWLock(%d)", (*ppDRWLock)->Id);
|
|
|
|
|
|
// if could not get a lock, then igmp is in serious trouble
|
|
|
|
if (*ppDRWLock==NULL) {
|
|
|
|
LEAVE_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
|
|
"AcquireDynamicRWLock");
|
|
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
|
|
else
|
|
;//Trace1(DYNLOCK, "Acquired existing dynamicRWLock(%d)", (*ppDRWLock)->Id);
|
|
|
|
|
|
// increment Count in the Dynamic Lock
|
|
|
|
(*ppDRWLock)->Count++;
|
|
DYNAMIC_LOCK_CHECK_SIGNATURE_INCR(*ppDRWLock);
|
|
|
|
|
|
// leave main CS lock
|
|
|
|
LEAVE_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
|
|
"_AcquireDynamicRWLock");
|
|
|
|
|
|
//
|
|
// acquire dynamic lock
|
|
//
|
|
if (LockMode==LOCK_MODE_READ) {
|
|
ACQUIRE_READ_LOCK(&(*ppDRWLock)->RWL, "pDynamicLock(Read)",
|
|
"_AcquireDynamicRWLock");
|
|
}
|
|
else {
|
|
ACQUIRE_WRITE_LOCK(&(*ppDRWLock)->RWL, "pDynamicLock(Write)",
|
|
"_AcquireDynamicRWLock");
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} //end _AcquireDynamicRWLock
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _GetDynamicRWLock
|
|
//
|
|
// If a free lock is available, returns it. Else allocates a new CS lock
|
|
// Lock: assumes the DRWStore MainLock
|
|
//------------------------------------------------------------------------------
|
|
PDYNAMIC_RW_LOCK
|
|
GetDynamicRWLock (
|
|
PDYNAMIC_LOCKS_STORE pDRWStore
|
|
)
|
|
{
|
|
PDYNAMIC_RW_LOCK pDRWLock;
|
|
DWORD Error = NO_ERROR;
|
|
PLIST_ENTRY ple;
|
|
|
|
|
|
//
|
|
// free dynamic lock available. Return it
|
|
//
|
|
if (!IsListEmpty(&pDRWStore->ListOfFreeLocks)) {
|
|
|
|
pDRWStore->CountFree--;
|
|
pDRWStore->CountAllocated++;
|
|
|
|
ple = RemoveTailList(&pDRWStore->ListOfFreeLocks);
|
|
|
|
pDRWLock = CONTAINING_RECORD(ple, DYNAMIC_RW_LOCK, Link);
|
|
|
|
/*Trace1(LEAVE1, "Leaving GetDynamicRWLock(%d):reusing lock",
|
|
pDRWLock->Id);
|
|
Trace2(DYNLOCK, "--------------------%d %d", pDRWLock->Id, DynamicRWLockId);
|
|
*/
|
|
return pDRWLock;
|
|
}
|
|
|
|
|
|
// allocate memory for a new dynamic lock
|
|
|
|
pDRWLock = IGMP_ALLOC(sizeof(DYNAMIC_RW_LOCK), 0x40000,0);
|
|
|
|
PROCESS_ALLOC_FAILURE2(pDRWLock,
|
|
"error %d allocating %d bytes for dynamic RW lock",
|
|
Error, sizeof(DYNAMIC_RW_LOCK),
|
|
return NULL);
|
|
|
|
|
|
//
|
|
// initialize the fields
|
|
//
|
|
|
|
try {
|
|
CREATE_READ_WRITE_LOCK(&pDRWLock->RWL);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
Error = GetExceptionCode();
|
|
Trace1(ERR,
|
|
"Error(%d) initializing critical section for dynamic RW lock", Error);
|
|
IgmpAssertOnError(FALSE);
|
|
Logerr0(INIT_CRITSEC_FAILED, Error);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// no need to initialize the link field
|
|
//InitializeListEntry(&pDRWLock->List);
|
|
|
|
pDRWLock->Count = 0;
|
|
#ifdef LOCK_DBG
|
|
pDRWLock->Id = ++DynamicRWLockId;
|
|
#endif
|
|
DYNAMIC_LOCK_SET_SIGNATURE(pDRWLock);
|
|
|
|
pDRWStore->CountAllocated++;
|
|
|
|
//Trace1(LEAVE1, "Leaving GetDynamicRWLock(%d):new lock", DynamicRWLockId);
|
|
//Trace2(DYNLOCK, "--------------------%d %d", pDRWLock->Id, DynamicRWLockId);
|
|
|
|
return pDRWLock;
|
|
|
|
} //end _GetDynamicRWLock
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _ReleaseDynamicRWLock
|
|
//
|
|
// Acquires the MainLock associated with the table, decrements the count,
|
|
// releases the DynamicLock if count becomes 0 and releases the MainLock.
|
|
//------------------------------------------------------------------------------
|
|
|
|
VOID
|
|
ReleaseDynamicRWLock (
|
|
PDYNAMIC_RW_LOCK *ppDRWLock,
|
|
LOCK_TYPE LockMode,
|
|
PDYNAMIC_LOCKS_STORE pDRWStore
|
|
)
|
|
{
|
|
PDYNAMIC_RW_LOCK pDRWLock = *ppDRWLock;
|
|
|
|
|
|
// acquire the main lock for the Dynamic RW store
|
|
|
|
ENTER_CRITICAL_SECTION(&pDRWStore->CS, "pDRWStore->CS",
|
|
"_ReleaseDynamicRWLock");
|
|
|
|
IgmpAssert(pDRWLock!=NULL);//deldel
|
|
#if DBG
|
|
if (pDRWLock==NULL)
|
|
IgmpDbgBreakPoint();
|
|
#endif
|
|
DYNAMIC_LOCK_CHECK_SIGNATURE_DECR(pDRWLock);
|
|
|
|
|
|
// leave the dynamic RW lock
|
|
if (LockMode==LOCK_MODE_READ) {
|
|
RELEASE_READ_LOCK(&pDRWLock->RWL, "pDynamicLock(read)",
|
|
"_ReleaseDynamicRWLock");
|
|
}
|
|
else {
|
|
RELEASE_WRITE_LOCK(&pDRWLock->RWL, "pDynamicLock(write)",
|
|
"_ReleaseDynamicRWLock");
|
|
}
|
|
|
|
// Decrement Count in the Dynamic Lock. Free the dynamic lock if count==0
|
|
|
|
if (--pDRWLock->Count==0) {
|
|
|
|
FreeDynamicRWLock(pDRWLock, pDRWStore);
|
|
|
|
// make the pDRWLock NULL so that it is known that it is not locked
|
|
*ppDRWLock = NULL;
|
|
|
|
}
|
|
|
|
|
|
// leave main CS lock
|
|
|
|
LEAVE_CRITICAL_SECTION(&pDRWStore->CS, "pDCSStore->CS",
|
|
"_ReleaseDynamicRWLock");
|
|
|
|
return;
|
|
|
|
} //end _ReleaseDynamicRWLock
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// _FreeDynamicRWLock
|
|
//------------------------------------------------------------------------------
|
|
|
|
VOID
|
|
FreeDynamicRWLock (
|
|
PDYNAMIC_RW_LOCK pDRWLock,
|
|
PDYNAMIC_LOCKS_STORE pDRWStore
|
|
)
|
|
{
|
|
// decrement count of allocated locks
|
|
|
|
pDRWStore->CountAllocated--;
|
|
|
|
|
|
// if there are too many dynamic RW locks, then free this lock
|
|
|
|
if (pDRWStore->CountFree+1
|
|
> DYNAMIC_LOCKS_HIGH_THRESHOLD)
|
|
{
|
|
DELETE_READ_WRITE_LOCK(&pDRWLock->RWL);
|
|
IGMP_FREE(pDRWLock);
|
|
}
|
|
|
|
// else put it into the list of free locks
|
|
|
|
else {
|
|
InsertHeadList(&pDRWStore->ListOfFreeLocks, &pDRWLock->Link);
|
|
pDRWStore->CountFree++;
|
|
}
|
|
|
|
return;
|
|
}
|