|
|
#include "TsunamiP.Hxx"
#pragma hdrstop
BOOL TsAllocate( IN const TSVC_CACHE &TSvcCache, IN ULONG cbSize, IN OUT PVOID * ppvNewBlock ) { return( TsAllocateEx( TSvcCache, cbSize, ppvNewBlock, NULL ) ); } // TsAllocate
BOOL TsAllocateEx( IN const TSVC_CACHE &TSvcCache, IN ULONG cbSize, IN OUT PVOID * ppvNewBlock, OPTIONAL PUSER_FREE_ROUTINE pfnFreeRoutine ) /*++
Routine Description:
This function allocates a memory block for the calling server.
The returned block is suitable for use as a parameter to TsCacheDirectoryBlob(). Blocks allocated by this function must either be cached or freed with TsFree(). Freeing of cached blocks will be handled by the cache manager.
Arguments:
pServiceInfo - An initialized SERVICE_INFO structure.
cbSize - Number of bytes to allocate. (Must be strictly greater than zero.)
ppvNewBlock - Address of a pointer to store the new block's address in.
Return Value:
TRUE - The allocation succeeded, and *ppvNewBlock points to at least cbSize accessable bytes.
FALSE - The allocation failed.
--*/ { PBLOB_HEADER pbhNewBlock;
ASSERT( cbSize > 0 ); ASSERT( ppvNewBlock != NULL );
//
// Set pbhNewBlock to NULL so that the exception-cleanup code
// can test against it to see if an allocation occurred before
// the exception.
//
pbhNewBlock = NULL;
__try { //
// If asked to allocate zero bytes, we return FALSE and NULL,
// as if allocation failure had occurred.
//
if ( cbSize != 0 ) { pbhNewBlock = ( PBLOB_HEADER ) ALLOC( cbSize + sizeof( BLOB_HEADER ) );
}
if ( pbhNewBlock != NULL ) { //
// If the allocation succeeded, we return a pointer to the
// memory just following the BLOB_HEADER.
//
*ppvNewBlock = ( PVOID )( pbhNewBlock + 1 );
//
// Set up the BLOB_HEADER: Normal flags and stored allocation
// size.
//
pbhNewBlock->IsCached = FALSE; pbhNewBlock->pfnFreeRoutine = pfnFreeRoutine; InitializeListHead( &pbhNewBlock->PFList ); } else { //
// The allocation failed, and we need to return NULL
//
*ppvNewBlock = NULL; } } __except( EXCEPTION_EXECUTE_HANDLER ) { //
// An exception transpired. The most likely causes are bogus input
// pointers for pServiceInfo and pbhNewBlock. Whatever the case, we
// free up any memory that may have been allocated and return failure.
//
if ( pbhNewBlock != NULL ) {
FREE( pbhNewBlock );
pbhNewBlock = NULL; } }
//
// Return TRUE or FALSE, according to the result of the allocation.
//
if ( pbhNewBlock == NULL ) { SetLastError( ERROR_NOT_ENOUGH_MEMORY); return( FALSE ); }
INC_COUNTER( TSvcCache.GetServiceId(), CurrentObjects );
return( TRUE ); } // TsAllocate
BOOL TsReallocate( IN const TSVC_CACHE &TSvcCache, IN ULONG cbSize, IN PVOID pvOldBlock, IN OUT PVOID * ppvNewBlock ) /*++
Routine Description:
This function will resize a previously allocated memory Blob for the calling server, possibly moving it in the process.
Arguments:
pServiceInfo - An initialized SERVICE_INFO structure.
cbSize - Number of bytes to resize the block to. (Must be strictly greater than zero.)
pvOldBlock - Address of a pointer to a previously-allocated block.
ppvNewBlock - Address of a pointer to store the new block's address in. If the allocation fails, NULL is stored here. Note that in many cases, pvOldBlock will be stored here.
Return Value:
TRUE - The reallocation succeeded, and *ppvNewBlock points to at least cbSize accessable bytes. pvOldBlock is no longer a valid pointer, if *ppvNewBlock!=pvOldBlock.
FALSE - The allocation failed. *ppvNewBlock = NULL. pvOldBlock is still a valid pointer to the block that we wished to resize.
--*/ { PBLOB_HEADER pbhNewBlock; PBLOB_HEADER pbhOldBlock;
ASSERT( pvOldBlock != NULL );
//
// Set pbhNewBlock to NULL so that the exception-cleanup code
// can test against it to see if an allocation occurred before
// the exception.
//
pbhNewBlock = NULL;
__try { //
// Adjust the input pointer to refer to the BLOB_HEADER.
//
pbhOldBlock = (( PBLOB_HEADER )pvOldBlock ) - 1;
//
// If the Blob is currently cached, we can't move it
// or change its size. Check for this in the Blob's
// flags, and fail if it occurs.
//
if ( pbhOldBlock->IsCached ) { DBGPRINTF(( DBG_CONTEXT, "A service (%d) has attempted to TsRealloc a BLOB that is cached.", TSvcCache.GetServiceId() )); BREAKPOINT(); SetLastError( ERROR_INVALID_PARAMETER ); } else { //
// The following assignment probes ppvNewBlock for writeability.
// Hopefully, this ensures that we get an AV from writing to it
// before we call REALLOC and potentially free the old block.
//
*ppvNewBlock = NULL;
pbhNewBlock = ( PBLOB_HEADER )REALLOC( pbhOldBlock, cbSize );
if ( pbhNewBlock != NULL ) { //
// Store a pointer to the caller-usable part of the new Blob in
// the output parameter.
//
*ppvNewBlock = ( PVOID )( pbhNewBlock + 1 ); } } } __except( EXCEPTION_EXECUTE_HANDLER ) { //
// An exception occured. If this was caught after a block was
// allocated, we must free the new block. Unfortunately, this
// means that we may end up returning FALSE in a case where
// pbhOldBlock is no longer valid.
//
// if ( pbhOldBlock == pbhNewBlock ), which implies the old
// pointer is still valid, we do not free the new block, but
// hope that the caller will. In any other case, we must
// free the new block to avoid a memory leak, and assume that
// TCPSVCs are going down soon...
//
// ISSUE: It might be best to reflect the exception up to the
// caller, so they can handle it and bail out of the current
// operation.
//
if ( pbhNewBlock != NULL && pbhOldBlock != pbhNewBlock ) { FREE( pbhNewBlock );
pbhNewBlock = NULL;
SetLastError( ERROR_INVALID_PARAMETER ); } }
//
// Return TRUE or FALSE, according to the result of the allocation.
//
if ( pbhNewBlock == NULL ) { return( FALSE ); }
return( TRUE ); } // TsReallocate
BOOL TsFree( IN const TSVC_CACHE &TSvcCache, IN PVOID pvOldBlock ) /*++
Routine Description:
This function frees a memory block allocated with TsAllocate().
Blocks that are currently cached cannot be freed with this function.
Arguments:
pServiceInfo - An initialized SERVICE_INFO structure.
pvOldBlock - The address of the block to free. (Must be non-NULL.)
Return Value:
TRUE - The block was freed. The pointer pvOldBlock is no longer valid.
FALSE - The block was not freed. Possible reasons include:
- pvOldBlock does not point to a block allocated with TsAllocate().
- pvOldBlock points to a block that has been cached with CacheDirectoryBlob().
- pServiceInfo does not point to a valid SERVICE_INFO structure.
--*/ { BOOLEAN bSuccess; PBLOB_HEADER pbhOldBlock;
ASSERT( pvOldBlock != NULL );
__try { //
// Adjust the input pointer to refer to the BLOB_HEADER.
//
pbhOldBlock = (( PBLOB_HEADER )pvOldBlock ) - 1;
if (!DisableSPUD) { EnterCriticalSection( &CacheTable.CriticalSection ); if ( !IsListEmpty( &pbhOldBlock->PFList ) ) { RemoveEntryList( &pbhOldBlock->PFList ); } LeaveCriticalSection( &CacheTable.CriticalSection ); }
//
// If the Blob is currently in the cache, we can't free it.
// Check for this in the Blob's flags, and fail if it
// occurs.
//
if ( pbhOldBlock->IsCached ) { DBGPRINTF(( DBG_CONTEXT, "A service (%d) has attempted to TsFree a BLOB that it put in the cache.", TSvcCache.GetServiceId() )); BREAKPOINT();
bSuccess = FALSE; } else { if ( pbhOldBlock->pfnFreeRoutine ) { bSuccess = pbhOldBlock->pfnFreeRoutine( pvOldBlock ); } else { bSuccess = TRUE; }
if ( bSuccess ) { //
// Free the memory used by the Blob.
//
bSuccess = !!FREE( pbhOldBlock );
DEC_COUNTER( TSvcCache.GetServiceId(), CurrentObjects ); }
}
} __except( EXCEPTION_EXECUTE_HANDLER ) { //
// Handle exception. Obviously, it's time to return failure.
// It's hardly possible to get here after succefully freeing
// the block, so it's likely that an app will either:
// - not check the return value and leak some memory.
// - check the return value and try again, probably
// only to fail forever.
//
// So, it is not advisable for callers to keep trying this
// call until it succeeds.
//
bSuccess = FALSE; }
return( bSuccess ); } // TsFree
BOOL TsCheckInOrFree( IN PVOID pvOldBlock ) /*++
Routine Description:
This function checks in a cached memory block or frees a non-cached memory block allocated with TsAllocate().
Arguments:
pServiceInfo - An initialized SERVICE_INFO structure.
pvOldBlock - The address of the block to free. (Must be non-NULL.)
Return Value:
TRUE - The block was freed. The pointer pvOldBlock is no longer valid.
FALSE - The block was not freed. Possible reasons include:
- pvOldBlock does not point to a block allocated with TsAllocate().
--*/ { BOOLEAN bSuccess; PBLOB_HEADER pbhOldBlock;
ASSERT( pvOldBlock != NULL );
__try { //
// Adjust the input pointer to refer to the BLOB_HEADER.
//
pbhOldBlock = (( PBLOB_HEADER )pvOldBlock ) - 1;
if (!DisableSPUD) { EnterCriticalSection( &CacheTable.CriticalSection ); if (!IsListEmpty( &pbhOldBlock->PFList ) ) { RemoveEntryList( &pbhOldBlock->PFList ); } LeaveCriticalSection( &CacheTable.CriticalSection ); }
if (BLOB_IS_OR_WAS_CACHED(pvOldBlock)) { bSuccess = TsCheckInCachedBlob( pvOldBlock ); } else { if ( pbhOldBlock->pfnFreeRoutine ) { bSuccess = pbhOldBlock->pfnFreeRoutine( pvOldBlock ); } else { bSuccess = TRUE; }
if ( bSuccess ) { //
// Free the memory used by the Blob.
//
bSuccess = !!FREE( pbhOldBlock ); } }
} __except( EXCEPTION_EXECUTE_HANDLER ) { //
// Handle exception. Obviously, it's time to return failure.
// It's hardly possible to get here after succefully freeing
// the block, so it's likely that an app will either:
// - not check the return value and leak some memory.
// - check the return value and try again, probably
// only to fail forever.
//
// So, it is not advisable for callers to keep trying this
// call until it succeeds.
//
ASSERT(FALSE); bSuccess = FALSE; }
return( bSuccess ); } // TsCheckInOrFree
|