231 lines
5.5 KiB
C++
231 lines
5.5 KiB
C++
#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;
|
|
}
|