#include "error_ext.h"
#include "part_ext.h"
#include "std_ext.h"
#include "string_ext.h"
#include "mem_ext.h"
#include "mem.h"
#include "xx_ext.h"
#if 0
#define PAD_ALIGNMENT(align, x) (((x)%(align)) ? ((align)-((x)%(align))) : 0)
#define ALIGN_BLOCK(p_Block, prefixSize, alignment) \
do { \
p_Block += (prefixSize); \
p_Block += PAD_ALIGNMENT((alignment), (uintptr_t)(p_Block)); \
} while (0)
#if defined(__GNUC__)
#define GET_CALLER_ADDR \
__asm__ ("mflr %0" : "=r" (callerAddr))
#elif defined(__MWERKS__)
#define GET_CALLER_ADDR \
__asm__("add %0, 0, %0" : : "r" (callerAddr))
#endif
static __inline__ void * MemGet(t_MemorySegment *p_Mem)
{
uint8_t *p_Block;
if (p_Mem->current == p_Mem->num)
{
p_Mem->getFailures++;
return NULL;
}
p_Block = p_Mem->p_BlocksStack[p_Mem->current];
#ifdef DEBUG
p_Mem->p_BlocksStack[p_Mem->current] = NULL;
#endif
p_Mem->current++;
return (void *)p_Block;
}
static __inline__ t_Error MemPut(t_MemorySegment *p_Mem, void *p_Block)
{
if (p_Mem->current > 0)
{
p_Mem->current--;
p_Mem->p_BlocksStack[p_Mem->current] = (uint8_t *)p_Block;
return E_OK;
}
RETURN_ERROR(MAJOR, E_FULL, NO_MSG);
}
#ifdef DEBUG_MEM_LEAKS
static t_Error InitMemDebugDatabase(t_MemorySegment *p_Mem)
{
p_Mem->p_MemDbg = (void *)XX_Malloc(sizeof(t_MemDbg) * p_Mem->num);
if (!p_Mem->p_MemDbg)
{
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory debug object"));
}
memset(p_Mem->p_MemDbg, ILLEGAL_BASE, sizeof(t_MemDbg) * p_Mem->num);
return E_OK;
}
static t_Error DebugMemGet(t_Handle h_Mem, void *p_Block, uintptr_t ownerAddress)
{
t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
uint32_t blockIndex;
ASSERT_COND(ownerAddress != ILLEGAL_BASE);
if (p_Mem->consecutiveMem)
{
blockIndex =
(((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
}
else
{
blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
}
ASSERT_COND(blockIndex < p_Mem->num);
ASSERT_COND(p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE);
p_MemDbg[blockIndex].ownerAddress = ownerAddress;
return E_OK;
}
static t_Error DebugMemPut(t_Handle h_Mem, void *p_Block)
{
t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
uint32_t blockIndex;
uint8_t *p_Temp;
if (p_Mem->consecutiveMem)
{
blockIndex =
(((uint8_t *)p_Block - (p_Mem->p_Bases[0] + p_Mem->blockOffset)) / p_Mem->blockSize);
if (blockIndex >= p_Mem->num)
{
RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
("Freed address (0x%08x) does not belong to this pool", p_Block));
}
}
else
{
blockIndex = *(uint32_t *)((uint8_t *)p_Block - 4);
if (blockIndex >= p_Mem->num)
{
RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
("Freed address (0x%08x) does not belong to this pool", p_Block));
}
p_Temp = p_Mem->p_Bases[blockIndex];
ALIGN_BLOCK(p_Temp, p_Mem->prefixSize, p_Mem->alignment);
if (p_Temp == p_Mem->p_Bases[blockIndex])
p_Temp += p_Mem->alignment;
if (p_Temp != p_Block)
{
RETURN_ERROR(MAJOR, E_INVALID_ADDRESS,
("Freed address (0x%08x) does not belong to this pool", p_Block));
}
}
if (p_MemDbg[blockIndex].ownerAddress == ILLEGAL_BASE)
{
RETURN_ERROR(MAJOR, E_ALREADY_FREE,
("Attempt to free unallocated address (0x%08x)", p_Block));
}
p_MemDbg[blockIndex].ownerAddress = (uintptr_t)ILLEGAL_BASE;
return E_OK;
}
#endif
uint32_t MEM_ComputePartitionSize(uint32_t num,
uint16_t dataSize,
uint16_t prefixSize,
uint16_t postfixSize,
uint16_t alignment)
{
uint32_t blockSize = 0, pad1 = 0, pad2 = 0;
if (alignment < 4)
{
alignment = 4;
}
pad1 = (uint32_t)PAD_ALIGNMENT(4, prefixSize);
blockSize = pad1 + prefixSize + dataSize + postfixSize;
pad2 = PAD_ALIGNMENT(alignment, blockSize);
blockSize += pad2;
return ((num * blockSize) + alignment);
}
t_Error MEM_Init(char name[],
t_Handle *p_Handle,
uint32_t num,
uint16_t dataSize,
uint16_t prefixSize,
uint16_t postfixSize,
uint16_t alignment)
{
uint8_t *p_Memory;
uint32_t allocSize;
t_Error errCode;
allocSize = MEM_ComputePartitionSize(num,
dataSize,
prefixSize,
postfixSize,
alignment);
p_Memory = (uint8_t *)XX_Malloc(allocSize);
if (!p_Memory)
{
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment"));
}
errCode = MEM_InitByAddress(name,
p_Handle,
num,
dataSize,
prefixSize,
postfixSize,
alignment,
p_Memory);
if (errCode != E_OK)
{
RETURN_ERROR(MAJOR, errCode, NO_MSG);
}
((t_MemorySegment *)(*p_Handle))->allocOwner = e_MEM_ALLOC_OWNER_LOCAL;
return E_OK;
}
t_Error MEM_InitByAddress(char name[],
t_Handle *p_Handle,
uint32_t num,
uint16_t dataSize,
uint16_t prefixSize,
uint16_t postfixSize,
uint16_t alignment,
uint8_t *p_Memory)
{
t_MemorySegment *p_Mem;
uint32_t i, blockSize;
uint16_t alignPad, endPad;
uint8_t *p_Blocks;
*p_Handle = NULL;
if (!p_Memory)
{
RETURN_ERROR(MAJOR, E_NULL_POINTER, ("Memory blocks"));
}
p_Blocks = p_Memory;
if (alignment < 4)
{
alignment = 4;
}
else if (!POWER_OF_2(alignment))
{
RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
}
p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
if (!p_Mem)
{
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
}
p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
if (!p_Mem->p_BlocksStack)
{
XX_Free(p_Mem);
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
}
p_Mem->p_Bases = (uint8_t **)XX_Malloc(sizeof(uint8_t*));
if (!p_Mem->p_Bases)
{
MEM_Free(p_Mem);
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
}
memset(p_Mem->p_Bases, 0, sizeof(uint8_t*));
p_Mem->num = num;
p_Mem->current = 0;
p_Mem->dataSize = dataSize;
p_Mem->p_Bases[0] = p_Blocks;
p_Mem->getFailures = 0;
p_Mem->allocOwner = e_MEM_ALLOC_OWNER_EXTERNAL;
p_Mem->consecutiveMem = TRUE;
p_Mem->prefixSize = prefixSize;
p_Mem->postfixSize = postfixSize;
p_Mem->alignment = alignment;
strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
p_Mem->h_Spinlock = XX_InitSpinlock();
if (!p_Mem->h_Spinlock)
{
MEM_Free(p_Mem);
RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
}
alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
endPad = (uint16_t)PAD_ALIGNMENT(alignment, (alignPad + prefixSize + dataSize + postfixSize));
ALIGN_BLOCK(p_Blocks, prefixSize, alignment);
blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
for (i=0; i < num; i++)
{
p_Mem->p_BlocksStack[i] = p_Blocks;
p_Blocks += blockSize;
}
*p_Handle = (t_Handle)p_Mem;
#ifdef DEBUG_MEM_LEAKS
{
t_Error errCode = InitMemDebugDatabase(p_Mem);
if (errCode != E_OK)
RETURN_ERROR(MAJOR, errCode, NO_MSG);
p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
p_Mem->blockSize = blockSize;
}
#endif
return E_OK;
}
t_Error MEM_InitSmart(char name[],
t_Handle *p_Handle,
uint32_t num,
uint16_t dataSize,
uint16_t prefixSize,
uint16_t postfixSize,
uint16_t alignment,
uint8_t memPartitionId,
bool consecutiveMem)
{
t_MemorySegment *p_Mem;
uint32_t i, blockSize;
uint16_t alignPad, endPad;
*p_Handle = NULL;
if (dataSize & 3)
{
dataSize &= ~3;
dataSize += 4;
}
if (alignment < 4)
{
alignment = 4;
}
else if (!POWER_OF_2(alignment))
{
RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Alignment (should be power of 2)"));
}
p_Mem = (t_MemorySegment *)XX_Malloc(sizeof(t_MemorySegment));
if (!p_Mem)
{
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment structure"));
}
p_Mem->p_BlocksStack = (uint8_t **)XX_Malloc(num * sizeof(uint8_t*));
if (!p_Mem->p_BlocksStack)
{
MEM_Free(p_Mem);
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment block pointers stack"));
}
p_Mem->p_Bases = (uint8_t **)XX_Malloc((consecutiveMem ? 1 : num) * sizeof(uint8_t*));
if (!p_Mem->p_Bases)
{
MEM_Free(p_Mem);
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment base pointers array"));
}
memset(p_Mem->p_Bases, 0, (consecutiveMem ? 1 : num) * sizeof(uint8_t*));
p_Mem->num = num;
p_Mem->current = 0;
p_Mem->dataSize = dataSize;
p_Mem->getFailures = 0;
p_Mem->allocOwner = e_MEM_ALLOC_OWNER_LOCAL_SMART;
p_Mem->consecutiveMem = consecutiveMem;
p_Mem->prefixSize = prefixSize;
p_Mem->postfixSize = postfixSize;
p_Mem->alignment = alignment;
p_Mem->h_Spinlock = XX_InitSpinlock();
if (!p_Mem->h_Spinlock)
{
MEM_Free(p_Mem);
RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't create spinlock!"));
}
alignPad = (uint16_t)PAD_ALIGNMENT(4, prefixSize);
endPad = (uint16_t)PAD_ALIGNMENT(alignment, alignPad + prefixSize + dataSize + postfixSize);
blockSize = (uint32_t)(alignPad + prefixSize + dataSize + postfixSize + endPad);
if (p_Mem->consecutiveMem)
{
uint8_t *p_Blocks = (uint8_t *)
XX_MallocSmart((uint32_t)((num * blockSize) + alignment), memPartitionId, 1);
if (!p_Blocks)
{
MEM_Free(p_Mem);
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
}
p_Mem->p_Bases[0] = p_Blocks;
ALIGN_BLOCK(p_Blocks, prefixSize, alignment);
for (i = 0; i < num; i++)
{
p_Mem->p_BlocksStack[i] = p_Blocks;
p_Blocks += blockSize;
}
#ifdef DEBUG_MEM_LEAKS
p_Mem->blockOffset = (uint32_t)(p_Mem->p_BlocksStack[0] - p_Mem->p_Bases[0]);
p_Mem->blockSize = blockSize;
#endif
}
else
{
for (i = 0; i < num; i++)
{
uint8_t *p_Block = (uint8_t *)
XX_MallocSmart((uint32_t)(blockSize + alignment), memPartitionId, 1);
if (!p_Block)
{
MEM_Free(p_Mem);
RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory segment blocks"));
}
p_Mem->p_Bases[i] = p_Block;
ALIGN_BLOCK(p_Block, prefixSize, alignment);
#ifdef DEBUG_MEM_LEAKS
if (p_Block == p_Mem->p_Bases[i])
p_Block += alignment;
*(uint32_t *)(p_Block - 4) = i;
#endif
p_Mem->p_BlocksStack[i] = p_Block;
}
}
strncpy(p_Mem->name, name, MEM_MAX_NAME_LENGTH-1);
*p_Handle = (t_Handle)p_Mem;
#ifdef DEBUG_MEM_LEAKS
{
t_Error errCode = InitMemDebugDatabase(p_Mem);
if (errCode != E_OK)
RETURN_ERROR(MAJOR, errCode, NO_MSG);
}
#endif
return E_OK;
}
void MEM_Free(t_Handle h_Mem)
{
t_MemorySegment *p_Mem = (t_MemorySegment*)h_Mem;
uint32_t num, i;
MEM_CheckLeaks(h_Mem);
if (p_Mem)
{
num = p_Mem->consecutiveMem ? 1 : p_Mem->num;
if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL_SMART)
{
for (i=0; i < num; i++)
{
if (p_Mem->p_Bases[i])
{
XX_FreeSmart(p_Mem->p_Bases[i]);
}
}
}
else if (p_Mem->allocOwner == e_MEM_ALLOC_OWNER_LOCAL)
{
for (i=0; i < num; i++)
{
if (p_Mem->p_Bases[i])
{
XX_Free(p_Mem->p_Bases[i]);
}
}
}
if (p_Mem->h_Spinlock)
XX_FreeSpinlock(p_Mem->h_Spinlock);
if (p_Mem->p_Bases)
XX_Free(p_Mem->p_Bases);
if (p_Mem->p_BlocksStack)
XX_Free(p_Mem->p_BlocksStack);
#ifdef DEBUG_MEM_LEAKS
if (p_Mem->p_MemDbg)
XX_Free(p_Mem->p_MemDbg);
#endif
XX_Free(p_Mem);
}
}
void * MEM_Get(t_Handle h_Mem)
{
t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
uint8_t *p_Block;
uint32_t intFlags;
#ifdef DEBUG_MEM_LEAKS
uintptr_t callerAddr = 0;
GET_CALLER_ADDR;
#endif
ASSERT_COND(h_Mem);
intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
if ((p_Block = (uint8_t *)MemGet(p_Mem)) == NULL)
{
XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
return NULL;
}
#ifdef DEBUG_MEM_LEAKS
DebugMemGet(p_Mem, p_Block, callerAddr);
#endif
XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
return (void *)p_Block;
}
uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[])
{
t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
uint32_t availableBlocks;
register uint32_t i;
uint32_t intFlags;
#ifdef DEBUG_MEM_LEAKS
uintptr_t callerAddr = 0;
GET_CALLER_ADDR;
#endif
ASSERT_COND(h_Mem);
intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
availableBlocks = (uint32_t)(p_Mem->num - p_Mem->current);
if (num > availableBlocks)
{
num = availableBlocks;
}
for (i=0; i < num; i++)
{
if ((array[i] = MemGet(p_Mem)) == NULL)
{
break;
}
#ifdef DEBUG_MEM_LEAKS
DebugMemGet(p_Mem, array[i], callerAddr);
#endif
}
XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
return (uint16_t)i;
}
t_Error MEM_Put(t_Handle h_Mem, void *p_Block)
{
t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
t_Error rc;
uint32_t intFlags;
ASSERT_COND(h_Mem);
intFlags = XX_LockIntrSpinlock(p_Mem->h_Spinlock);
if ((rc = MemPut(p_Mem, p_Block)) != E_OK)
{
XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
RETURN_ERROR(MAJOR, rc, NO_MSG);
}
#ifdef DEBUG_MEM_LEAKS
DebugMemPut(p_Mem, p_Block);
#endif
XX_UnlockIntrSpinlock(p_Mem->h_Spinlock, intFlags);
return E_OK;
}
#ifdef DEBUG_MEM_LEAKS
void MEM_CheckLeaks(t_Handle h_Mem)
{
t_MemorySegment *p_Mem = (t_MemorySegment *)h_Mem;
t_MemDbg *p_MemDbg = (t_MemDbg *)p_Mem->p_MemDbg;
uint8_t *p_Block;
int i;
ASSERT_COND(h_Mem);
if (p_Mem->consecutiveMem)
{
for (i=0; i < p_Mem->num; i++)
{
if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
{
p_Block = ((p_Mem->p_Bases[0] + p_Mem->blockOffset) +
(i * p_Mem->blockSize));
XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
p_Block, p_MemDbg[i].ownerAddress);
}
}
}
else
{
for (i=0; i < p_Mem->num; i++)
{
if (p_MemDbg[i].ownerAddress != ILLEGAL_BASE)
{
p_Block = p_Mem->p_Bases[i];
ALIGN_BLOCK(p_Block, p_Mem->prefixSize, p_Mem->alignment);
if (p_Block == p_Mem->p_Bases[i])
p_Block += p_Mem->alignment;
XX_Print("MEM leak: 0x%08x, Caller address: 0x%08x\n",
p_Block, p_MemDbg[i].ownerAddress);
}
}
}
}
#endif
#endif