You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
414 lines
8.9 KiB
414 lines
8.9 KiB
/*++
|
|
|
|
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());
|
|
}
|