/*---------------------------------------------------------------------------* * pmemory_ext.c * * * * Copyright 2007, 2008 Nuance Communciations, Inc. * * * * Licensed under the Apache License, Version 2.0 (the 'License'); * * you may not use this file except in compliance with the License. * * * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an 'AS IS' BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * *---------------------------------------------------------------------------*/ #include "pmemory.h" #include "ptrd.h" #include "pmutex.h" #include "passert.h" #include "pmemory_ext.h" #include "pmalloc.h" #ifdef __cplusplus extern "C" { #endif #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) static MUTEX memextMutex; #endif #ifdef RTXC void* operator new(size_t size) { return (PortNew(size)); } void operator delete(void* ptr) { PortDelete(ptr); } #endif #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) /* to assist with leak checking */ static int portNewCount = 0; static int portDeleteCount = 0; /* enable writing and checking of guard words if debugging is enabled */ #ifdef _DEBUG /* crash on Xanavi's board with this option on, do not know why */ /* #define DBG_GUARD_WORDS */ #endif /* _DEBUG */ /* ************************************************************************************ * PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR || PORTABLE_DINKUM_MEM_MGR || PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME * ************************************************************************************/ /* data ******************************************************************************/ static BOOL gMemoryInitted = FALSE; /* TODO: Temporary fix to PortTerm failure */ #define MEM_MGR_GetPoolSize() PortMallocGetPoolSize() #define MEM_MGR_SetPoolSize(sizeInBytes) PortMallocSetPoolSize(sizeInBytes) #define MEM_MGR_Init() PortMallocInit() #define MEM_MGR_Term() PortMallocTerm() #define MEM_MGR_Allocate(sizeInBytes) PortMalloc(sizeInBytes) #define MEM_MGR_Free(objectPtr) PortFree(objectPtr) #define MEM_MGR_Dump() #define MEM_MGR_GetMaxMemUsed() PortMallocGetMaxMemUsed() /* guard word data ********************************************************/ #ifdef DBG_GUARD_WORDS #define GUARD_BEGIN 0xbbbbbbbb #define GUARD_END 0xeeeeeeee #define GUARD_OFF_REQ_SIZE 0 #define GUARD_OFF_START sizeof(unsigned int) #define GUARD_OFF_PTR (sizeof(unsigned int) + sizeof(unsigned int)) #define GUARD_EXTRA (sizeof(unsigned int) + sizeof(unsigned int) + sizeof(unsigned int)) #define GUARD_OFF_END(allocSize) ((allocSize) - sizeof(unsigned int)) #define GUARD_ALLOC_SIZE(reqSize) ((reqSize)+GUARD_EXTRA) #define GUARD_PTR_FIELD(ptr,off) (unsigned int *)((char *)(ptr) + (off)) #define GUARD_ALLOC_PTR(ptr) (void*) ((char *)(ptr) - GUARD_OFF_PTR) #endif /* scan guard words data **************************************************/ /* maintain a static list of allocated blocks (didn't want to perform any dynamic allocation). * This list can be scanned by PortMemScan() to determine if any allocated blocks * have overwritten their guard words. * Calling PortDelete() will check guard words upon de-allocation, but many * allocated blocks are only freed at program termination, which sometimes doesn't happen. * * This software is enabled separately with DBG_SCAN_GUARD_WORDS, because the performance * overhead is severe. */ #ifdef DBG_SCAN_GUARD_WORDS #define MAX_ALLOCATED_BLOCKS 80000 static void *allocArray[MAX_ALLOCATED_BLOCKS+1]; static int allocArrayCount = 0; void AddToAllocList(void *memPtr); void RemoveFromAllocList(void *memPtr); #define ADD_TO_ALLOC_LIST(ptr) AddToAllocList(ptr) #define REMOVE_FROM_ALLOC_LIST(ptr) RemoveFromAllocList(ptr) #else #define ADD_TO_ALLOC_LIST(ptr) #define REMOVE_FROM_ALLOC_LIST(ptr) #endif /* Guard Functions ********************************************************/ #ifdef DBG_SCAN_GUARD_WORDS /* AddToAllocList() : maintain an array of allocated blocks that can be * used by PortMemScan() to check for overwritten guard words. */ void AddToAllocList(void *memPtr) { allocArray[allocArrayCount] = memPtr; allocArrayCount++; if (allocArrayCount >= MAX_ALLOCATED_BLOCKS) { char buf[256]; sprintf(buf, "AddToAllocList ERROR : MAX_ALLOCATED_BLOCKS is too small (%d)", allocArrayCount); PORT_INTERNAL_ERROR(buf); } } /* RemoveFromAllocList() : maintain an array of allocated blocks that can be * used by PortMemScan() to check for overwritten guard words. */ void RemoveFromAllocList(void *memPtr) { int i; /* loop index */ int j; /* loop index */ int inList = FALSE; /* TRUE when found in list */ for (i = 0; i < allocArrayCount; i++) { if (allocArray[i] == memPtr) { inList = TRUE; break; } } PORT_ASSERT(inList == TRUE); /* MUST be in list */ /* remove by sliding down all following entries */ for (j = i + 1; j < allocArrayCount; j++) allocArray[j-1] = allocArray[j]; allocArrayCount--; allocArray[allocArrayCount] = NULL; /* clear out end of list */ } /* PortMemScan() : scan the array of allocated blocks, confirming that no * allocated block has overwritten its guard words. */ void PortMemScan(void) { int i; PortCriticalSectionEnter(&PortMemoryCriticalSection); /* scan the allocated memory list */ for (i = 0; i < allocArrayCount; i++) { /* verify that guard words have not been corrupted */ void *memPtr = allocArray[i]; void *allocPtr = GUARD_ALLOC_PTR(memPtr); unsigned int *requestedSizePtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE); unsigned int *guardStartPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START); unsigned int *guardEndPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr))); if ((*guardStartPtr) != GUARD_BEGIN) { PLogError("PortMemScan : corrupted start guard from block 0x%08x \n", (int)memPtr); } if ((*guardEndPtr) != GUARD_END) { PLogError("PortMemScan : corrupted end guard from block 0x%08x \n", (int)memPtr); } } PortCriticalSectionLeave(&PortMemoryCriticalSection); } #endif /* DBG_SCAN_GUARD_WORDS */ /* Port Memory Functions ******************************************************/ /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if * unknown. */ int PortMemGetPoolSize(void) { return MEM_MGR_GetPoolSize(); } /* PortMemSetPoolSize() : set size of portable memory pool on PSOS. * This must be called before PortMemoryInit(), which is called by PortInit(). */ void PortMemSetPoolSize(size_t sizeInBytes) { MEM_MGR_SetPoolSize(sizeInBytes); } /* PortMemoryInit() : */ int PortMemoryInit(void) { #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) if (createMutex(&memextMutex) == ESR_SUCCESS) #endif { if (!gMemoryInitted) { MEM_MGR_Init(); gMemoryInitted = TRUE; } } return gMemoryInitted; } /* PortMemoryTerm() : */ void PortMemoryTerm(void) { /* TODO: MEM_PSOS_BLOCK_SCHEME * Figure out why free memory causes rn#0 is get messed up! */ MEM_MGR_Term(); #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) deleteMutex(&memextMutex); #endif gMemoryInitted = FALSE; } /* PortNew() : */ void* PortNew(size_t sizeInBytes) { if (gMemoryInitted) { void *pMemory = NULL; #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) lockMutex(&memextMutex); #endif portNewCount++; #ifdef DBG_GUARD_WORDS sizeInBytes += GUARD_EXTRA; /* space for: requestedSize,guardStart,guardEnd */ #endif pMemory = MEM_MGR_Allocate(sizeInBytes); #ifdef DBG_GUARD_WORDS if (NULL != pMemory) { /* at the beginning of the buffer, store the requested size and a guard word. * Store another guard word at the end of the buffer. */ /* set guard words at either end of allocated buffer; will be checked at delete time */ unsigned int * requestedSizePtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_REQ_SIZE); unsigned int * guardStartPtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_START); unsigned int * guardEndPtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_END(sizeInBytes)); *requestedSizePtr = sizeInBytes - GUARD_EXTRA; *guardStartPtr = GUARD_BEGIN; *guardEndPtr = GUARD_END; pMemory = (void *) GUARD_PTR_FIELD(pMemory, GUARD_OFF_PTR); ADD_TO_ALLOC_LIST(pMemory); } #endif /* DBG_GUARD_WORDS */ #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) unlockMutex(&memextMutex); #endif return pMemory; } #ifdef PSOSIM /* PSOSIM's license manager calls new() before PSOS is running */ else { return(malloc(sizeInBytes)); } #else /* PSOSIM */ /* Memory allocator not initialized when request for memory was made */ passert(FALSE && "Call PortInit() before calling any portable functions\r\n"); return NULL; #endif /* PSOSIM */ } void PortDelete(void* objectPtr) { #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) lockMutex(&memextMutex); #endif portDeleteCount++; #ifdef DBG_GUARD_WORDS { /* verify that guard words have not been corrupted */ void *allocPtr = GUARD_ALLOC_PTR(objectPtr); unsigned int *requestedSizePtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE); unsigned int *guardStartPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START); unsigned int *guardEndPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr))); passert((*guardStartPtr) == GUARD_BEGIN); passert((*guardEndPtr) == GUARD_END); REMOVE_FROM_ALLOC_LIST(allocPtr); objectPtr = allocPtr; } #endif MEM_MGR_Free(objectPtr); #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) unlockMutex(&memextMutex); #endif } void PortMemTrackDump(void) { MEM_MGR_Dump(); } /* PortGetMaxMemUsed() : return the maximum real memory allocated. * There is another function of the same name in pmalloc.c, for tracking * non-psos block memory. It uses #ifndef MEM_PSOS_BLOCK_SCHEME to enable. */ int PortGetMaxMemUsed(void) { return MEM_MGR_GetMaxMemUsed(); } /* PortMemCntReset() : reset the New/Delete count. * This is useful for checking that each new has a corresponding delete once * the system gets into a steady state. */ void PortMemCntReset() { portNewCount = 0; portDeleteCount = 0; } /* PortMemGetCount() : return the accumulated new & delete counts */ void PortMemGetCount(int *newCount, int *deleteCount) { *newCount = portNewCount; *deleteCount = portDeleteCount; } #endif /* (==PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR) || (==PORTABLE_DINKUM_MEM_MGR) || (==PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) */ #ifdef __cplusplus } #endif