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) 1993-1999 Microsoft Corporation
Module Name:
pool.cpp
Abstract:
Fixed size memory allocator.
Author:
Bill Bolosky [bolosky] 1993
Revision History:
--*/
#include "sibp.h"
struct PoolEntry { void *object; struct PoolEntry *next; };
struct PoolBlob { struct PoolBlob *next; void *data; };
Pool::Pool( unsigned objectSize, void *(*allocator)(unsigned), unsigned blobSize, void (*destructor)(void *)) { assert(objectSize > 0);
assert(!destructor || allocator); // Can't have a destructor without an allocator. Allocator w/o destructor leaks objects on pool destruct.
this->countAllocator = allocator; this->singleAllocator = NULL; this->destructor = destructor; this->objectSize = objectSize; entries = NULL; freeEntries = NULL; entriesBlobHead = NULL; objectsBlobHead = NULL;
entriesPerBlob = blobSize / sizeof(PoolEntry); assert(entriesPerBlob > 0);
objectsPerBlob = blobSize / objectSize; if (!objectsPerBlob) { objectsPerBlob = 1; }
allocations = 0; frees = 0; news = 0;
numFree = 0; }
// This version of the pool constructor uses the old kind of allocator function that only returns one object. Object blobs have one object,
// and the blob size for entry blobs is smaller so that we have finer grain memory allocation.
Pool::Pool( unsigned objectSize, void *(*allocator)(void)) { assert(objectSize > 0);
assert(!destructor || allocator); // Can't have a destructor without an allocator; allocator w/o destructor leaks objects on pool destruct
this->singleAllocator = allocator; this->countAllocator = NULL; this->destructor = NULL; this->objectSize = objectSize; entries = NULL; freeEntries = NULL; entriesBlobHead = NULL; objectsBlobHead = NULL;
unsigned blobSize = 1024 - 50; // Our default allocation size; we leave the 50 byte headroom for the underlying allocator
entriesPerBlob = blobSize / sizeof(PoolEntry); assert(entriesPerBlob > 0);
objectsPerBlob = 1;
allocations = 0; frees = 0; news = 0;
numFree = 0; }
Pool::~Pool(void) { // Just delete the blob lists. All objects that have been allocated from this pool will be destroyed.
while (entriesBlobHead) { PoolBlob *blob = entriesBlobHead; assert(blob->data); delete [] blob->data; entriesBlobHead = blob->next; delete blob; }
while (objectsBlobHead) { PoolBlob *blob = objectsBlobHead; assert(blob->data); if (destructor) { (*destructor)(blob->data); } else if (!singleAllocator && !countAllocator) { delete [] blob->data; } // else leak the objects
objectsBlobHead = blob->next; delete blob; }
}
void Pool::allocateMoreObjects(void) { assert(objectsPerBlob);
PoolBlob *blob = new PoolBlob; if (!blob) { return; }
if (countAllocator) { blob->data = (*countAllocator)(objectsPerBlob); } else if (singleAllocator) { assert(objectsPerBlob == 1); blob->data = (*singleAllocator)(); } else { blob->data = (void *)new char[objectSize * objectsPerBlob]; }
if (!blob->data) { delete blob; return; }
blob->next = objectsBlobHead; objectsBlobHead = blob;
// Now put them on the free list.
for (unsigned i = 0; i < objectsPerBlob; i++) { PoolEntry *entry = getEntry(); if (!entry) { return; // This is kinda bogus, because it might leave some allocated objects unreachable.
} entry->object = (void *)(((char *)blob->data) + i * objectSize); entry->next = entries; entries = entry; }
news += objectsPerBlob; numFree += objectsPerBlob; }
// Allocate entries until the free list is of size n (or until an allocation fails).
void Pool::preAllocate( unsigned n) { assert(n);
while (numFree < n) { unsigned oldNumFree = numFree; allocateMoreObjects(); if (oldNumFree == numFree) { // We can't allocate more; punt
return; } } }
PoolEntry * Pool::getEntry(void) { PoolEntry *entry = NULL; if (freeEntries) { entry = freeEntries; freeEntries = entry->next; assert(entry->object == NULL); } else { // Allocate a new entry blob and fill it in.
PoolBlob *blob = new PoolBlob; if (blob) { PoolEntry *blobEntries = new PoolEntry[entriesPerBlob]; if (blobEntries) { blob->data = (void *)blobEntries; // Release all of the newly allocated entries except the first one, which we'll return.
for (unsigned i = 1; i < entriesPerBlob; i++) { releaseEntry(&blobEntries[i]); } entry = &blobEntries[0];
// Stick the new blob on the entries blob list.
blob->next = entriesBlobHead; entriesBlobHead = blob; } else { // Give up; we couldn't get memory
delete blob; } } } return(entry); }
void Pool::releaseEntry( PoolEntry *entry) { assert(entry); entry->object = NULL; entry->next = freeEntries; freeEntries = entry; }
void * Pool::allocate(void) { allocations++;
assert((numFree == 0) == (entries == NULL));
if (!entries) { allocateMoreObjects(); }
if (entries) { // We've got something
struct PoolEntry *thisEntry = entries; entries = entries->next; void *object = thisEntry->object;
assert(object);
releaseEntry(thisEntry);
assert(numFree); numFree--;
return(object); } else { // Coudn't allocate more, we're out of memory.
assert(numFree == 0); return NULL; } }
void Pool::free( void *object) { assert(object);
frees++;
// No way to assert that this is the right kind (size) of object...
// Get a PoolEntry.
struct PoolEntry *entry = getEntry(); if (!entry) { // We couldn't get an entry, so we can't add this object to the free list. Leak it.
return; }
numFree++;
entry->object = object; entry->next = entries; entries = entry; }
unsigned Pool::numAllocations(void) { return(allocations); }
unsigned Pool::numFrees(void) { return(frees); }
unsigned Pool::numNews(void) { return(news); }
unsigned Pool::getObjectSize(void) { return(objectSize); }
|