Changeset 11265 for trunk/psLib/src/sys/psMemory.c
- Timestamp:
- Jan 24, 2007, 12:14:48 PM (19 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/sys/psMemory.c (modified) (33 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/sys/psMemory.c
r10547 r11265 3 3 * @brief Contains the definitions for the memory management system 4 4 * 5 * psMemory.h has additional information and documentation of the routines found in this file. 5 * psMemory.h has additional information and documentation of the routines 6 * found in this file. 6 7 * 7 8 * @author Robert DeSonia, MHPCC 8 9 * @author Robert Lupton, Princeton University 10 * @author Joshua Hoblitt, University of Hawaii 9 11 * 10 * @version $Revision: 1.8 8$ $Name: not supported by cvs2svn $11 * @date $Date: 200 6-12-08 11:35:54$12 * @version $Revision: 1.89 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2007-01-24 22:14:48 $ 12 14 * 13 15 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 14 16 */ 17 18 #if HAVE_CONFIG_H 19 # include "config.h" 20 #endif 15 21 16 22 #define PS_ALLOW_MALLOC // we're allowed to call malloc() … … 22 28 #include <assert.h> 23 29 30 #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE) 31 # include <execinfo.h> 32 #endif 33 24 34 #include "psMemory.h" 25 #include "psError.h" 26 #include "psAssert.h" 27 #include "psAbort.h" 28 #include "psLogMsg.h" 29 #include "psBitSet.h" 30 #include "psFits.h" 31 #include "psPixels.h" 32 #include "psSphereOps.h" 33 #include "psMinimizeLMM.h" 34 #include "psImageConvolve.h" 35 #include "psTime.h" 36 #include "psLine.h" 37 #include "psRegion.h" 38 #include "psHistogram.h" 39 40 #define P_PS_LARGE_BLOCK_SIZE 65536 // size where under, we try to recycle 41 42 static psS32 checkMemBlock(const psMemBlock* m, const char *funcName); 43 static psMemBlock* lastMemBlockAllocated = NULL; 35 #include "psError.h" // for psErrorStackPrint() only 36 37 #define MUTEX_LOCK(mutexPtr) \ 38 if (safeThreads) { \ 39 pthread_mutex_lock(mutexPtr); \ 40 } 41 42 #define MUTEX_UNLOCK(mutexPtr) \ 43 if (safeThreads) { \ 44 pthread_mutex_unlock(mutexPtr); \ 45 } 46 47 // psAbort() calls functions that call psAlloc() so it is *UNSAFE* to use it 48 // from within the memory subsystem. Previous implementations tried to do 49 // this and would deadlock while trying to allocate memory. 50 // 51 // Note that psError() is also *UNSAFE* to use from within the memory 52 // subsystem. 53 #define PS_MEM_ABORT(name, ...) \ 54 P_PS_MEM_ABORT(__FILE__, __LINE__, __func__, name, __VA_ARGS__) 55 56 // psErrorStackPrint() was specifically modified to be safe to call from inside 57 // psMemory.c. 58 #define P_PS_MEM_ABORT(filename, lineno, func, name, ...) \ 59 fprintf(stderr, "%s (%s:%d) ", func, filename, lineno); \ 60 fprintf(stderr, __VA_ARGS__);\ 61 psErrorStackPrint(stderr, "\nAborting. Error stack:\n"); \ 62 fprintf(stderr, "\n");\ 63 abort(); 64 65 #define HANDLE_BAD_BLOCK(memBlock, file, lineo, func) \ 66 if (isBadMemBlock(stderr, memBlock, file, lineo, func)) { \ 67 PS_MEM_ABORT(__func__, "Unsafe to Continue\n"); \ 68 } 69 70 static bool isBadMemBlock(FILE *output, const psMemBlock *memBlock, const char *file, unsigned int lineo, const char *func); 71 72 // pointer to the last mem block that was allocated 73 static psMemBlock *lastMemBlockAllocated = NULL; 74 75 // memBlockListMutex protects access to: 76 // lastMemBlockAllocated 77 // safeThreads 78 // memid 79 // memory_is_persistent 80 // "the linked list of mem blocks" 81 // p_psMemAllocID 82 // p_psMemFreeID 83 // memAllocCallback 84 // memFreeCallback 85 // memExhaustedCallback 86 // 87 // This is a fair ammount of stuff to protect with a single mutex but most of 88 // these items are *VERY* low contention items. The only item that should be 89 // performance issue is "the linked list of mem blocks". If this does become a 90 // problem in production use of the list should be disabled as it is really a 91 // debugging feature. 92 // 93 // XXX make the mem block list a build time option 94 // 44 95 static pthread_mutex_t memBlockListMutex = PTHREAD_MUTEX_INITIALIZER; 45 static pthread_mutex_t memIdMutex = PTHREAD_MUTEX_INITIALIZER;46 96 47 97 //private boolean for enabling/disabling thread safety. Default = enabled. … … 51 101 static bool memory_is_persistent = false; 52 102 53 #ifdef PS_MEM_USE_RECYCLE // Only use recycling if this is set54 #define N_RECYCLE_BINS 14 // number of recycle bins55 #define MAX_RECYCLE 100 // Maximum number permitted in a recycle bin56 static pthread_mutex_t recycleMemBlockListMutex = PTHREAD_MUTEX_INITIALIZER; // Mutex for recycle bins57 static const psS32 recycleBinSize[N_RECYCLE_BINS] = // Size of each bin58 {59 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, P_PS_LARGE_BLOCK_SIZE60 };61 // N.B. recycleBinSize should be terminated by P_PS_LARGE_BLOCK_SIZE (simplifies search loops)62 static psS32 recycleBinNums[N_RECYCLE_BINS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Number in each bin63 static psMemBlock* recycleMemBlockList[N_RECYCLE_BINS] = // Contents of the bins64 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };65 #endif // #ifdef PS_MEM_USE_RECYCLE66 67 #ifdef PS_MEM_DEBUG68 static psMemBlock* deadBlockList; // a place to put dead memBlocks in debug mode.69 #endif // #ifdef PS_MEM_DEBUG70 71 103 /** 72 104 * Unique ID for allocated blocks … … 79 111 static psPtr memExhaustedCallbackDefault(size_t size) 80 112 { 81 #if PS_MEM_USE_RECYCLE82 psPtr ptr = NULL;83 if (safeThreads) {84 pthread_mutex_lock(&recycleMemBlockListMutex);85 }86 // Attempt to free up everything I can find so I can alloc my ptr87 int bin = N_RECYCLE_BINS - 1; // Recycle bin88 89 while (bin >= 0 && ptr == NULL) {90 while (recycleMemBlockList[bin] != NULL && ptr == NULL) {91 psMemBlock *old = recycleMemBlockList[bin];92 recycleMemBlockList[bin] = recycleMemBlockList[bin]->nextBlock;93 free(old);94 ptr = malloc(size);95 }96 bin--;97 }98 99 if (safeThreads) {100 pthread_mutex_unlock(&recycleMemBlockListMutex);101 }102 return ptr;103 #else // #ifdef PS_MEM_USE_RECYCLE104 105 113 return NULL; 106 #endif // #ifdef PS_MEM_USE_RECYCLE107 114 } 108 115 … … 113 120 * isn't resignalled) 114 121 */ 115 static psMemId memAllocCallbackDefault(const psMemBlock * ptr)122 static psMemId memAllocCallbackDefault(const psMemBlock *memBlock) 116 123 { 117 124 static psMemId incr = 0; // "p_psMemAllocID += incr" … … 120 127 } 121 128 122 static psMemId memFreeCallbackDefault(const psMemBlock * ptr)129 static psMemId memFreeCallbackDefault(const psMemBlock *memBlock) 123 130 { 124 131 static psMemId incr = 0; // "p_psMemFreeID += incr" 125 132 126 133 return incr; 127 }128 129 static void memProblemCallbackDefault(psMemBlock* ptr,130 const char *file,131 unsigned int lineno)132 {133 if (ptr->refCounter < 1) {134 psError(PS_ERR_MEMORY_CORRUPTION, false,135 _("Block %lu, allocated at %s:%d, freed multiple times at %s:%d."),136 (unsigned long)ptr->id, ptr->file, ptr->lineno, file, lineno);137 }138 139 if (lineno > 0) {140 psAbort(__func__, "Detected a problem in the memory system at %s:%d", file, lineno);141 }142 134 } 143 135 … … 147 139 * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted 148 140 */ 149 static psS32 checkMemBlock(const psMemBlock* m, 150 const char *funcName) 151 { 152 // n.b. since this is called by psMemCheckCorruption while the memblock list is mutex locked, 153 // we shouldn't call such things as p_psAlloc/p_psFree here. 154 155 if (m == NULL) { 156 psError(PS_ERR_MEMORY_CORRUPTION, true, 157 _("NULL memory block found.")); 158 return 1; 159 } 160 161 if (m->refCounter == 0) { 141 static bool isBadMemBlock(FILE *output, const psMemBlock *memBlock, const char *file, unsigned int lineno, const char *func) 142 { 143 // n.b. since this is called by psMemCheckCorruption while the memblock 144 // list is mutex locked, we shouldn't call such things as 145 // p_psAlloc/p_psFree here. 146 147 bool bad = false; 148 bool blockPrinted = false; 149 150 if (memBlock == NULL) { 151 fprintf(output, _("NULL memory block.\n" 152 "Caught in %s at (%s:%d.).\n\n"), func, file, lineno); 153 // return now as we can't do anything else 154 return true; 155 } 156 157 #if 0 158 // Currently psAlloc()/psRealloc() will blindly create memBlock's with a 159 // size of 0. This test is in here to check if this is really 160 // happening/being use as a feature in the wild. 161 if (memBlock->userMemorySize < 1) { 162 psMemBlockPrint(output, memBlock); 163 blockPrinted = true; 164 fprintf(output, _("\n\tMemory block has a size of less than 1.\n")); 165 bad = true; 166 } 167 #endif 168 169 if (memBlock->refCounter < 1) { 162 170 // using an unreferenced block of memory, are you? 163 psError(PS_ERR_MEMORY_CORRUPTION, true, 164 _("Memory block %lu was freed but still being used."), 165 (unsigned long)m->id); 166 return 1; 167 } 168 169 if (m->startblock != P_PS_MEMMAGIC || m->endblock != P_PS_MEMMAGIC) { 170 psError(PS_ERR_MEMORY_CORRUPTION, true, 171 _("Memory block %lu is corrupted; buffer underflow detected."), 172 (unsigned long)m->id); 173 return 1; 174 } 175 if (*(psPtr *)((int8_t *) (m + 1) + m->userMemorySize) != P_PS_MEMMAGIC) { 176 psError(PS_ERR_MEMORY_CORRUPTION, true, 177 _("Memory block %lu is corrupted; buffer overflow detected."), 178 (unsigned long)m->id); 179 return 1; 180 } 181 182 return 0; 171 psMemBlockPrint(output, memBlock); 172 blockPrinted = true; 173 fprintf(output, _("\n\tMemory block was freed but still being used.\n")); 174 bad = true; 175 } 176 177 if (memBlock->startblock != P_PS_MEMMAGIC || memBlock->endblock != P_PS_MEMMAGIC) { 178 if (!blockPrinted) { 179 psMemBlockPrint(output, memBlock); 180 blockPrinted = true; 181 } 182 fprintf(output, _("\n\tMemory block is corrupted; buffer underflow detected.\n")); 183 bad = true; 184 } 185 186 if (*(psU32 *)((char *)(memBlock + 1) + memBlock->userMemorySize) != P_PS_MEMMAGIC) { 187 if (!blockPrinted) { 188 psMemBlockPrint(output, memBlock); 189 blockPrinted = true; 190 } 191 fprintf(output, _("\n\tMemory block is corrupted; buffer overflow detected.\n")); 192 bad = true; 193 } 194 195 // XXX ->nextBlock, & -> prevousBlock really should not be looked at by 196 // this function as they may be changed out from underneath us by new 197 // memory allocation. However, the memBlock itself shouldn't go away (end 198 // users responsiblity) so all we're really risking is a garbage value. 199 200 if (memBlock == memBlock->nextBlock) { 201 if (!blockPrinted) { 202 psMemBlockPrint(output, memBlock); 203 blockPrinted = true; 204 } 205 fprintf(output, _("\n\tMemory block's ->nextBlock pointer refers to itself.\n")); 206 bad = true; 207 } 208 209 if (memBlock == memBlock->previousBlock) { 210 if (!blockPrinted) { 211 psMemBlockPrint(output, memBlock); 212 blockPrinted = true; 213 } 214 fprintf(output, _("\n\tMemory block's ->previousBlock pointer refers to itself.\n")); 215 bad = true; 216 } 217 218 if (bad) { 219 fprintf(output, _("\tCaught in %s at (%s:%d).\n\n"), func, file, lineno); 220 } 221 222 return bad; 183 223 } 184 224 … … 188 228 * with psMem{Alloc,Free}CallbackSet 189 229 */ 190 static psMemId memAllocCallbackCheckCorruption(const psMemBlock * ptr)230 static psMemId memAllocCallbackCheckCorruption(const psMemBlock *memBlock) 191 231 { 192 232 static psMemId incr = 10; // "p_psMemAllocID += incr" 193 bool abort_on_error = false; 194 195 if (psMemCheckCorruption(abort_on_error) > 0) { 196 fprintf(stderr,"Detected memory corruption\n"); // somewhere to set a breakpoint 233 234 if (psMemCheckCorruption(stderr, false) > 0) { 235 fprintf(stderr, "Detected memory corruption\n"); // somewhere to set a breakpoint 197 236 } 198 237 … … 205 244 static psMemAllocCallback memAllocCallback = memAllocCallbackDefault; 206 245 static psMemFreeCallback memFreeCallback = memFreeCallbackDefault; 207 static psMemProblemCallback memProblemCallback = memProblemCallbackDefault;208 246 static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault; 209 247 210 248 psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func) 211 249 { 250 MUTEX_LOCK(&memBlockListMutex); 251 212 252 psMemExhaustedCallback old = memExhaustedCallback; 213 253 … … 218 258 } 219 259 220 return old; 221 } 222 223 psMemProblemCallback psMemProblemCallbackSet(psMemProblemCallback func) 224 { 225 psMemProblemCallback old = memProblemCallback; 226 227 if (func != NULL) { 228 memProblemCallback = func; 229 } else { 230 memProblemCallback = memProblemCallbackDefault; 231 } 260 MUTEX_UNLOCK(&memBlockListMutex); 232 261 233 262 return old; … … 244 273 psMemId psMemAllocCallbackSetID(psMemId id) 245 274 { 275 MUTEX_LOCK(&memBlockListMutex); 276 246 277 psMemId old = p_psMemAllocID; 247 278 … … 253 284 p_psMemAllocID = id; 254 285 286 MUTEX_UNLOCK(&memBlockListMutex); 287 255 288 return old; 256 289 } … … 258 291 psMemId psMemFreeCallbackSetID(psMemId id) 259 292 { 293 MUTEX_LOCK(&memBlockListMutex); 294 260 295 psMemId old = p_psMemFreeID; 261 296 262 297 p_psMemFreeID = id; 263 298 299 MUTEX_UNLOCK(&memBlockListMutex); 300 264 301 return old; 265 302 } … … 267 304 psMemAllocCallback psMemAllocCallbackSet(psMemAllocCallback func) 268 305 { 306 MUTEX_LOCK(&memBlockListMutex); 307 269 308 psMemFreeCallback old = memAllocCallback; 270 309 … … 275 314 } 276 315 316 MUTEX_UNLOCK(&memBlockListMutex); 317 277 318 return old; 278 319 } … … 280 321 psMemFreeCallback psMemFreeCallbackSet(psMemFreeCallback func) 281 322 { 323 MUTEX_LOCK(&memBlockListMutex); 324 282 325 psMemFreeCallback old = memFreeCallback; 283 326 … … 288 331 } 289 332 333 MUTEX_UNLOCK(&memBlockListMutex); 334 290 335 return old; 291 336 } … … 301 346 psMemId psMemGetLastId(void) 302 347 { 303 if (safeThreads) { 304 pthread_mutex_lock(&memIdMutex); 305 } 348 MUTEX_LOCK(&memBlockListMutex); 306 349 307 350 psMemId id = memid; 308 351 309 if (safeThreads) { 310 pthread_mutex_unlock(&memIdMutex); 311 } 352 MUTEX_UNLOCK(&memBlockListMutex); 312 353 313 354 return id; 314 355 } 315 356 316 int psMemCheckCorruption(bool abort_on_error) 317 { 357 int psMemCheckCorruption(FILE *output, bool abort_on_error) 358 { 359 // get exclusive access to the memBlock list to avoid it changing on us 360 // while we use it. 361 MUTEX_LOCK(&memBlockListMutex); 362 318 363 psS32 nbad = 0; // number of bad blocks 319 psBool failure = false; 320 321 // get exclusive access to the memBlock list to avoid it changing on us while we use it. 322 // pthread_mutex_lock(&memBlockListMutex); 323 324 for (psMemBlock* iter = lastMemBlockAllocated; iter != NULL; iter = iter->nextBlock) { 325 if (safeThreads) { 326 pthread_mutex_unlock(&memBlockListMutex); 327 } 328 failure = checkMemBlock(iter, __func__); 329 if (safeThreads) { 330 pthread_mutex_lock(&memBlockListMutex); 331 } 332 if ( failure ) { 364 for (psMemBlock *memBlock = lastMemBlockAllocated; memBlock != NULL; memBlock = memBlock->nextBlock) { 365 if (isBadMemBlock(output, memBlock, __FILE__, __LINE__, __func__)) { 333 366 nbad++; 334 335 memProblemCallback(iter, __func__, __LINE__);336 367 337 368 if (abort_on_error) { 338 369 // release the lock on the memblock list 339 if (safeThreads) { 340 pthread_mutex_unlock(&memBlockListMutex); 341 } 342 psAbort(__func__, "Detected memory corruption"); 370 MUTEX_UNLOCK(&memBlockListMutex); 371 PS_MEM_ABORT(__func__, "Detected memory corruption"); 343 372 return nbad; 344 373 } … … 347 376 348 377 // release the lock on the memblock list 349 if (safeThreads) { 350 pthread_mutex_unlock(&memBlockListMutex); 351 } 378 MUTEX_UNLOCK(&memBlockListMutex); 379 352 380 return nbad; 353 381 } … … 358 386 bool p_psMemAllocatePersistent(bool is_persistent) 359 387 { 388 MUTEX_LOCK(&memBlockListMutex); 389 360 390 const bool old = memory_is_persistent; 361 391 memory_is_persistent = is_persistent; 362 392 393 MUTEX_UNLOCK(&memBlockListMutex); 394 363 395 return old; 364 396 } 365 366 #ifdef PS_MEM_USE_RECYCLE367 // Return the appropriate recycle bin number368 static int getRecycleBin(size_t size)369 {370 if (size >= P_PS_LARGE_BLOCK_SIZE) {371 return N_RECYCLE_BINS;372 }373 int binNum = 0; // Recycle bin number374 while (size > recycleBinSize[binNum]) {375 binNum++;376 }377 return binNum;378 }379 380 // Push a pointer onto the recycle bin381 static void recyclePush(psMemBlock *mb, // Pointer to push382 int bin // Recycling bin383 )384 {385 assert(mb);386 assert(bin < N_RECYCLE_BINS);387 388 mb->previousBlock = NULL;389 390 if (safeThreads) {391 pthread_mutex_lock(&recycleMemBlockListMutex);392 }393 394 mb->nextBlock = recycleMemBlockList[bin];395 if (recycleMemBlockList[bin] != NULL) {396 recycleMemBlockList[bin]->previousBlock = mb;397 }398 recycleMemBlockList[bin] = mb;399 recycleBinNums[bin]++;400 401 if (safeThreads) {402 pthread_mutex_unlock(&recycleMemBlockListMutex);403 }404 405 return;406 }407 408 // Pop a pointer from the recycle bin409 static psMemBlock *recyclePop(int bin // Recycling bin410 )411 {412 if (bin >= N_RECYCLE_BINS) {413 return NULL;414 }415 416 if (safeThreads) {417 pthread_mutex_lock(&recycleMemBlockListMutex);418 }419 420 psMemBlock *mb = recycleMemBlockList[bin]; // Pointer popped from recycle bin421 422 if (mb) {423 // We pull it off the list424 recycleMemBlockList[bin] = mb->nextBlock;425 if (recycleMemBlockList[bin] != NULL) {426 recycleMemBlockList[bin]->previousBlock = NULL;427 }428 recycleBinNums[bin]--;429 }430 431 if (safeThreads) {432 pthread_mutex_unlock(&recycleMemBlockListMutex);433 }434 435 return mb;436 }437 #endif // #ifdef PS_MEM_USE_RECYCLE438 397 439 398 /* … … 442 401 psPtr p_psAlloc(size_t size, 443 402 const char *file, 444 unsigned int lineno) 445 { 446 447 psMemBlock *ptr = NULL; 448 449 #ifdef PS_MEM_USE_RECYCLE 450 // Are we in one of the recycle bins? 451 int bin = getRecycleBin(size); 452 if (bin < N_RECYCLE_BINS) { 453 size = recycleBinSize[bin]; // round-up size to next sized bin. 454 ptr = recyclePop(bin); // grab out of the recycle bin 455 } 456 #endif // #ifdef PS_MEM_USE_RECYCLE 457 458 if (ptr == NULL) { 459 ptr = malloc(sizeof(psMemBlock) + size + sizeof(psPtr )); 460 461 if (ptr == NULL) { 462 ptr = memExhaustedCallback(size); 463 if (ptr == NULL) { 464 psAbort(__func__, "Failed to allocate %zd bytes at %s:%d", size, file, lineno); 465 } 466 } 467 468 *(psPtr*)&ptr->startblock = P_PS_MEMMAGIC; 469 *(psPtr*)&ptr->endblock = P_PS_MEMMAGIC; 470 ptr->userMemorySize = size; 471 if (safeThreads) { 472 pthread_mutex_init(&ptr->refCounterMutex, NULL); 473 } 474 } 475 // increment the memory id safely. 476 if (safeThreads) { 477 pthread_mutex_lock(&memBlockListMutex); 478 } 479 *(psMemId* ) & ptr->id = ++memid; 480 if (safeThreads) { 481 pthread_mutex_unlock(&memBlockListMutex); 482 } 483 ptr->file = file; 484 ptr->freeFunc = NULL; 485 ptr->persistent = memory_is_persistent; 486 *(psU32 *)&ptr->lineno = lineno; 487 *(psPtr *)((int8_t *) (ptr + 1) + size) = P_PS_MEMMAGIC; 488 ptr->previousBlock = NULL; 489 490 ptr->refCounter = 1; // one user so far 403 unsigned int lineno, 404 const char *func) 405 { 406 407 psMemBlock *memBlock = malloc(sizeof(psMemBlock) + size + sizeof(psPtr)); 408 if (memBlock == NULL) { 409 MUTEX_LOCK(&memBlockListMutex); 410 memBlock = memExhaustedCallback(size); 411 MUTEX_UNLOCK(&memBlockListMutex); 412 if (memBlock == NULL) { 413 PS_MEM_ABORT(__func__, "Failed to allocate %zd bytes at %s (%s:%d)", size, func, file, lineno); 414 } 415 } 416 417 // posts 418 *(psU32 *)&memBlock->startblock = P_PS_MEMMAGIC; 419 *(psU32 *)&memBlock->endblock = P_PS_MEMMAGIC; 420 *(psU32 *)((char *) (memBlock + 1) + size) = P_PS_MEMMAGIC; 421 422 // size of memory allocated 423 memBlock->userMemorySize = size; 424 425 // alloc request by: 426 // thread 427 *(pthread_t *)&memBlock->tid = pthread_self(); 428 // file 429 memBlock->file = file; 430 // line number 431 *(unsigned int *)&memBlock->lineno = (unsigned int)lineno; 432 // function 433 memBlock->func = func; 434 435 #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE) 436 #define BACKTRACE_BUFFER_SIZE 32 437 // psMemBlock.func is a 'const char *', so basically we're going to abuse 438 // that and treat it as a void ** to carry around backtrace information. 439 // psMemBlock is not ifdef'd to make sure that psMemBlock is always the 440 // same size & layout reguardless of the pslib .so that's being linked 441 // against 442 void **bt = malloc(BACKTRACE_BUFFER_SIZE * sizeof(void *)); 443 if (bt == NULL) { 444 PS_MEM_ABORT(__func__, "Failed to allocate memmory for backtrace buffer: %zd bytes at %s (%s:%d)", 32 * sizeof(void *), func, file, lineno); 445 } 446 *(size_t *)&memBlock->backtraceSize = backtrace(bt, BACKTRACE_BUFFER_SIZE); 447 *(void ***)&memBlock->backtrace = bt; 448 #endif // ifdef HAVE_BACKTRACE 449 450 // free function 451 memBlock->freeFunc = NULL; 452 453 // persistent memory flag 454 memBlock->persistent = memory_is_persistent; 455 456 // this block will be add as the last mem block in the list 457 memBlock->previousBlock = NULL; 458 459 // ref count 460 memBlock->refCounter = 1; // one user so far 491 461 492 462 // need exclusive access of the memory block list now... 493 if (safeThreads) { 494 pthread_mutex_lock(&memBlockListMutex); 495 } 463 MUTEX_LOCK(&memBlockListMutex); 464 465 // increment the memory id only after we've grabbed the memBlockListMutex 466 *(psMemId* )&memBlock->id = ++memid; 496 467 497 468 // insert the new block to the front of the memBlock linked-list 498 ptr->nextBlock = lastMemBlockAllocated; 499 if (ptr->nextBlock != NULL) { 500 ptr->nextBlock->previousBlock = ptr; 501 } 502 lastMemBlockAllocated = ptr; 503 504 if (safeThreads) { 505 pthread_mutex_unlock(&memBlockListMutex); 506 } 469 memBlock->nextBlock = lastMemBlockAllocated; 470 if (memBlock->nextBlock != NULL) { 471 memBlock->nextBlock->previousBlock = memBlock; 472 } 473 lastMemBlockAllocated = memBlock; 507 474 508 475 // Did the user ask to be informed about this allocation? 509 if (ptr->id == p_psMemAllocID) { 510 p_psMemAllocID += memAllocCallback(ptr); 511 } 476 if (memBlock->id == p_psMemAllocID) { 477 // p_psMemAllocID can only be changed while the memBlockList mutex is 478 // held 479 p_psMemAllocID += memAllocCallback(memBlock); 480 } 481 482 MUTEX_UNLOCK(&memBlockListMutex); 483 512 484 // And return the user the memory that they allocated 513 return ptr+ 1; // user memory514 } 515 516 psPtr p_psRealloc(psPtr vptr,485 return memBlock + 1; // user memory 486 } 487 488 psPtr p_psRealloc(psPtr ptr, 517 489 size_t size, 518 490 const char *file, 519 unsigned int lineno) 520 { 521 if (vptr == NULL) { 522 return p_psAlloc(size, file, lineno); 523 } 524 525 psMemBlock *ptr = ((psMemBlock*)vptr) - 1; 526 527 if (checkMemBlock(ptr, __func__) != 0) { 528 memProblemCallback(ptr, file, lineno); 529 psAbort(file, "Realloc detected a memory corruption (id %lu @ %s:%d).", 530 (unsigned long)ptr->id, ptr->file, ptr->lineno); 531 } 532 533 #ifdef PS_MEM_USE_RECYCLE 534 // Ensure the size matches that of the recycle bin 535 int bin = getRecycleBin(size); 536 if (bin < N_RECYCLE_BINS) { 537 size = recycleBinSize[bin]; // round-up size to next sized bin. 538 } 539 #endif // #ifdef PS_MEM_USE_RECYCLE 540 541 if (size == ptr->userMemorySize) { 491 unsigned int lineno, 492 const char *func) 493 { 494 if (ptr == NULL) { 495 return p_psAlloc(size, file, lineno, func); 496 } 497 498 psMemBlock *memBlock = ((psMemBlock *)ptr) - 1; 499 500 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 501 502 if (size == memBlock->userMemorySize) { 542 503 // Nothing to do 543 return vptr;504 return ptr; 544 505 } 545 506 546 507 // Reallocate the memory 547 508 548 if (safeThreads) { 549 pthread_mutex_lock(&memBlockListMutex); 550 } 551 552 bool isBlockLast = (ptr == lastMemBlockAllocated); // Is this the last block we allocated? 553 ptr = (psMemBlock *)realloc(ptr, sizeof(psMemBlock) + size + sizeof(psPtr)); 554 if (ptr == NULL) { 555 ptr = memExhaustedCallback(size); 556 if (ptr == NULL) { 557 psAbort(__func__, "Failed to reallocate %zd bytes at %s:%d", size, file, lineno); 558 } 559 } 560 561 ptr->userMemorySize = size; 562 *(psPtr *)((int8_t *) (ptr + 1) + size) = P_PS_MEMMAGIC; 563 509 // Is this the last block we allocated? If it is, we need to keep track of 510 // this fact and update lastMemBlockAllocated *after* the realloc or 511 // lastMemBlockAllocated will be left with a bogus value 512 bool isBlockLast = (memBlock == lastMemBlockAllocated); 513 514 memBlock = (psMemBlock *)realloc(memBlock, sizeof(psMemBlock) + size + sizeof(psPtr)); 515 if (memBlock== NULL) { 516 MUTEX_LOCK(&memBlockListMutex); 517 memBlock = memExhaustedCallback(size); 518 if (memBlock == NULL) { 519 MUTEX_UNLOCK(&memBlockListMutex); 520 psMemBlockPrint(stderr, ((psMemBlock *)ptr) - 1); 521 fprintf(stderr, "Problem reallocating block\n"); 522 PS_MEM_ABORT(__func__, "Failed to reallocate to %zd bytes at %s (%s:%d)", size, func, file, lineno); 523 } 524 } 525 526 // realloc() successed so need to update lastMemBlockAllocated if we just 527 // mucked with the last mem block 564 528 if (isBlockLast) { 565 lastMemBlockAllocated = ptr; 529 lastMemBlockAllocated = memBlock; 530 } 531 532 memBlock->userMemorySize = size; 533 *(psU32 *)((char *)(memBlock + 1) + size) = P_PS_MEMMAGIC; 534 535 MUTEX_LOCK(&memBlockListMutex); 536 537 // Is this the last block we allocated? 538 if (memBlock== lastMemBlockAllocated) { 539 lastMemBlockAllocated = memBlock; 566 540 } 567 541 568 542 // the block location may have changed, so fix the linked list addresses. 569 if (ptr->nextBlock != NULL) { 570 ptr->nextBlock->previousBlock = ptr; 571 } 572 if (ptr->previousBlock != NULL) { 573 ptr->previousBlock->nextBlock = ptr; 574 } 575 576 if (safeThreads) { 577 pthread_mutex_unlock(&memBlockListMutex); 543 if (memBlock->nextBlock != NULL) { 544 memBlock->nextBlock->previousBlock = memBlock; 545 } 546 if (memBlock->previousBlock != NULL) { 547 memBlock->previousBlock->nextBlock = memBlock; 578 548 } 579 549 580 550 // Did the user ask to be informed about this allocation? 581 if (ptr->id == p_psMemAllocID) { 582 p_psMemAllocID += memAllocCallback(ptr); 583 } 584 585 return ptr + 1; // usr memory 586 } 587 588 void p_psFree(psPtr vptr, 589 const char *filename, 590 unsigned int lineno) 591 { 592 if (vptr == NULL) { 593 return; 594 } 595 psMemBlock* ptr = ((psMemBlock* ) vptr) - 1; 596 if (ptr->refCounter < 1) { 597 psMemBlock* ptr = ((psMemBlock* ) vptr) - 1; 598 599 psAbort(__func__,_("Block %lu, allocated at %s:%d, freed multiple times at %s:%d."), 600 (unsigned long)ptr->id, ptr->file, ptr->lineno, filename, lineno); 601 } 602 603 if (checkMemBlock(ptr, __func__) != 0) { 604 memProblemCallback(ptr, filename, lineno); 605 psAbort(__func__,"Memory Corruption Detected."); 606 } 607 608 (void)p_psMemDecrRefCounter(vptr, filename, lineno); // this handles the free, if required. 551 if (memBlock->id == p_psMemAllocID) { 552 p_psMemAllocID += memAllocCallback(memBlock); 553 } 554 555 MUTEX_UNLOCK(&memBlockListMutex); 556 557 return memBlock + 1; // usr memory 609 558 } 610 559 … … 619 568 psS32 nleak = 0; 620 569 psS32 j = 0; 621 psMemBlock* topBlock = lastMemBlockAllocated; 622 623 if (safeThreads) { 624 pthread_mutex_lock(&memBlockListMutex); 625 } 626 627 for (psMemBlock* iter = topBlock; iter != NULL; iter = iter->nextBlock) { 628 if ( (iter->refCounter > 0) && 629 ( (persistence) || (!persistence && !iter->persistent) ) && 630 (iter->id >= id0)) { 570 psMemBlock *topBlock = lastMemBlockAllocated; 571 572 MUTEX_LOCK(&memBlockListMutex); 573 574 // find the very first memblock 575 psMemBlock *memBlock = NULL; 576 for (memBlock = topBlock; memBlock->nextBlock != NULL; memBlock = memBlock->nextBlock) { } 577 578 // iterate through the block list starting with the oldest block 579 for (; memBlock != NULL; memBlock = memBlock->previousBlock) { 580 if ( (memBlock->refCounter > 0) && 581 ( (persistence) || (!persistence && !memBlock->persistent) ) && 582 (memBlock->id >= id0)) { 631 583 632 584 nleak++; … … 634 586 if (fd != NULL) { 635 587 if (nleak == 1) { 636 fprintf(fd, " %20s:line ID\n", "file");588 fprintf(fd, "# func at (file:line) ID: X\n"); 637 589 } 638 590 639 fprintf(fd, " %20s:%-4d %lu\n", iter->file, (int)iter->lineno, (unsigned long)iter->id); 591 fprintf(fd, "%s at (%s:%d) ID: %lu", memBlock->func, memBlock->file, (int)memBlock->lineno, (unsigned long)memBlock->id); 592 #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE) 593 594 size_t size = memBlock->backtraceSize; 595 char **strings = backtrace_symbols((void *const *)memBlock->backtrace, size); 596 597 fprintf(fd, " Alloc Call Depth: %zd\n", size); 598 599 for (int i = 0; i < size; i++) { 600 // always ident 601 int ident = 4; // initial indent 602 ident += 2 * i; // nesting depth 603 fprintf(fd, "%*s", ident, ""); 604 605 // if the caller was an anon function then strchr won't 606 // find a '(' in the string and will return NULL 607 char *caller = caller = strchr(strings[i], '('); 608 if (caller) { 609 // skip over the '(' 610 caller++; 611 // find the end of the symbol name 612 size_t callerLength = abs(strchr(caller, '+') - caller); 613 // print just the symbol name 614 for (int i = 0; i < callerLength; i++) { 615 fputc(caller[i],fd); 616 } 617 fprintf(fd, "\n"); 618 } else { 619 fprintf(fd, "(unknown)\n"); 620 } 621 } 622 623 free (strings); 624 #else // ifdef HAVE_BACKTRACE 625 // \n after "Memory Block ID" 626 fprintf(fd, "\n"); 627 #endif // ifdef HAVE_BACKTRACE 628 640 629 } 641 630 } 642 631 } 643 632 644 if (safeThreads) { 645 pthread_mutex_unlock(&memBlockListMutex); 646 } 633 MUTEX_UNLOCK(&memBlockListMutex); 647 634 648 635 if (nleak == 0 || array == NULL) { … … 650 637 } 651 638 652 *array = p_psAlloc(nleak * sizeof(psMemBlock), __FILE__, __LINE__); 653 if (safeThreads) { 654 pthread_mutex_lock(&memBlockListMutex); 655 } 656 657 for (psMemBlock* iter = topBlock; iter != NULL; iter = iter->nextBlock) { 658 if ( (iter->refCounter > 0) && 659 ( (persistence) || (!persistence && !iter->persistent) ) && 660 (iter->id >= id0)) { 661 662 (*array)[j++] = iter; 639 *array = psAlloc(nleak * sizeof(psMemBlock)); 640 641 MUTEX_LOCK(&memBlockListMutex); 642 643 for (psMemBlock *memBlock = topBlock; memBlock != NULL; memBlock = memBlock ->nextBlock) { 644 if ( (memBlock->refCounter > 0) && 645 ( (persistence) || (!persistence && !memBlock->persistent) ) && 646 (memBlock->id >= id0)) { 647 648 (*array)[j++] = memBlock; 663 649 if (j == nleak) { // found them all 664 650 break; … … 667 653 } 668 654 669 if (safeThreads) { 670 pthread_mutex_unlock(&memBlockListMutex); 671 } 655 MUTEX_UNLOCK(&memBlockListMutex); 672 656 673 657 return nleak; … … 679 663 680 664 // return refCounter 681 psReferenceCount p sMemGetRefCounter(const psPtr ptr)682 { 683 psMemBlock* ptr2;684 psU32 refCount;685 665 psReferenceCount p_psMemGetRefCounter(const psPtr ptr, 666 const char *file, 667 unsigned int lineno, 668 const char *func) 669 { 686 670 if (ptr == NULL) { 687 671 return 0; 688 672 } 689 673 690 ptr2 = ((psMemBlock* ) ptr) - 1; 691 692 if (checkMemBlock(ptr2, __func__) != 0) { 693 memProblemCallback(ptr2, __func__, __LINE__); 694 } 695 696 if (safeThreads) { 697 pthread_mutex_lock(&ptr2->refCounterMutex); 698 } 699 refCount = ptr2->refCounter; 700 if (safeThreads) { 701 pthread_mutex_unlock(&ptr2->refCounterMutex); 702 } 703 704 return refCount; 674 psMemBlock *memBlock = ((psMemBlock *) ptr) - 1; 675 676 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 677 678 return memBlock->refCounter; 705 679 } 706 680 707 681 // increment and return refCounter 708 psPtr p_psMemIncrRefCounter(const psPtr vptr,682 psPtr p_psMemIncrRefCounter(const psPtr ptr, 709 683 const char *file, 710 psS32 lineno) 711 { 712 psMemBlock* ptr; 713 714 if (vptr == NULL) { 715 return vptr; 716 } 717 718 ptr = ((psMemBlock* ) vptr) - 1; 719 720 if (checkMemBlock(ptr, __func__)) { 721 memProblemCallback(ptr, file, lineno); 722 } 723 724 if (safeThreads) { 725 pthread_mutex_lock(&ptr->refCounterMutex); 726 } 727 ptr->refCounter++; 728 if (safeThreads) { 729 pthread_mutex_unlock(&ptr->refCounterMutex); 730 } 684 unsigned int lineno, 685 const char *func) 686 { 687 if (ptr == NULL) { 688 return ptr; 689 } 690 691 psMemBlock* memBlock = ((psMemBlock *) ptr) - 1; 692 693 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 694 695 memBlock->refCounter++; 731 696 732 697 // Did the user ask to be informed about this allocation? 733 if (ptr->id == p_psMemAllocID) { 734 p_psMemAllocID += memAllocCallback(ptr); 735 } 736 737 return vptr; 738 } 739 698 MUTEX_LOCK(&memBlockListMutex); 699 if (memBlock->id == p_psMemAllocID) { 700 p_psMemAllocID += memAllocCallback(memBlock); 701 } 702 MUTEX_UNLOCK(&memBlockListMutex); 703 704 return ptr; 705 } 706 707 #if 0 740 708 psPtr p_psMemSetRefCounter(psPtr vptr, 741 709 psReferenceCount count, … … 755 723 ptr = ((psMemBlock* ) vptr) - 1; 756 724 757 if (checkMemBlock(ptr, __func__)) { 725 if (isBadMemBlock(ptr, __func__)) { 726 (void)p_psMemDecrRefCounter(vptr, filename, lineno); 758 727 memProblemCallback(ptr, file, lineno); 759 728 } 760 729 761 if (safeThreads) {762 pthread_mutex_lock(&ptr->refCounterMutex);763 }764 730 ptr->refCounter = count; 765 if (safeThreads) {766 pthread_mutex_unlock(&ptr->refCounterMutex);767 }768 731 769 732 if (count < 1) { … … 773 736 return vptr; 774 737 } 738 #endif 775 739 776 740 // decrement and return refCounter 777 psPtr p_psMemDecrRefCounter(psPtr vptr,741 psPtr p_psMemDecrRefCounter(psPtr ptr, 778 742 const char *file, 779 psS32 lineno) 780 { 781 if (vptr == NULL) { 743 unsigned int lineno, 744 const char *func) 745 { 746 if (ptr == NULL) { 782 747 return NULL; 783 748 } 784 749 785 psMemBlock* ptr = ((psMemBlock* ) vptr) - 1; 786 787 if (checkMemBlock(ptr, __func__) != 0) { 788 memProblemCallback(ptr, file, lineno); 789 return NULL; 790 } 750 psMemBlock *memBlock = ((psMemBlock *) ptr) - 1; 751 752 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 753 754 // if we have multiple references, just decrement the count and return. 755 if (memBlock->refCounter > 1) { 756 memBlock->refCounter--; 757 758 // Did the user ask to be informed about this deallocation? 759 MUTEX_LOCK(&memBlockListMutex); 760 if (memBlock->id == p_psMemFreeID) { 761 p_psMemFreeID += memFreeCallback(memBlock); 762 } 763 MUTEX_UNLOCK(&memBlockListMutex); 764 765 return ptr; 766 } 767 768 // we can't invoke freeFunc() while we're holding memBlockListMutex as it 769 // may invoke psFree() itself 770 if (memBlock->freeFunc != NULL) { 771 memBlock->freeFunc(ptr); 772 } 773 774 MUTEX_LOCK(&memBlockListMutex); 791 775 792 776 // Did the user ask to be informed about this deallocation? 793 if ( ptr->id == p_psMemFreeID) {777 if (memBlock->id == p_psMemFreeID) { 794 778 p_psMemFreeID += memFreeCallback(ptr); 795 779 } 796 780 797 if (safeThreads) { 798 pthread_mutex_lock(&ptr->refCounterMutex); 799 } 800 801 if (ptr->refCounter > 1) { 802 ptr->refCounter--; // multiple references, just decrement the count. 803 if (safeThreads) { 804 pthread_mutex_unlock(&ptr->refCounterMutex); 805 } 806 807 } else { 808 if (safeThreads) { 809 pthread_mutex_unlock(&ptr->refCounterMutex); 810 } 811 812 if (ptr->freeFunc != NULL) { 813 ptr->freeFunc(vptr); 814 } 815 816 if (safeThreads) { 817 pthread_mutex_lock(&memBlockListMutex); 818 } 819 820 // cut the memBlock out of the memBlock list 821 if (ptr->nextBlock != NULL) { 822 ptr->nextBlock->previousBlock = ptr->previousBlock; 823 } 824 if (ptr->previousBlock != NULL) { 825 ptr->previousBlock->nextBlock = ptr->nextBlock; 826 } 827 if (lastMemBlockAllocated == ptr) { 828 lastMemBlockAllocated = ptr->nextBlock; 829 } 830 831 if (safeThreads) { 832 pthread_mutex_unlock(&memBlockListMutex); 833 } 834 835 #ifdef PS_MEM_USE_RECYCLE 836 // do we recycle? 837 int bin = getRecycleBin(ptr->userMemorySize); 838 if (bin < N_RECYCLE_BINS && recycleBinNums[bin] < MAX_RECYCLE) { 839 ptr->refCounter = 0; 840 recyclePush(ptr, bin); 841 } else 842 #endif // #ifdef PS_MEM_USE_RECYCLE 843 { 844 // memory is larger than I want to recycle. 845 #ifdef PS_MEM_DEBUG 846 (void)p_psRealloc(vptr, 0, file, lineno); 847 ptr->previousBlock = NULL; 848 ptr->nextBlock = deadBlockList; 849 if (deadBlockList != NULL) { 850 deadBlockList->previous = ptr; 851 } 852 deadBlockList = ptr; 853 #else // #ifdef PS_MEM_DEBUG 854 855 if (safeThreads) { 856 pthread_mutex_destroy(&ptr->refCounterMutex); 857 } 858 free(ptr); 859 #endif // #else - #ifdef PS_MEM_DEBUG 860 861 } 862 863 vptr = NULL; // since we freed it, make sure we return NULL. 864 } 865 866 return vptr; 867 } 868 869 void psMemSetDeallocator(psPtr ptr, 870 psFreeFunc freeFunc) 781 // cut the memBlock out of the memBlock list 782 if (memBlock->nextBlock != NULL) { 783 memBlock->nextBlock->previousBlock = memBlock->previousBlock; 784 } 785 if (memBlock->previousBlock != NULL) { 786 memBlock->previousBlock->nextBlock = memBlock->nextBlock; 787 } 788 if (lastMemBlockAllocated == memBlock) { 789 lastMemBlockAllocated = memBlock->nextBlock; 790 } 791 792 MUTEX_UNLOCK(&memBlockListMutex); 793 794 // invoke free only after we've released the block list lock as free() 795 // could take awhile. We can get away with this as at this point the 796 // memBlock is no longer part of the mem block list. 797 #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE) 798 799 free(memBlock->backtrace); 800 #endif 801 802 free(memBlock); 803 804 // since we freed it, make sure we return NULL. 805 return NULL; 806 } 807 808 void p_psMemSetDeallocator(psPtr ptr, 809 psFreeFunc freeFunc, 810 const char *file, 811 unsigned int lineno, 812 const char *func) 871 813 { 872 814 if (ptr == NULL) { … … 874 816 } 875 817 876 psMemBlock* PTR = ((psMemBlock* )ptr) - 1;877 878 if (checkMemBlock(PTR, __func__) != 0) {879 memProblemCallback(PTR, __func__, __LINE__); 880 }881 882 PTR->freeFunc = freeFunc; 883 884 } 885 886 psFreeFunc psMemGetDeallocator(const psPtr ptr)818 psMemBlock* memBlock = ((psMemBlock *)ptr) - 1; 819 820 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 821 822 memBlock->freeFunc = freeFunc; 823 } 824 825 psFreeFunc p_psMemGetDeallocator(const psPtr ptr, 826 const char *file, 827 unsigned int lineno, 828 const char *func) 887 829 { 888 830 if (ptr == NULL) { … … 890 832 } 891 833 892 psMemBlock* PTR = ((psMemBlock* ) ptr) - 1; 893 894 if (checkMemBlock(PTR, __func__) != 0) { 895 memProblemCallback(PTR, __func__, __LINE__); 896 } 897 898 return PTR->freeFunc; 899 } 900 901 bool psMemCheckType(psDataType type, 902 psPtr ptr) 903 { 904 PS_ASSERT_PTR(ptr, false); 905 906 switch(type) { 907 case PS_DATA_ARRAY: 908 if ( psMemCheckArray(ptr) ) 909 return true; 910 else { 911 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 912 "Incorrect pointer. Datatypes do not match.\n"); 913 break; 914 } 915 case PS_DATA_BITSET: 916 if ( psMemCheckBitSet(ptr) ) 917 return true; 918 else { 919 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 920 "Incorrect pointer. Datatypes do not match.\n"); 921 break; 922 } 923 case PS_DATA_CUBE: 924 if ( psMemCheckCube(ptr) ) 925 return true; 926 else { 927 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 928 "Incorrect pointer. Datatypes do not match.\n"); 929 break; 930 } 931 case PS_DATA_FITS: 932 if ( psMemCheckFits(ptr) ) 933 return true; 934 else { 935 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 936 "Incorrect pointer. Datatypes do not match.\n"); 937 break; 938 } 939 case PS_DATA_HASH: 940 if ( psMemCheckHash(ptr) ) 941 return true; 942 else { 943 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 944 "Incorrect pointer. Datatypes do not match.\n"); 945 break; 946 } 947 case PS_DATA_HISTOGRAM: 948 if ( psMemCheckHistogram(ptr) ) 949 return true; 950 else { 951 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 952 "Incorrect pointer. Datatypes do not match.\n"); 953 break; 954 } 955 case PS_DATA_IMAGE: 956 if ( psMemCheckImage(ptr) ) 957 return true; 958 else { 959 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 960 "Incorrect pointer. Datatypes do not match.\n"); 961 break; 962 } 963 case PS_DATA_KERNEL: 964 if ( psMemCheckKernel(ptr) ) 965 return true; 966 else { 967 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 968 "Incorrect pointer. Datatypes do not match.\n"); 969 break; 970 } 971 case PS_DATA_LINE: 972 if ( psMemCheckLine(ptr) ) 973 return true; 974 else { 975 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 976 "Incorrect pointer. Datatypes do not match.\n"); 977 break; 978 } 979 case PS_DATA_LIST: 980 if ( psMemCheckList(ptr) ) 981 return true; 982 else { 983 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 984 "Incorrect pointer. Datatypes do not match.\n"); 985 break; 986 } 987 case PS_DATA_LOOKUPTABLE: 988 if ( psMemCheckLookupTable(ptr) ) 989 return true; 990 else { 991 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 992 "Incorrect pointer. Datatypes do not match.\n"); 993 break; 994 } 995 case PS_DATA_METADATA: 996 if ( psMemCheckMetadata(ptr) ) 997 return true; 998 else { 999 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1000 "Incorrect pointer. Datatypes do not match.\n"); 1001 break; 1002 } 1003 case PS_DATA_METADATAITEM: 1004 if ( psMemCheckMetadataItem(ptr) ) 1005 return true; 1006 else { 1007 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1008 "Incorrect pointer. Datatypes do not match.\n"); 1009 break; 1010 } 1011 case PS_DATA_MINIMIZATION: 1012 if ( psMemCheckMinimization(ptr) ) 1013 return true; 1014 else { 1015 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1016 "Incorrect pointer. Datatypes do not match.\n"); 1017 break; 1018 } 1019 case PS_DATA_PIXELS: 1020 if ( psMemCheckPixels(ptr) ) 1021 return true; 1022 else { 1023 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1024 "Incorrect pointer. Datatypes do not match.\n"); 1025 break; 1026 } 1027 case PS_DATA_PLANE: 1028 if ( psMemCheckPlane(ptr) ) 1029 return true; 1030 else { 1031 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1032 "Incorrect pointer. Datatypes do not match.\n"); 1033 break; 1034 } 1035 case PS_DATA_PLANEDISTORT: 1036 if ( psMemCheckPlaneDistort(ptr) ) 1037 return true; 1038 else { 1039 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1040 "Incorrect pointer. Datatypes do not match.\n"); 1041 break; 1042 } 1043 case PS_DATA_PLANETRANSFORM: 1044 if ( psMemCheckPlaneTransform(ptr) ) 1045 return true; 1046 else { 1047 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1048 "Incorrect pointer. Datatypes do not match.\n"); 1049 break; 1050 } 1051 case PS_DATA_POLYNOMIAL1D: 1052 if ( psMemCheckPolynomial1D(ptr) ) 1053 return true; 1054 else { 1055 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1056 "Incorrect pointer. Datatypes do not match.\n"); 1057 break; 1058 } 1059 case PS_DATA_POLYNOMIAL2D: 1060 if ( psMemCheckPolynomial2D(ptr) ) 1061 return true; 1062 else { 1063 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1064 "Incorrect pointer. Datatypes do not match.\n"); 1065 break; 1066 } 1067 case PS_DATA_POLYNOMIAL3D: 1068 if ( psMemCheckPolynomial3D(ptr) ) 1069 return true; 1070 else { 1071 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1072 "Incorrect pointer. Datatypes do not match.\n"); 1073 break; 1074 } 1075 case PS_DATA_POLYNOMIAL4D: 1076 if ( psMemCheckPolynomial4D(ptr) ) 1077 return true; 1078 else { 1079 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1080 "Incorrect pointer. Datatypes do not match.\n"); 1081 break; 1082 } 1083 case PS_DATA_PROJECTION: 1084 if ( psMemCheckProjection(ptr) ) 1085 return true; 1086 else { 1087 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1088 "Incorrect pointer. Datatypes do not match.\n"); 1089 break; 1090 } 1091 case PS_DATA_REGION: 1092 if ( psMemCheckRegion(ptr) ) 1093 return true; 1094 else { 1095 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1096 "Incorrect pointer. Datatypes do not match.\n"); 1097 break; 1098 } 1099 case PS_DATA_SCALAR: 1100 if ( psMemCheckScalar(ptr) ) 1101 return true; 1102 else { 1103 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1104 "Incorrect pointer. Datatypes do not match.\n"); 1105 break; 1106 } 1107 case PS_DATA_SPHERE: 1108 if ( psMemCheckSphere(ptr) ) 1109 return true; 1110 else { 1111 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1112 "Incorrect pointer. Datatypes do not match.\n"); 1113 break; 1114 } 1115 case PS_DATA_SPHEREROT: 1116 if ( psMemCheckSphereRot(ptr) ) 1117 return true; 1118 else { 1119 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1120 "Incorrect pointer. Datatypes do not match.\n"); 1121 break; 1122 } 1123 case PS_DATA_SPLINE1D: 1124 if ( psMemCheckSpline1D(ptr) ) 1125 return true; 1126 else { 1127 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1128 "Incorrect pointer. Datatypes do not match.\n"); 1129 break; 1130 } 1131 case PS_DATA_STATS: 1132 if ( psMemCheckStats(ptr) ) 1133 return true; 1134 else { 1135 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1136 "Incorrect pointer. Datatypes do not match.\n"); 1137 break; 1138 } 1139 case PS_DATA_STRING: 1140 if ( psMemCheckString(ptr) ) 1141 return true; 1142 else { 1143 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1144 "Incorrect pointer. Datatypes do not match.\n"); 1145 break; 1146 } 1147 case PS_DATA_TIME: 1148 if ( psMemCheckTime(ptr) ) 1149 return true; 1150 else { 1151 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1152 "Incorrect pointer. Datatypes do not match.\n"); 1153 break; 1154 } 1155 case PS_DATA_VECTOR: 1156 if ( psMemCheckVector(ptr) ) 1157 return true; 1158 else { 1159 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 1160 "Incorrect pointer. Datatypes do not match.\n"); 1161 break; 1162 } 1163 default: 1164 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 1165 "Invalid datatype specified.\n"); 1166 } 1167 return false; 834 psMemBlock* memBlock = ((psMemBlock *)ptr) - 1; 835 836 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 837 838 return memBlock->freeFunc; 1168 839 } 1169 840 1170 841 bool psMemSetThreadSafety(bool safe) 1171 842 { 1172 bool out = safeThreads; 843 MUTEX_LOCK(&memBlockListMutex); 844 845 bool oldState = safeThreads; 1173 846 safeThreads = safe; 1174 return out; 847 848 MUTEX_UNLOCK(&memBlockListMutex); 849 850 return oldState; 1175 851 } 1176 852 1177 853 bool psMemGetThreadSafety(void) 1178 854 { 1179 return safeThreads; 1180 } 1181 1182 bool p_psMemGetPersistent(psPtr vptr) 1183 { 1184 if (vptr == NULL) { 855 MUTEX_LOCK(&memBlockListMutex); 856 857 bool oldState = safeThreads; 858 859 MUTEX_UNLOCK(&memBlockListMutex); 860 861 return oldState; 862 } 863 864 bool p_psMemGetPersistent(psPtr ptr, 865 const char *file, 866 unsigned int lineno, 867 const char *func) 868 { 869 if (ptr == NULL) { 1185 870 return NULL; 1186 871 } 1187 872 1188 psMemBlock* ptr = ((psMemBlock* ) vptr) - 1; 1189 1190 if (checkMemBlock(ptr, __func__) != 0) { 1191 memProblemCallback(ptr, __func__, __LINE__); 1192 } 1193 1194 return ptr->persistent; 1195 } 1196 1197 void p_psMemSetPersistent(psPtr vptr, 1198 bool value) 1199 { 1200 if (vptr == NULL) { 873 psMemBlock* memBlock = ((psMemBlock *) ptr) - 1; 874 875 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 876 877 return memBlock->persistent; 878 } 879 880 void p_psMemSetPersistent(psPtr ptr, 881 bool value, 882 const char *file, 883 unsigned int lineno, 884 const char *func) 885 { 886 if (ptr == NULL) { 1201 887 return; 1202 888 } 1203 889 1204 psMemBlock* ptr = ((psMemBlock* ) vptr) - 1; 1205 1206 if (checkMemBlock(ptr, __func__) != 0) { 1207 memProblemCallback(ptr, __func__, __LINE__); 1208 } 1209 1210 ptr->persistent = value; 890 psMemBlock* memBlock = ((psMemBlock *) ptr) - 1; 891 892 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 893 894 memBlock->persistent = value; 1211 895 } 1212 896 … … 1221 905 size_t psMemStats(const bool print, // print details as they're found? 1222 906 size_t *allocated, // memory that's currently allocated (but not persistent) 1223 size_t *persistent, // persistent memory that's currently allocated 1224 size_t *freelist) // memory that's waiting to be recycled 907 size_t *persistent) // persistent memory that's currently allocated 1225 908 { 1226 909 const size_t overhead = sizeof(psMemBlock) + sizeof(psPtr); // overhead on each allocation … … 1230 913 } 1231 914 1232 if (safeThreads) { 1233 pthread_mutex_lock(&memBlockListMutex); 1234 } 915 MUTEX_LOCK(&memBlockListMutex); 1235 916 /* 1236 917 * All memory that's currently allocated, whether persistent or not … … 1264 945 printf("Persistent %6s %10zd %8zd\n", "", persist, npersist); 1265 946 } 1266 /* 1267 * Count the memory on the free list 1268 */ 1269 size_t freelist_s; 1270 if (freelist == NULL) { 1271 freelist = &freelist_s; 1272 } 1273 1274 *freelist = 0; 1275 int nblock_tot = 0; 1276 #ifdef PS_MEM_USE_RECYCLE 1277 1278 for (int i = 0; recycleBinSize[i] < P_PS_LARGE_BLOCK_SIZE; i++) { 1279 size_t bin_contents = 0; 1280 size_t nblock = 0; 1281 for (const psMemBlock *ptr = recycleMemBlockList[i]; ptr != NULL; ptr = ptr->nextBlock) { 1282 nblock++; 1283 bin_contents += ptr->userMemorySize + overhead; 1284 } 1285 *freelist += bin_contents; 1286 nblock_tot += nblock; 1287 1288 if (print) { 1289 printf("Freelist %6d %10d %8d\n", recycleBinSize[i], bin_contents, nblock); 1290 } 1291 } 1292 #endif // #ifdef PS_MEM_USE_RECYCLE 1293 1294 if (print) { 1295 printf("Freelist %6s %10zd %8d\n", "", *freelist, nblock_tot); 1296 } 1297 1298 1299 if (safeThreads) { 1300 pthread_mutex_unlock(&memBlockListMutex); 1301 } 1302 1303 return *freelist + *allocated + *persistent; 1304 } 947 948 MUTEX_UNLOCK(&memBlockListMutex); 949 950 return *allocated + *persistent; 951 } 952 953 int psMemBlockPrint(FILE *output, const psMemBlock *memBlock) 954 { 955 return fprintf(output, 956 "Memory Block ID: %lu @ %p\n" 957 "\tPrevious Block: %p Next Block: %p\n" 958 "\tFree function: %p\n" 959 "\tSize: %zd Reference count: %lu Persistent: %s\n" 960 "\tPosts: %x %x %x\n" 961 "\tAllocated in %s at (%s:%d)\n" 962 "\t\tby Thread ID %lu\n", 963 memBlock->id, memBlock, 964 memBlock->previousBlock, memBlock->nextBlock, 965 memBlock->freeFunc, 966 memBlock->userMemorySize, memBlock->refCounter, (memBlock->persistent ? "Yes" : "No"), 967 memBlock->startblock, memBlock->endblock, 968 *(psU32 *)((char *) (memBlock + 1) + memBlock->userMemorySize), 969 memBlock->func, memBlock->file, memBlock->lineno, memBlock->tid); 970 }
Note:
See TracChangeset
for help on using the changeset viewer.
