1 /*---------------------------------------------------------------------------* 2 * pmemory_ext.c * 3 * * 4 * Copyright 2007, 2008 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20 21 22 #include "pmemory.h" 23 #include "ptrd.h" 24 #include "pmutex.h" 25 #include "passert.h" 26 #include "pmemory_ext.h" 27 #include "pmalloc.h" 28 29 #ifdef __cplusplus 30 extern "C" 31 { 32 #endif 33 34 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) 35 static MUTEX memextMutex; 36 #endif 37 38 #ifdef RTXC new(size_t size)39 void* operator new(size_t size) 40 { 41 return (PortNew(size)); 42 } delete(void * ptr)43 void operator delete(void* ptr) 44 { 45 PortDelete(ptr); 46 } 47 #endif 48 49 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) 50 51 /* to assist with leak checking */ 52 static int portNewCount = 0; 53 static int portDeleteCount = 0; 54 55 /* enable writing and checking of guard words if debugging is enabled */ 56 #ifdef _DEBUG 57 /* crash on Xanavi's board with this option on, do not know why */ 58 /* #define DBG_GUARD_WORDS */ 59 #endif /* _DEBUG */ 60 61 /* ************************************************************************************ 62 * PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR || PORTABLE_DINKUM_MEM_MGR || PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME 63 * ************************************************************************************/ 64 65 /* data ******************************************************************************/ 66 67 static BOOL gMemoryInitted = FALSE; /* TODO: Temporary fix to PortTerm failure */ 68 69 #define MEM_MGR_GetPoolSize() PortMallocGetPoolSize() 70 #define MEM_MGR_SetPoolSize(sizeInBytes) PortMallocSetPoolSize(sizeInBytes) 71 #define MEM_MGR_Init() PortMallocInit() 72 #define MEM_MGR_Term() PortMallocTerm() 73 #define MEM_MGR_Allocate(sizeInBytes) PortMalloc(sizeInBytes) 74 #define MEM_MGR_Free(objectPtr) PortFree(objectPtr) 75 #define MEM_MGR_Dump() 76 #define MEM_MGR_GetMaxMemUsed() PortMallocGetMaxMemUsed() 77 78 /* guard word data ********************************************************/ 79 80 #ifdef DBG_GUARD_WORDS 81 #define GUARD_BEGIN 0xbbbbbbbb 82 #define GUARD_END 0xeeeeeeee 83 84 #define GUARD_OFF_REQ_SIZE 0 85 #define GUARD_OFF_START sizeof(unsigned int) 86 #define GUARD_OFF_PTR (sizeof(unsigned int) + sizeof(unsigned int)) 87 #define GUARD_EXTRA (sizeof(unsigned int) + sizeof(unsigned int) + sizeof(unsigned int)) 88 #define GUARD_OFF_END(allocSize) ((allocSize) - sizeof(unsigned int)) 89 #define GUARD_ALLOC_SIZE(reqSize) ((reqSize)+GUARD_EXTRA) 90 91 #define GUARD_PTR_FIELD(ptr,off) (unsigned int *)((char *)(ptr) + (off)) 92 #define GUARD_ALLOC_PTR(ptr) (void*) ((char *)(ptr) - GUARD_OFF_PTR) 93 #endif 94 95 /* scan guard words data **************************************************/ 96 97 /* maintain a static list of allocated blocks (didn't want to perform any dynamic allocation). 98 * This list can be scanned by PortMemScan() to determine if any allocated blocks 99 * have overwritten their guard words. 100 * Calling PortDelete() will check guard words upon de-allocation, but many 101 * allocated blocks are only freed at program termination, which sometimes doesn't happen. 102 * 103 * This software is enabled separately with DBG_SCAN_GUARD_WORDS, because the performance 104 * overhead is severe. 105 */ 106 #ifdef DBG_SCAN_GUARD_WORDS 107 #define MAX_ALLOCATED_BLOCKS 80000 108 static void *allocArray[MAX_ALLOCATED_BLOCKS+1]; 109 static int allocArrayCount = 0; 110 111 void AddToAllocList(void *memPtr); 112 void RemoveFromAllocList(void *memPtr); 113 114 #define ADD_TO_ALLOC_LIST(ptr) AddToAllocList(ptr) 115 #define REMOVE_FROM_ALLOC_LIST(ptr) RemoveFromAllocList(ptr) 116 117 #else 118 #define ADD_TO_ALLOC_LIST(ptr) 119 #define REMOVE_FROM_ALLOC_LIST(ptr) 120 #endif 121 122 /* Guard Functions ********************************************************/ 123 124 #ifdef DBG_SCAN_GUARD_WORDS 125 /* AddToAllocList() : maintain an array of allocated blocks that can be 126 * used by PortMemScan() to check for overwritten guard words. 127 */ AddToAllocList(void * memPtr)128 void AddToAllocList(void *memPtr) 129 { 130 allocArray[allocArrayCount] = memPtr; 131 allocArrayCount++; 132 if (allocArrayCount >= MAX_ALLOCATED_BLOCKS) 133 { 134 char buf[256]; 135 sprintf(buf, "AddToAllocList ERROR : MAX_ALLOCATED_BLOCKS is too small (%d)", allocArrayCount); 136 PORT_INTERNAL_ERROR(buf); 137 } 138 } 139 140 /* RemoveFromAllocList() : maintain an array of allocated blocks that can be 141 * used by PortMemScan() to check for overwritten guard words. 142 */ RemoveFromAllocList(void * memPtr)143 void RemoveFromAllocList(void *memPtr) 144 { 145 int i; /* loop index */ 146 int j; /* loop index */ 147 int inList = FALSE; /* TRUE when found in list */ 148 149 for (i = 0; i < allocArrayCount; i++) 150 { 151 if (allocArray[i] == memPtr) 152 { 153 inList = TRUE; 154 break; 155 } 156 } 157 PORT_ASSERT(inList == TRUE); /* MUST be in list */ 158 /* remove by sliding down all following entries */ 159 for (j = i + 1; j < allocArrayCount; j++) 160 allocArray[j-1] = allocArray[j]; 161 allocArrayCount--; 162 allocArray[allocArrayCount] = NULL; /* clear out end of list */ 163 } 164 165 /* PortMemScan() : scan the array of allocated blocks, confirming that no 166 * allocated block has overwritten its guard words. 167 */ PortMemScan(void)168 void PortMemScan(void) 169 { 170 int i; 171 172 PortCriticalSectionEnter(&PortMemoryCriticalSection); 173 174 /* scan the allocated memory list */ 175 for (i = 0; i < allocArrayCount; i++) 176 { 177 /* verify that guard words have not been corrupted */ 178 void *memPtr = allocArray[i]; 179 void *allocPtr = GUARD_ALLOC_PTR(memPtr); 180 unsigned int *requestedSizePtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE); 181 unsigned int *guardStartPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START); 182 unsigned int *guardEndPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr))); 183 184 if ((*guardStartPtr) != GUARD_BEGIN) 185 { 186 PLogError("PortMemScan : corrupted start guard from block 0x%08x \n", (int)memPtr); 187 } 188 if ((*guardEndPtr) != GUARD_END) 189 { 190 PLogError("PortMemScan : corrupted end guard from block 0x%08x \n", (int)memPtr); 191 } 192 } 193 194 PortCriticalSectionLeave(&PortMemoryCriticalSection); 195 } 196 #endif /* DBG_SCAN_GUARD_WORDS */ 197 198 /* Port Memory Functions ******************************************************/ 199 200 /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if 201 * unknown. 202 */ PortMemGetPoolSize(void)203 int PortMemGetPoolSize(void) 204 { 205 return MEM_MGR_GetPoolSize(); 206 } 207 208 /* PortMemSetPoolSize() : set size of portable memory pool on PSOS. 209 * This must be called before PortMemoryInit(), which is called by PortInit(). 210 */ PortMemSetPoolSize(size_t sizeInBytes)211 void PortMemSetPoolSize(size_t sizeInBytes) 212 { 213 MEM_MGR_SetPoolSize(sizeInBytes); 214 } 215 216 /* PortMemoryInit() : 217 */ 218 PortMemoryInit(void)219 int PortMemoryInit(void) 220 { 221 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) 222 if (createMutex(&memextMutex) == ESR_SUCCESS) 223 #endif 224 { 225 if (!gMemoryInitted) 226 { 227 MEM_MGR_Init(); 228 gMemoryInitted = TRUE; 229 } 230 } 231 232 return gMemoryInitted; 233 } 234 235 /* PortMemoryTerm() : 236 */ 237 PortMemoryTerm(void)238 void PortMemoryTerm(void) 239 { 240 /* TODO: MEM_PSOS_BLOCK_SCHEME 241 * Figure out why free memory causes rn#0 is get messed up! */ 242 MEM_MGR_Term(); 243 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) 244 deleteMutex(&memextMutex); 245 #endif 246 gMemoryInitted = FALSE; 247 } 248 249 /* PortNew() : 250 */ 251 PortNew(size_t sizeInBytes)252 void* PortNew(size_t sizeInBytes) 253 { 254 if (gMemoryInitted) 255 { 256 void *pMemory = NULL; 257 258 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) 259 lockMutex(&memextMutex); 260 #endif 261 portNewCount++; 262 263 #ifdef DBG_GUARD_WORDS 264 sizeInBytes += GUARD_EXTRA; /* space for: requestedSize,guardStart,guardEnd */ 265 #endif 266 267 pMemory = MEM_MGR_Allocate(sizeInBytes); 268 269 #ifdef DBG_GUARD_WORDS 270 if (NULL != pMemory) 271 { 272 /* at the beginning of the buffer, store the requested size and a guard word. 273 * Store another guard word at the end of the buffer. 274 */ 275 /* set guard words at either end of allocated buffer; will be checked at delete time */ 276 unsigned int * requestedSizePtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_REQ_SIZE); 277 unsigned int * guardStartPtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_START); 278 unsigned int * guardEndPtr = GUARD_PTR_FIELD(pMemory, GUARD_OFF_END(sizeInBytes)); 279 280 *requestedSizePtr = sizeInBytes - GUARD_EXTRA; 281 *guardStartPtr = GUARD_BEGIN; 282 *guardEndPtr = GUARD_END; 283 pMemory = (void *) GUARD_PTR_FIELD(pMemory, GUARD_OFF_PTR); 284 ADD_TO_ALLOC_LIST(pMemory); 285 } 286 #endif /* DBG_GUARD_WORDS */ 287 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) 288 unlockMutex(&memextMutex); 289 #endif 290 return pMemory; 291 } 292 #ifdef PSOSIM 293 /* PSOSIM's license manager calls new() before PSOS is running */ 294 else 295 { 296 return(malloc(sizeInBytes)); 297 } 298 #else /* PSOSIM */ 299 /* Memory allocator not initialized when request for memory was made */ 300 passert(FALSE && "Call PortInit() before calling any portable functions\r\n"); 301 return NULL; 302 #endif /* PSOSIM */ 303 } 304 PortDelete(void * objectPtr)305 void PortDelete(void* objectPtr) 306 { 307 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) 308 lockMutex(&memextMutex); 309 #endif 310 portDeleteCount++; 311 312 #ifdef DBG_GUARD_WORDS 313 { 314 /* verify that guard words have not been corrupted */ 315 void *allocPtr = GUARD_ALLOC_PTR(objectPtr); 316 unsigned int *requestedSizePtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE); 317 unsigned int *guardStartPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START); 318 unsigned int *guardEndPtr = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr))); 319 320 passert((*guardStartPtr) == GUARD_BEGIN); 321 passert((*guardEndPtr) == GUARD_END); 322 REMOVE_FROM_ALLOC_LIST(allocPtr); 323 objectPtr = allocPtr; 324 } 325 #endif 326 327 MEM_MGR_Free(objectPtr); 328 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT) 329 unlockMutex(&memextMutex); 330 #endif 331 } 332 PortMemTrackDump(void)333 void PortMemTrackDump(void) 334 { 335 MEM_MGR_Dump(); 336 } 337 338 /* PortGetMaxMemUsed() : return the maximum real memory allocated. 339 * There is another function of the same name in pmalloc.c, for tracking 340 * non-psos block memory. It uses #ifndef MEM_PSOS_BLOCK_SCHEME to enable. 341 */ PortGetMaxMemUsed(void)342 int PortGetMaxMemUsed(void) 343 { 344 return MEM_MGR_GetMaxMemUsed(); 345 } 346 347 /* PortMemCntReset() : reset the New/Delete count. 348 * This is useful for checking that each new has a corresponding delete once 349 * the system gets into a steady state. 350 */ PortMemCntReset()351 void PortMemCntReset() 352 { 353 portNewCount = 0; 354 portDeleteCount = 0; 355 } 356 357 358 /* PortMemGetCount() : return the accumulated new & delete counts */ PortMemGetCount(int * newCount,int * deleteCount)359 void PortMemGetCount(int *newCount, int *deleteCount) 360 { 361 *newCount = portNewCount; 362 *deleteCount = portDeleteCount; 363 } 364 365 #endif /* (==PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR) || (==PORTABLE_DINKUM_MEM_MGR) || (==PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) */ 366 367 #ifdef __cplusplus 368 } 369 #endif 370