| /*---------------------------------------------------------------------------* |
| * 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 |