2025-11-28 00:35:46 +09:00

687 lines
17 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
/*
FILE: Resources.cpp
PURPOSE: Declarations for resource management routines and
data structures.
COMMENTS: See Resources.h for function and data-type info.
*/
#include "common.h"
#include "Resources.h"
#include "Service.h"
#ifdef DEBUG2
#include "DbgMsg.h"
#endif
Counter * CounterCreate(UINT Bound) {
Counter * pCounter;
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> CounterCreate\n"));
#endif
pCounter = (Counter *)AutoHeapAlloc(sizeof(Counter));
if (pCounter == NULL) {
return NULL;
}
pCounter->Value = 0;
pCounter->Bound = Bound;
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- CounterCreate\n"));
#endif
return pCounter;
}
VOID CounterDelete(Counter * pCounter) {
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> CounterDelete\n"));
#endif
ASSERT(pCounter != NULL);
AutoHeapFree(pCounter);
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- CounterDelete\n"));
#endif
}
BOOL CounterIncrement(Counter *pCounter) {
BOOL ret = FALSE;
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> CounterIncrement\n"));
#endif
ASSERT(pCounter != NULL);
// Check for the bound.
if (InterlockedIncrement(&pCounter->Value) > pCounter->Bound) {
ret = FALSE;
InterlockedDecrement(&pCounter->Value);
}
else {
ret = TRUE;
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- CounterIncrement\n"));
#endif
return ret;
}
VOID CounterDecrement(Counter *pCounter) {
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> CounterDecrement\n"));
#endif
ASSERT(pCounter != NULL);
InterlockedDecrement(&pCounter->Value);
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- CounterDecrement\n"));
#endif
}
BOOL CountersCreate(Counter *pCounters[], UINT n, UINT * Bounds) {
BOOL ret = FALSE;
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> CountersCreate\n"));
#endif
for (UINT i=0; i<n; i++) {
if ((pCounters[i] = CounterCreate(Bounds[i])) == NULL) {
CountersDelete(pCounters, i-1);
ret = FALSE;
break;
}
}
ret = TRUE;
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- CountersCreate\n"));
#endif
return ret;
}
VOID CountersDelete(Counter *pCounters[], UINT n) {
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> CountersDelete\n"));
#endif
for (UINT i=0; i<n; i++) {
ASSERT(pCounters[i] != NULL);
CounterDelete(pCounters[i]);
pCounters[i] = NULL;
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- CountersDelete\n"));
#endif
}
BOOL CountersCheckForNonzero(Counter *pCounters[], UINT n) {
for (UINT i=0; i<n; i++) {
ASSERT(pCounters[i] != NULL);
if (pCounters[i]->Value != 0) {
return TRUE;
}
}
return FALSE;
}
Queue * QueueCreate(BOOL NoCritSec) {
Queue * pQueue;
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueCreate\n"));
#endif
pQueue = (Queue *)AutoHeapAlloc(sizeof(Queue));
if (pQueue == NULL) {
AddToMessageLog(TEXT("QueueCreate: AutoHeapAlloc failed"));
return NULL;
}
pQueue->pFirst = NULL;
pQueue->pLast = NULL;
if (NoCritSec) {
pQueue->lpCriticalSection = NULL;
}
else {
pQueue->lpCriticalSection = (LPCRITICAL_SECTION) AutoHeapAlloc(sizeof(CRITICAL_SECTION));
if (InitializeCriticalSectionAndSpinCount(pQueue->lpCriticalSection, 100) == 0) {
AddToMessageLogProcFailure(TEXT("QueueCreate: InitializeCriticalSectionAndSpinCount"), GetLastError());
QueueDelete(pQueue);
return NULL;
}
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueCreate\n"));
#endif
return pQueue;
}
VOID QueueDelete(Queue * pQueue) {
QueueNode *pNextNode;
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueDelete\n"));
#endif
ASSERT(pQueue != NULL);
if (pQueue->lpCriticalSection != NULL) {
DeleteCriticalSection(pQueue->lpCriticalSection);
AutoHeapFree(pQueue->lpCriticalSection);
}
if (pQueue->pFirst != NULL) {
for (QueueNode *pNode = pQueue->pFirst; pNode != NULL; pNode = pNextNode) {
pNextNode = pNode->pNext;
AutoHeapFree(pNode->pData);
AutoHeapFree(pNode);
}
}
AutoHeapFree(pQueue);
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueDelete\n"));
#endif
}
BOOL QueueIsEmpty(Queue * pQueue) {
BOOL Ret = FALSE;
ASSERT(pQueue != NULL);
if (pQueue->lpCriticalSection != NULL) EnterCriticalSection(pQueue->lpCriticalSection);
Ret = (pQueue->pFirst == NULL);
ASSERT((!Ret) || (pQueue->pFirst == pQueue->pLast));
if (pQueue->lpCriticalSection != NULL) LeaveCriticalSection(pQueue->lpCriticalSection);
return Ret;
}
VOID QueueAdd(Queue *pQueue, VOID *pData, BOOL EnterCritSec) {
ASSERT(pQueue != NULL);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueAdd\n"));
#endif
QueueNode * pNode = (QueueNode *) AutoHeapAlloc(sizeof(QueueNode));
if (pNode == NULL) {
AddToMessageLog(TEXT("QueueAdd: AutoHeapAlloc failed"));
return;
}
pNode->pNext = NULL;
pNode->pData = pData;
if (pQueue->lpCriticalSection != NULL && EnterCritSec) EnterCriticalSection(pQueue->lpCriticalSection);
if (pQueue->pFirst == NULL) {
//ASSERT(pQueue->pLast == NULL);
pQueue->pFirst = pNode;
pQueue->pLast = pNode;
}
else {
ASSERT(pQueue->pLast->pNext == NULL);
pQueue->pLast->pNext = pNode;
pQueue->pLast = pNode;
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueAdd\n"));
#endif
if (pQueue->lpCriticalSection != NULL && EnterCritSec) LeaveCriticalSection(pQueue->lpCriticalSection);
}
VOID * QueueRemove(Queue *pQueue) {
VOID * pData;
QueueNode *pFuturepFirst;
VOID * pToFree;
ASSERT(pQueue != NULL);
if (pQueue->lpCriticalSection != NULL) EnterCriticalSection(pQueue->lpCriticalSection);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueRemove\n"));
#endif
if (pQueue->pFirst == NULL) {
ASSERT(pQueue->pFirst == pQueue->pLast);
if (pQueue->lpCriticalSection != NULL) LeaveCriticalSection(pQueue->lpCriticalSection);
return NULL;
}
pData = pQueue->pFirst->pData;
pFuturepFirst = pQueue->pFirst->pNext;
if (pFuturepFirst == NULL) {
pQueue->pLast = NULL;
}
pToFree = pQueue->pFirst;
pQueue->pFirst = pFuturepFirst;
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueRemove\n"));
#endif
if (pQueue->lpCriticalSection != NULL) LeaveCriticalSection(pQueue->lpCriticalSection);
AutoHeapFree(pToFree);
return pData;
}
VOID * QueueRemoveData(Queue *pQueue, VOID *pData) {
QueueNode *pFuturepFirst = NULL;
VOID *pToFree = NULL;
QueueNode *pNodeToFree = NULL;
QueueNode *pPrevNode = NULL;
ASSERT(pQueue != NULL);
if (pQueue->lpCriticalSection != NULL) EnterCriticalSection(pQueue->lpCriticalSection);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueRemoveData\n"));
#endif
// Find a node to remove.
// Walk the queue of active client requests
for (QueueNode *pNode = pQueue->pFirst; pNode != NULL; pNode = pNode->pNext) {
if (pNode->pData == pData) {
// If this is not the first node
if (pPrevNode) {
pPrevNode->pNext = pNode->pNext;
if (pQueue->pLast == pNode) {
ASSERT(pNode->pNext == NULL);
pQueue->pLast = pPrevNode;
}
}
else {
pQueue->pFirst = pNode->pNext;
}
pToFree = pNode;
break;
}
pPrevNode = pNode;
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueRemoveData\n"));
#endif
if (pQueue->lpCriticalSection != NULL) LeaveCriticalSection(pQueue->lpCriticalSection);
AutoHeapFree(pToFree);
return pData;
}
VOID QueueMoveToBack(Queue *pQueue, QueueNode *pNode, QueueNode *pPrevNode) {
ASSERT(pQueue != NULL);
ASSERT(pNode != NULL);
if (pQueue->lpCriticalSection != NULL) EnterCriticalSection(pQueue->lpCriticalSection);
// If it is the first element.
if (pPrevNode == NULL) {
pQueue->pFirst = pNode->pNext;
}
// If it has a predecessor in the queue
else {
pPrevNode->pNext = pNode->pNext;
}
// If it is the last element.
if (pNode->pNext == NULL) {
if (pQueue->lpCriticalSection != NULL) LeaveCriticalSection(pQueue->lpCriticalSection);
return;
}
// Put the subqueue onto the back of the queue.
pNode->pNext = NULL;
if (QueueIsEmpty(pQueue)) {
pQueue->pFirst = pNode;
pQueue->pLast = pNode;
}
else {
pQueue->pLast->pNext = pNode;
pQueue->pLast = pNode;
}
if (pQueue->lpCriticalSection != NULL) LeaveCriticalSection(pQueue->lpCriticalSection);
}
BOOL QueuesCreate(Queue *Queues[], UINT n, BOOL NoCritSec) {
BOOL ret = FALSE;
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueuesCreate\n"));
#endif
for (UINT i=0; i<n; i++) {
if ((Queues[i] = QueueCreate(NoCritSec)) == NULL) {
QueuesDelete(Queues, i-1);
ret = FALSE;
break;
}
}
ret = TRUE;
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueuesCreate\n"));
#endif
return ret;
}
VOID QueuesDelete(Queue *Queues[], UINT n) {
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueuesDelete\n"));
#endif
for (UINT i=0; i<n; i++) {
QueueDelete(Queues[i]);
Queues[i] = NULL;
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueuesDelete\n"));
#endif
}
VOID QueueHashAdd(Queue *pQueue, PSID Sid, VOID *pValue, BOOL EnterCritSec) {
QueueHashNode *pQueueHashNode;
DWORD SidLength;
ASSERT(pQueue != NULL);
if (pQueue->lpCriticalSection != NULL && EnterCritSec) EnterCriticalSection(pQueue->lpCriticalSection);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueHashAdd\n"));
#endif
pQueueHashNode = (QueueHashNode *) AutoHeapAlloc(sizeof(QueueHashNode));
SidLength = GetLengthSid(Sid);
// We need to copy the key so that if the original
// copy gets deallocated we still have one.
if ((pQueueHashNode->pKey = AutoHeapAlloc(SidLength)) == NULL) {
AddToMessageLog(TEXT("QueueHashAdd: AutoHeapAlloc failed"));
if (pQueue->lpCriticalSection != NULL && EnterCritSec) LeaveCriticalSection(pQueue->lpCriticalSection);
return;
}
if (CopySid(SidLength, pQueueHashNode->pKey, Sid) == 0) {
AddToMessageLogProcFailure(TEXT("QueueHashAdd: CopySid"), GetLastError());
if (pQueue->lpCriticalSection != NULL && EnterCritSec) LeaveCriticalSection(pQueue->lpCriticalSection);
return;
}
pQueueHashNode->pValue = pValue;
QueueAdd(pQueue, (VOID *) pQueueHashNode, FALSE);
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueHashAdd\n"));
#endif
if (pQueue->lpCriticalSection != NULL && EnterCritSec) LeaveCriticalSection(pQueue->lpCriticalSection);
}
VOID * QueueHashLookup(Queue *pQueue, PSID Sid, BOOL EnterCritSec) {
VOID * pValue;
QueueNode *pNextNode;
ASSERT(pQueue != NULL);
if (pQueue->lpCriticalSection != NULL && EnterCritSec) EnterCriticalSection(pQueue->lpCriticalSection);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueHashLookup\n"));
#endif
pValue = NULL;
for (QueueNode *pNode = pQueue->pFirst; pNode != NULL; pNode = pNextNode) {
pNextNode = pNode->pNext;
if (EqualSid(((QueueHashNode *)(pNode->pData))->pKey, Sid) == TRUE) {
pValue = ((QueueHashNode *)(pNode->pData))->pValue;
break;
}
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueHashLookup\n"));
#endif
if (pQueue->lpCriticalSection != NULL && EnterCritSec) LeaveCriticalSection(pQueue->lpCriticalSection);
return pValue;
}
VOID QueueHashAddToSubqueue(Queue *pHashQueue, PSID pSID, VOID * pData) {
ASSERT(pHashQueue != NULL);
if (pHashQueue->lpCriticalSection != NULL) EnterCriticalSection(pHashQueue->lpCriticalSection);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueHashAddToSubqueue\n"));
#endif
// Put the request onto the appropriate queue.
// Lookup the subqueue for the user's sid.
Queue * pQueue = (Queue *) QueueHashLookup(pHashQueue, pSID, FALSE);
// If the subqueue does not exist, create it.
if (pQueue == NULL) {
if ((pQueue = QueueCreate(TRUE)) == NULL) {
AddToMessageLog(TEXT("QueueHashAddToSubqueue: QueueCreate failed"));
if (pHashQueue->lpCriticalSection != NULL) LeaveCriticalSection(pHashQueue->lpCriticalSection);
return;
}
QueueHashAdd(pHashQueue, pSID, pQueue, FALSE);
}
// Add the request to the subqueue
QueueAdd(pQueue, pData, FALSE);
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueHashAddToSubqueue\n"));
#endif
if (pHashQueue->lpCriticalSection != NULL) LeaveCriticalSection(pHashQueue->lpCriticalSection);
}
VOID * QueueHashRemoveFromSubqueue(Queue *pQueue) {
Queue * pSubQueue;
QueueNode *pPrevNode;
VOID * pData;
ASSERT(pQueue != NULL);
if (pQueue->lpCriticalSection != NULL) EnterCriticalSection(pQueue->lpCriticalSection);
pSubQueue = NULL;
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueHashRemoveFromSubqueue\n"));
#endif
// If the hash queue is not empty.
if (pQueue->pFirst != NULL) {
// Find the first nonempty subqueue.
pPrevNode = NULL;
for (QueueNode *pNode = pQueue->pFirst; pNode != NULL; pNode = pNode->pNext) {
// Check if it has elements in it.
if (!QueueIsEmpty((Queue*) ((QueueHashNode *)pNode->pData)->pValue)) {
// Select it. We will extract an element off this subqueue
// and put the subqueue into the end of the hash queue.
pSubQueue = (Queue*) ((QueueHashNode *)pNode->pData)->pValue;
// Take it off the hash queue and put it
// on the back.
QueueMoveToBack(pQueue, pNode, pPrevNode);
break;
}
pPrevNode = pNode;
}
if (pSubQueue == NULL) {
// We did not find any nonemoty subqueues.
pData = NULL;
}
}
else {
// There are no nonempty subqueues.
pData = NULL;
}
if (pSubQueue != NULL) {
// Extract an element from the subqueue.
pData = QueueRemove(pSubQueue);
}
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueHashRemoveFromSubqueue\n"));
#endif
if (pQueue->lpCriticalSection != NULL) LeaveCriticalSection(pQueue->lpCriticalSection);
return pData;
}
BOOL QueueHashIncrementCounter(Queue *pHashQueue, PSID pSID) {
Counter *pCounter;
BOOL ret;
ASSERT(pHashQueue != NULL);
if (pHashQueue->lpCriticalSection != NULL) EnterCriticalSection(pHashQueue->lpCriticalSection);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueHashIncrementCounter\n"));
#endif
// Put the counter onto the appropriate queue.
// Lookup the counter for the user's sid.
pCounter = (Counter *) QueueHashLookup(pHashQueue, pSID, FALSE);
// If the counter does not exist, create it.
if (pCounter == NULL) {
if ((pCounter = CounterCreate(MaxUserReqs)) == NULL) {
AddToMessageLog(TEXT("QueueHashIncrementCounter: CounterCreate failed"));
if (pHashQueue->lpCriticalSection != NULL) LeaveCriticalSection(pHashQueue->lpCriticalSection);
return FALSE;
}
QueueHashAdd(pHashQueue, pSID, pCounter, FALSE);
}
// Attempt to increment the counter
ret = CounterIncrement(pCounter);
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueHashIncrementCounter\n"));
#endif
if (pHashQueue->lpCriticalSection != NULL) LeaveCriticalSection(pHashQueue->lpCriticalSection);
return ret;
}
VOID QueueHashDecrementCounter(Queue *pHashQueue, PSID pSID) {
Counter *pCounter;
ASSERT(pHashQueue != NULL);
if (pHashQueue->lpCriticalSection != NULL) EnterCriticalSection(pHashQueue->lpCriticalSection);
#ifdef DEBUG2
DbgMsgRecord(TEXT("-> QueueHashDecrementCounter\n"));
#endif
// Put the counter onto the appropriate queue.
// Lookup the counter for the user's sid.
pCounter = (Counter *) QueueHashLookup(pHashQueue, pSID, FALSE);
// If the counter does not exist, create it.
if (pCounter == NULL) {
if ((pCounter = CounterCreate(MaxUserReqs)) == NULL) {
AddToMessageLog(TEXT("QueueHashIncrementCounter: CounterCreate failed"));
if (pHashQueue->lpCriticalSection != NULL) LeaveCriticalSection(pHashQueue->lpCriticalSection);
return;
}
QueueHashAdd(pHashQueue, pSID, pCounter, FALSE);
}
// Decrement the counter.
CounterDecrement(pCounter);
#ifdef DEBUG2
DbgMsgRecord(TEXT("<- QueueHashDecrementCounter\n"));
#endif
if (pHashQueue->lpCriticalSection != NULL) LeaveCriticalSection(pHashQueue->lpCriticalSection);
}
// end Resources.cpp