Source code of Windows XP (NT5)
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.
|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
bufpool.c
Abstract:
Generic Buffer Pool Manager.
Author:
Mike Massa (mikemas) April 5, 1996
Revision History:
Who When What -------- -------- ---------------------------------------------- mikemas 04-05-96 created
Notes:
Buffer Pools provide a mechanism for managing caches of fixed size structures which are frequently allocated/deallocated.
--*/
#include "clusrtlp.h"
//
// Pool of generic buffers
//
typedef struct _CLRTL_BUFFER_POOL { DWORD PoolSignature; DWORD BufferSize; SINGLE_LIST_ENTRY FreeList; DWORD MaximumCached; DWORD CurrentCached; DWORD MaximumAllocated; DWORD ReferenceCount; CLRTL_BUFFER_CONSTRUCTOR Constructor; CLRTL_BUFFER_DESTRUCTOR Destructor; CRITICAL_SECTION Lock; } CLRTL_BUFFER_POOL;
//
// Header for each allocated buffer
//
typedef struct { SINGLE_LIST_ENTRY Linkage; PCLRTL_BUFFER_POOL Pool; } BUFFER_HEADER, *PBUFFER_HEADER;
#define BP_SIG 'loop'
#define ASSERT_BP_SIG(pool) CL_ASSERT((pool)->PoolSignature == BP_SIG)
//
// Macros
//
//
#define BpAllocateMemory(size) LocalAlloc(LMEM_FIXED, (size))
#define BpFreeMemory(buf) LocalFree(buf)
#define BpAcquirePoolLock(Pool) EnterCriticalSection(&((Pool)->Lock))
#define BpReleasePoolLock(Pool) LeaveCriticalSection(&((Pool)->Lock))
//
// Public Functions
//
PCLRTL_BUFFER_POOL ClRtlCreateBufferPool( IN DWORD BufferSize, IN DWORD MaximumCached, IN DWORD MaximumAllocated, IN CLRTL_BUFFER_CONSTRUCTOR Constructor, OPTIONAL IN CLRTL_BUFFER_DESTRUCTOR Destructor OPTIONAL ) /*++
Routine Description:
Creates a pool from which fixed-size buffers may be allocated.
Arguments:
BufferSize - Size of the buffers managed by the pool.
MaximumCached - The maximum number of buffers to cache in the pool. Must be less than or equal to MaximumAllocated.
MaximumAllocated - The maximum number of buffers to allocate from system memory. Must be less than or equal to CLRTL_MAX_POOL_BUFFERS.
Constructor - An optional routine to be called when a new buffer is allocated from system memory. May be NULL
Destructor - An optional routine to be called when a buffer is returned to system memory. May be NULL.
Return Value:
A pointer to the created buffer pool or NULL on error. Extended error information is available from GetLastError().
--*/
{ PCLRTL_BUFFER_POOL pool;
if ( (MaximumAllocated > CLRTL_MAX_POOL_BUFFERS) || (MaximumCached > MaximumAllocated) ) { SetLastError(ERROR_INVALID_PARAMETER); return(NULL); }
pool = BpAllocateMemory(sizeof(CLRTL_BUFFER_POOL));
if (pool != NULL) {
InitializeCriticalSection(&(pool->Lock));
pool->PoolSignature = BP_SIG; pool->BufferSize = sizeof(BUFFER_HEADER) + BufferSize; pool->FreeList.Next = NULL; pool->MaximumCached = MaximumCached; pool->CurrentCached = 0; pool->MaximumAllocated = MaximumAllocated + 1; pool->ReferenceCount = 1; pool->Constructor = Constructor; pool->Destructor = Destructor; } else { SetLastError(ERROR_NOT_ENOUGH_MEMORY); }
return(pool); }
VOID ClRtlDestroyBufferPool( IN PCLRTL_BUFFER_POOL Pool ) /*++
Routine Description:
Destroys a previously created buffer pool.
Arguments:
Pool - A pointer to the pool to destroy.
Return Value:
None.
Notes:
The pool will not actually be destroyed until all outstanding buffers have been returned. Each outstanding buffer is effectively a reference on the pool.
--*/
{ SINGLE_LIST_ENTRY deleteList; CLRTL_BUFFER_DESTRUCTOR destructor; PSINGLE_LIST_ENTRY item; PBUFFER_HEADER header; BOOLEAN freePool;
deleteList.Next = NULL;
ASSERT_BP_SIG(Pool);
BpAcquirePoolLock(Pool);
CL_ASSERT(Pool->ReferenceCount != 0); Pool->ReferenceCount--; // Remove initial reference.
destructor = Pool->Destructor;
//
// Free all cached buffers
//
item = PopEntryList(&(Pool->FreeList));
while (item != NULL) { CL_ASSERT(Pool->ReferenceCount != 0); PushEntryList(&deleteList, item); Pool->ReferenceCount--;
item = PopEntryList(&(Pool->FreeList)); }
if (Pool->ReferenceCount == 0) { BpReleasePoolLock(Pool);
DeleteCriticalSection(&(Pool->Lock)); BpFreeMemory(Pool); } else { //
// Pool destruction is deferred until all buffers have been freed.
//
Pool->CurrentCached = 0; Pool->MaximumCached = 0;
BpReleasePoolLock(Pool); }
item = PopEntryList(&deleteList);
while (item != NULL) { header = CONTAINING_RECORD( item, BUFFER_HEADER, Linkage );
if (destructor != NULL) { (*destructor)(header+1); }
BpFreeMemory(header);
item = PopEntryList(&deleteList); }
return; }
PVOID ClRtlAllocateBuffer( IN PCLRTL_BUFFER_POOL Pool ) /*++
Routine Description:
Allocates a buffer from a previously created buffer pool.
Arguments:
Pool - A pointer to the pool from which to allocate the buffer.
Return Value:
A pointer to the allocated buffer if the routine was successfull. NULL if the routine failed. Extended error information is available by calling GetLastError().
--*/
{
//
// turn this fancy stuff off until it works.
//
#if 0
PSINGLE_LIST_ENTRY item; PBUFFER_HEADER header; PVOID buffer; DWORD status;
ASSERT_BP_SIG(Pool);
BpAcquirePoolLock(Pool);
//
// First, check the cache.
//
item = PopEntryList(&(Pool->FreeList));
if (item != NULL) { CL_ASSERT(Pool->CurrentCached != 0); Pool->CurrentCached--;
BpReleasePoolLock(Pool);
header = CONTAINING_RECORD( item, BUFFER_HEADER, Linkage );
return(header+1); }
//
// Need to allocate a fresh buffer from system memory.
//
if (Pool->ReferenceCount < Pool->MaximumAllocated) { //
// This is equivalent to a reference on the Pool.
//
Pool->ReferenceCount++;
BpReleasePoolLock(Pool);
header = BpAllocateMemory(Pool->BufferSize);
if (header != NULL) { header->Pool = Pool; buffer = header+1;
if (Pool->Constructor == NULL) { return(buffer); }
status = (*(Pool->Constructor))(buffer);
if (status == ERROR_SUCCESS) { return(buffer); }
SetLastError(status);
//
// The constructor failed.
//
BpFreeMemory(header); } else { SetLastError(ERROR_NOT_ENOUGH_MEMORY); }
//
// Failed - undo the reference.
//
BpAcquirePoolLock(Pool);
Pool->ReferenceCount--; } else { SetLastError(ERROR_NOT_ENOUGH_MEMORY); }
BpReleasePoolLock(Pool);
return(NULL); #else
return(LocalAlloc(LMEM_FIXED, Pool->BufferSize)); #endif
}
VOID ClRtlFreeBuffer( PVOID Buffer ) /*++
Routine Description:
Frees a buffer back to its owning pool.
Arguments:
Buffer - The buffer to free.
Return Value:
None.
--*/ { //
// turn this fancy stuff off until it works.
//
#if 0
PBUFFER_HEADER header; PCLRTL_BUFFER_POOL pool; CLRTL_BUFFER_DESTRUCTOR destructor;
header = ((PBUFFER_HEADER) Buffer) - 1;
pool = header->Pool;
ASSERT_BP_SIG(pool);
BpAcquirePoolLock(pool);
if (pool->CurrentCached < pool->MaximumCached) { //
// Return to free list
//
PushEntryList( &(pool->FreeList), (PSINGLE_LIST_ENTRY) &(header->Linkage) );
pool->CurrentCached++;
BpReleasePoolLock(pool);
return; }
destructor = pool->Destructor;
CL_ASSERT(pool->ReferenceCount != 0);
if (--(pool->ReferenceCount) != 0) { BpReleasePoolLock(pool);
if (destructor) { (*destructor)(Buffer); }
BpFreeMemory(header);
return;
}
CL_ASSERT(pool->CurrentCached == 0); BpReleasePoolLock(pool); DeleteCriticalSection(&(pool->Lock)); BpFreeMemory(pool);
if (destructor) { (*destructor)(Buffer); }
BpFreeMemory(header);
return; #else
LocalFree(Buffer); #endif
}
|