/*++ Copyright (c) 1996 Microsoft Corporation Module Name: gbuf.cxx Abstract: IIS MetaBase subroutines to support global buffers Author: Michael W. Thomas 12-July-96 Revision History: --*/ #include "precomp.hxx" HRESULT InitBufferPoolGlobalsToNull() /*++ Routine Description: Initializes the pool of buffers globals to NULL. Arguments: None Return Value: HHRESULT - S_OK Notes: --*/ { HRESULT hr = S_OK; g_ppvDataBufferBlock = NULL; g_pbcDataContainerBlock = NULL; g_pbcDataFreeBufHead = NULL; g_pbcDataUsedBufHead = NULL; g_fDataBufferCritSecInitialized = FALSE; g_hDataBufferSemaphore = NULL; return hr; } HRESULT InitBufferPool() /*++ Routine Description: Initializes the pool of buffers. Arguments: Return Value: HRESULT - S_OK E_OUTOFMEMORY Errors by CreateSemaphore, InitializeCriticalSectionAndSpinCount Notes: --*/ { HRESULT hr = S_OK; DWORD dwError = ERROR_SUCCESS; DWORD i; InitBufferPoolGlobalsToNull(); g_ppvDataBufferBlock = (PVOID *) new PVOID[NUM_DATA_BUFFERS][DATA_BUFFER_LEN]; if ( g_ppvDataBufferBlock == NULL ) { hr = E_OUTOFMEMORY; goto exit; } g_pbcDataContainerBlock = (PBUFFER_CONTAINER) new BUFFER_CONTAINER[NUM_DATA_BUFFERS]; if (g_pbcDataContainerBlock == NULL) { hr = E_OUTOFMEMORY; goto exit; } g_hDataBufferSemaphore = IIS_CREATE_SEMAPHORE( "g_hDataBufferSemaphore", &g_hDataBufferSemaphore, NUM_DATA_BUFFERS, NUM_DATA_BUFFERS ); if ( g_hDataBufferSemaphore == NULL ) { dwError = GetLastError(); hr = HRESULT_FROM_WIN32( dwError ); goto exit; } g_fDataBufferCritSecInitialized = INITIALIZE_CRITICAL_SECTION( &g_csDataBufferCritSec ); if ( !g_fDataBufferCritSecInitialized ) { dwError = GetLastError(); hr = HRESULT_FROM_WIN32( dwError ); goto exit; } for ( i = 0; i < NUM_DATA_BUFFERS; i++ ) { g_pbcDataContainerBlock[i].ppvBuffer = g_ppvDataBufferBlock + (i * DATA_BUFFER_LEN); g_pbcDataContainerBlock[i].NextPtr = g_pbcDataFreeBufHead; g_pbcDataFreeBufHead = g_pbcDataContainerBlock + i; } exit: if ( FAILED(hr) ) { DeleteBufferPool(); } return hr; } VOID DeleteBufferPool() /*++ Routine Description: Deletes the pool of buffers. Arguments: Return Value: Notes: --*/ { if ( g_ppvDataBufferBlock != NULL ) { delete[] g_ppvDataBufferBlock; } if ( g_pbcDataContainerBlock != NULL ) { delete[] g_pbcDataContainerBlock; } if ( g_fDataBufferCritSecInitialized ) { DeleteCriticalSection(&g_csDataBufferCritSec); } if ( g_hDataBufferSemaphore != NULL ) { CloseHandle( g_hDataBufferSemaphore ); } InitBufferPoolGlobalsToNull(); } PVOID * GetDataBuffer() /*++ Routine Description: Gets a buffer. Arguments: Return Value: PVOID * - The buffer. Notes: --*/ { DWORD dwError; PVOID *ppvReturn = NULL; PBUFFER_CONTAINER pbcTemp; DWORD i; // // Use a dual synchonization scheme. // The semaphore is used to guarantee // a buffer is available. // The critical section is used to // contol access to global data. // dwError = WaitForSingleObject(g_hDataBufferSemaphore, INFINITE); if (dwError != WAIT_FAILED) { EnterCriticalSection(&g_csDataBufferCritSec); MD_ASSERT(g_pbcDataFreeBufHead != NULL); ppvReturn = g_pbcDataFreeBufHead->ppvBuffer; pbcTemp = g_pbcDataFreeBufHead->NextPtr; g_pbcDataFreeBufHead->NextPtr = g_pbcDataUsedBufHead; g_pbcDataUsedBufHead = g_pbcDataFreeBufHead; g_pbcDataFreeBufHead = pbcTemp; LeaveCriticalSection(&g_csDataBufferCritSec); for (i = 0; i < DATA_BUFFER_LEN; i++) { ppvReturn[i] = NULL; } } return (ppvReturn); } VOID FreeDataBuffer( PVOID *ppvBuffer) { /*++ Routine Description: Gets a buffer. Arguments: ppvBuffer - The buffer. Return Value: Notes: --*/ PBUFFER_CONTAINER pbcTemp; EnterCriticalSection(&g_csDataBufferCritSec); MD_ASSERT(g_pbcDataUsedBufHead != NULL); // // Just grab any container. It's more efficient to set ppvBuffer // than to find the right container. // Of course, this eliminates error checking. The caller is // responsible to make sure that it only passes in correct addresses. // pbcTemp = g_pbcDataUsedBufHead->NextPtr; g_pbcDataUsedBufHead->NextPtr = g_pbcDataFreeBufHead; g_pbcDataFreeBufHead = g_pbcDataUsedBufHead; g_pbcDataUsedBufHead = pbcTemp; g_pbcDataFreeBufHead->ppvBuffer = ppvBuffer; LeaveCriticalSection(&g_csDataBufferCritSec); MD_REQUIRE(ReleaseSemaphore(g_hDataBufferSemaphore, 1, NULL)); } BOOL InsertItemIntoDataBuffer( PVOID pvItem, PVOID *ppvMainDataBuf, DWORD &dwNumBufferEntries) { /*++ Routine Description: Appends an item to the buffer at the specified location. This must be an append. Random insertion is not supported. This is actually a 2 tiered buffer scheme, where the first buffer is used an array of buffers. Items are pointers. Arguments: Item - The pointer to add to the buffer. MainDataBuf - The buffer. NumBufferEntries - The number of entries currently in the buffer. Return Value: BOOL - TRUE if the item was added successfully. Notes: --*/ BOOL bReturn = TRUE; DWORD dwMainBufIndex = dwNumBufferEntries / (DATA_BUFFER_LEN - 1); DWORD dwSubBufIndex = dwNumBufferEntries % (DATA_BUFFER_LEN - 1); PVOID *ppvCurrentDataBuf = ppvMainDataBuf; int i; MD_ASSERT(ppvMainDataBuf != NULL); for (i = 0; i < ((int)dwMainBufIndex - 1); i++) { // // Go to the buffer before the one we want, // in case we need to get the final one. // MD_ASSERT(ppvCurrentDataBuf[DATA_BUFFER_LEN - 1] != NULL); ppvCurrentDataBuf = (PVOID *)(ppvCurrentDataBuf[DATA_BUFFER_LEN -1]); } if ((dwMainBufIndex != 0) && (dwSubBufIndex == 0)) { MD_ASSERT(ppvCurrentDataBuf[DATA_BUFFER_LEN - 1] == NULL); ppvCurrentDataBuf[DATA_BUFFER_LEN - 1] = GetDataBuffer(); } MD_ASSERT((dwMainBufIndex == 0) || (i == (int)dwMainBufIndex - 1)); if (dwMainBufIndex != 0) { ppvCurrentDataBuf = (PVOID *)(ppvCurrentDataBuf[DATA_BUFFER_LEN - 1]); } MD_ASSERT(ppvCurrentDataBuf[dwSubBufIndex] == 0); ppvCurrentDataBuf[dwSubBufIndex] = pvItem; dwNumBufferEntries++; return(bReturn); } PVOID GetItemFromDataBuffer( PVOID *ppvMainDataBuf, DWORD dwItemNum) /*++ Routine Description: Gets the specified item from the buffer. Arguments: MainDataBuf - The buffer. ItemNum - The number of the item to get. Return Value: PVOID - The Item from that location. NULL if no item exists at that location. Notes: --*/ { DWORD dwMainBufIndex = dwItemNum / (DATA_BUFFER_LEN - 1); DWORD dwSubBufIndex = dwItemNum % (DATA_BUFFER_LEN - 1); PVOID pvReturn; PVOID *ppvCurrentDataBuf = ppvMainDataBuf; int i; MD_ASSERT(ppvMainDataBuf != NULL); for (i = 0; i < (int)dwMainBufIndex; i++) { ppvCurrentDataBuf = (PVOID *)(ppvCurrentDataBuf[DATA_BUFFER_LEN -1]); } if (ppvCurrentDataBuf == NULL) { pvReturn = NULL; } else { pvReturn = ppvCurrentDataBuf[dwSubBufIndex]; } return(pvReturn); } VOID FreeMainDataBuffer( PVOID *ppvMainDataBuf) /*++ Routine Description: Frees a main data buffer. Deletes all sub buffers. Arguments: MainDataBuf - The main data buffer. Return Value: Notes: --*/ { MD_ASSERT(ppvMainDataBuf != NULL); PVOID *ppvCurrentDataBuf; PVOID *ppvNextDataBuf; for ( ppvCurrentDataBuf = ppvMainDataBuf; ppvCurrentDataBuf != NULL; ppvCurrentDataBuf = ppvNextDataBuf ) { ppvNextDataBuf = (PVOID *)(ppvCurrentDataBuf[DATA_BUFFER_LEN - 1]); FreeDataBuffer(ppvCurrentDataBuf); } } PVOID * GetMainDataBuffer() /*++ Routine Description: Gets a main data buffer. Deletes all sub buffers. Arguments: Return Value: PVOID * - The main data buffer. Notes: --*/ { return(GetDataBuffer()); }