Initial commit
This commit is contained in:
230
ZUtil/ZAllocWindow.cpp
Normal file
230
ZUtil/ZAllocWindow.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
#include <ZUtil/ZAllocWindow.hpp>
|
||||
#include <ZUtil/ZAssert.hpp>
|
||||
|
||||
#include <SST/SST_OS.h>
|
||||
|
||||
#define ALLOC_BITS (0xF00D) // Used to flag a section of memory as 'allocated'
|
||||
#define DEALLOC_BITS (0xDEAD) // Used to flag a section of memory as 'deallocated'
|
||||
#define LOOP_BITS (0xCAB0) // Used to flag that the next allocated section is back at the beginning of the buffer
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZAllocWindow::ZAllocWindow()
|
||||
: Buffer(NULL), Begin(NULL), End(NULL),
|
||||
BufferSize(0), bOwnsBuffer(true),
|
||||
NumAllocs(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZAllocWindow::ZAllocWindow( size_t _buffersize )
|
||||
: Buffer(NULL), Begin(NULL), End(NULL),
|
||||
BufferSize(_buffersize), bOwnsBuffer(true),
|
||||
NumAllocs(0)
|
||||
{
|
||||
Resize(_buffersize);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
ZAllocWindow::~ZAllocWindow()
|
||||
{
|
||||
if (bOwnsBuffer)
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void* ZAllocWindow::Allocate( size_t _size )
|
||||
{
|
||||
// boundary is the location in memory that we cannot write past
|
||||
uintptr_t boundary;
|
||||
|
||||
// determine where our boundary is
|
||||
uintptr_t pool_begin = (uintptr_t)Buffer;
|
||||
uintptr_t pool_end = pool_begin + BufferSize;
|
||||
uintptr_t ptr_begin = (uintptr_t)Begin;
|
||||
uintptr_t ptr_end = (uintptr_t)End;
|
||||
|
||||
boundary = (ptr_begin > ptr_end ? ptr_begin :
|
||||
ptr_begin < ptr_end ? pool_end :
|
||||
( NumAllocs > 0 ? ptr_end :
|
||||
pool_end ) );
|
||||
|
||||
// align segment to word boundary
|
||||
uintptr_t seg_begin = (uintptr_t)End;
|
||||
uintptr_t seg_end = (uintptr_t)SST_OS_AlignPtr((void*)(seg_begin + 2*sizeof(uint32_t) + _size), sizeof(void*));
|
||||
|
||||
// check segment against boundary
|
||||
if (seg_end > boundary) {
|
||||
|
||||
// if the segment has not just run up against the pool end, we are done
|
||||
if (boundary != pool_end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// signal a loop (if less than 'end') and check again
|
||||
if (seg_begin < pool_end) {
|
||||
uint32_t* ptr_32 = (uint32_t*)seg_begin;
|
||||
ptr_32[0] = (uint32_t)LOOP_BITS;
|
||||
}
|
||||
|
||||
boundary = ptr_begin;
|
||||
|
||||
seg_begin = pool_begin;
|
||||
seg_end = (uintptr_t)SST_OS_AlignPtr((void*)(seg_begin + 2 * sizeof(uint32_t) + _size), sizeof(void*));
|
||||
}
|
||||
|
||||
// check segment against boundary again
|
||||
if (seg_end <= boundary) {
|
||||
NumAllocs++;
|
||||
|
||||
// set size as first element in block
|
||||
uint32_t* ptr_32 = (uint32_t*)seg_begin;
|
||||
ptr_32[0] = (uint32_t)ALLOC_BITS;
|
||||
ptr_32[1] = (uint32_t)(seg_end - seg_begin);
|
||||
|
||||
// set new End pointer to ptr_end
|
||||
End = (void*)seg_end;
|
||||
|
||||
// if End == BufferEnd, End == 0
|
||||
if (End == (void*)((uintptr_t)Buffer + (uintptr_t)BufferSize))
|
||||
End = Buffer;
|
||||
|
||||
// return the address of the first non-reserved element of the segment
|
||||
return &ptr_32[2];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZAllocWindow::Deallocate( void* _data )
|
||||
{
|
||||
// check size before data
|
||||
uint32_t* ptr_32 = (uint32_t*)((uintptr_t)_data - (2*sizeof(uint32_t)));
|
||||
uint32_t flag = ptr_32[0];
|
||||
uint32_t size = ptr_32[1];
|
||||
|
||||
// quick sanity check
|
||||
ZASSERT(flag == ALLOC_BITS, "ZAllocWindow passed invalid pointer to deallocate!");
|
||||
ZASSERT(size < BufferSize, "ZAllocWindow passed corrupted pointer to deallocate!");
|
||||
|
||||
// mark size slot as 'freed'
|
||||
ptr_32[0] = (uint32_t)DEALLOC_BITS;
|
||||
NumAllocs--;
|
||||
|
||||
// see if this was the oldest allocated block, and start rolling up
|
||||
if (ptr_32 == Begin) {
|
||||
while (WHILE_TRUE) {
|
||||
ptr_32 = (uint32_t*)Begin;
|
||||
|
||||
// if begin is at or past end, loop to the beginning
|
||||
if ((uintptr_t)ptr_32 >= ((uintptr_t)Begin + BufferSize)) {
|
||||
Begin = Buffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine flag (size if needed)
|
||||
flag = ptr_32[0];
|
||||
|
||||
// if this is a loop flag, start again at the beginning
|
||||
if (flag == LOOP_BITS) {
|
||||
Begin = Buffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if this is a dealloc flag, dealloc the segment, increment Begin
|
||||
if (flag == DEALLOC_BITS) {
|
||||
size = ptr_32[1];
|
||||
|
||||
uintptr_t seg_start = (uintptr_t)ptr_32;
|
||||
uintptr_t seg_end = seg_start + size;
|
||||
|
||||
Begin = (void*)seg_end;
|
||||
|
||||
#ifdef _DEBUG
|
||||
ptr_32[1] = DEALLOC_BITS;
|
||||
#endif
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void ZAllocWindow::Reset()
|
||||
{
|
||||
NumAllocs = 0;
|
||||
Begin = Buffer;
|
||||
End = Buffer;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZAllocWindow::Resize( size_t _newsize )
|
||||
{
|
||||
// don't resize if we have allocations or don't own the buffer
|
||||
if (NumAllocs > 0 || !bOwnsBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check newsize is zero to free everything
|
||||
if (_newsize == 0) {
|
||||
if (Buffer != NULL) {
|
||||
free(Buffer);
|
||||
Buffer = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// free current buffer if not NULL
|
||||
if (Buffer != NULL) {
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
// allocate new buffer and return success / failure
|
||||
Buffer = malloc(_newsize);
|
||||
Begin = Buffer;
|
||||
End = Buffer;
|
||||
BufferSize = _newsize;
|
||||
|
||||
return Buffer != NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool ZAllocWindow::SetBuffer( void* _buffer, size_t _buffersize )
|
||||
{
|
||||
// don't accept buffer if we have allocations
|
||||
if (NumAllocs > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if the new buffer is null, just reallocate to buffersize
|
||||
if (_buffer == NULL) {
|
||||
bOwnsBuffer = true;
|
||||
return Resize(_buffersize);
|
||||
}
|
||||
|
||||
// Get rid of the current buffer if we need to
|
||||
if (Buffer != NULL) {
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
// lose ownership and set parameters, return success
|
||||
bOwnsBuffer = false;
|
||||
Buffer = _buffer;
|
||||
Begin = Buffer;
|
||||
End = Buffer;
|
||||
BufferSize = _buffersize;
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user