windows-nt/Source/XPSP1/NT/base/cluster/clusrtl/bufpool.c
2020-09-26 16:20:57 +08:00

450 lines
9.1 KiB
C

/*++
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
}