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 30extern "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 39 void* operator new(size_t size) 40 { 41 return (PortNew(size)); 42 } 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 */ 52static int portNewCount = 0; 53static 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 */ 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 */ 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 */ 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 */ 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 */ 211 void PortMemSetPoolSize(size_t sizeInBytes) 212 { 213 MEM_MGR_SetPoolSize(sizeInBytes); 214 } 215 216 /* PortMemoryInit() : 217 */ 218 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 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 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 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 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 */ 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 */ 351 void PortMemCntReset() 352 { 353 portNewCount = 0; 354 portDeleteCount = 0; 355 } 356 357 358 /* PortMemGetCount() : return the accumulated new & delete counts */ 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