Changeset 18809
- Timestamp:
- Jul 30, 2008, 5:57:31 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branch_20080719/psLib/src/sys/psMemory.c
r14677 r18809 10 10 * @author Joshua Hoblitt, University of Hawaii 11 11 * 12 * @version $Revision: 1.98 $ $Name: not supported by cvs2svn $13 * @date $Date: 200 7-08-27 23:16:17$12 * @version $Revision: 1.98.20.1 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2008-07-31 03:57:31 $ 14 14 * 15 15 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii … … 73 73 static bool isBadMemBlock(FILE *output, const psMemBlock *memBlock, const char *file, unsigned int lineo, const char *func); 74 74 75 // pointer to the last mem block that was allocated76 static psMemBlock *lastMemBlockAllocated = NULL;77 78 75 // memBlockListMutex protects access to: 79 // lastMemBlockAllocated 80 // safeThreads 81 // memid 82 // memory_is_persistent 76 // safeThreads -- very rarely accessed 77 // memory_is_persistent -- very rarely accessed 78 // memAllocCallback -- very rarely accessed 79 // memFreeCallback -- very rarely accessed 80 // memExhaustedCallback -- very rarely accessed 81 // p_psMemAllocID -- rarely accessed 82 // p_psMemFreeID -- rarely accessed 83 // lastMemBlockAllocated 84 // memid -- rarely accessby 83 85 // "the linked list of mem blocks" 84 // p_psMemAllocID85 // p_psMemFreeID86 // memAllocCallback87 // memFreeCallback88 // memExhaustedCallback89 86 // 90 87 // This is a fair ammount of stuff to protect with a single mutex but most of … … 98 95 static pthread_mutex_t memBlockListMutex = PTHREAD_MUTEX_INITIALIZER; 99 96 100 //private boolean for enabling/disabling thread safety. Default = enabled. 97 /******** thread safety options management ********/ 98 99 // private boolean for enabling/disabling thread safety. Default = enabled. 101 100 static bool safeThreads = true; 102 101 103 // private boolean for deciding if allocated memory is persistent 102 // Set the thread-safety state of the memory system: default is true 103 bool psMemSetThreadSafety(bool safe) 104 { 105 // this function is only called ~once per program, before threads are launched 106 MUTEX_LOCK(&memBlockListMutex); 107 108 bool oldState = safeThreads; 109 safeThreads = safe; 110 111 MUTEX_UNLOCK(&memBlockListMutex); 112 113 return oldState; 114 } 115 116 117 // Get the thread-safety state of the memory system 118 bool psMemGetThreadSafety(void) 119 { 120 // this function is only called ~once per program, probably before threads are launched 121 MUTEX_LOCK(&memBlockListMutex); 122 123 bool oldState = safeThreads; 124 125 MUTEX_UNLOCK(&memBlockListMutex); 126 127 return oldState; 128 } 129 130 /******** persistent memory options management ********/ 131 132 // private boolean for deciding if allocated memory is persistent by default 104 133 static bool memory_is_persistent = false; 105 134 106 /** 107 * Unique ID for allocated blocks 135 /* Set whether allocated memory is persistent 136 */ 137 bool p_psMemAllocatePersistent(bool is_persistent) 138 { 139 // this function is only called ~once per program, before threads are launched 140 MUTEX_LOCK(&memBlockListMutex); 141 142 const bool old = memory_is_persistent; 143 memory_is_persistent = is_persistent; 144 145 MUTEX_UNLOCK(&memBlockListMutex); 146 147 return old; 148 } 149 150 /* 151 * And now the I-want-to-be-informed callbacks 152 * 153 * Call the callbacks when these IDs are allocated/freed 154 */ 155 /******** memory allocation callback management (memAllocCallback) ********/ 156 157 // Default memFreeCallback function 158 static psMemId memAllocCallbackDefault(const psMemBlock *memBlock) 159 { 160 static psMemId incr = 0; // "p_psMemAllocID += incr" 161 162 return incr; 163 } 164 165 static psMemAllocCallback memAllocCallback = memAllocCallbackDefault; 166 167 psMemAllocCallback psMemAllocCallbackSet(psMemAllocCallback func) 168 { 169 // this function is only called rarely per program 170 MUTEX_LOCK(&memBlockListMutex); 171 172 psMemAllocCallback old = memAllocCallback; 173 174 if (func != NULL) { 175 memAllocCallback = func; 176 } else { 177 memAllocCallback = memAllocCallbackDefault; 178 } 179 180 MUTEX_UNLOCK(&memBlockListMutex); 181 182 return old; 183 } 184 185 // notify user when this block is allocated 186 // XXX why was this not static, and why was it p_psMemAllocID? 187 static psMemId p_psMemAllocID = 0; 188 189 // the above callback is only called if a specific psMemId is set with this function 190 // this function is rarely called in a given program 191 psMemId psMemAllocCallbackSetID(psMemId id) 192 { 193 // this function is only called rarely per program 194 MUTEX_LOCK(&memBlockListMutex); 195 196 psMemId old = p_psMemAllocID; 197 198 p_psMemAllocID = id; 199 200 MUTEX_UNLOCK(&memBlockListMutex); 201 202 return old; 203 } 204 205 /******** memory free callback management (memFreeCallback) ********/ 206 207 // Default memFreeCallback function 208 static psMemId memFreeCallbackDefault(const psMemBlock *memBlock) 209 { 210 static psMemId incr = 0; // "p_psMemFreeID += incr" 211 212 return incr; 213 } 214 215 static psMemFreeCallback memFreeCallback = memFreeCallbackDefault; 216 217 // this function is called only rarely in a program 218 psMemFreeCallback psMemFreeCallbackSet(psMemFreeCallback func) 219 { 220 // this function is only called rarely per program 221 MUTEX_LOCK(&memBlockListMutex); 222 223 psMemFreeCallback old = memFreeCallback; 224 225 if (func != NULL) { 226 memFreeCallback = func; 227 } else { 228 memFreeCallback = memFreeCallbackDefault; 229 } 230 231 MUTEX_UNLOCK(&memBlockListMutex); 232 233 return old; 234 } 235 236 // notify user when this block is freed 237 // XXX why was this not static? 238 static psMemId p_psMemFreeID = 0; 239 240 // the above callback is only called if a specific psMemId is set with this function 241 psMemId psMemFreeCallbackSetID(psMemId id) 242 { 243 // this function is rarely called in a given program 244 MUTEX_LOCK(&memBlockListMutex); 245 246 psMemId old = p_psMemFreeID; 247 248 p_psMemFreeID = id; 249 250 MUTEX_UNLOCK(&memBlockListMutex); 251 252 return old; 253 } 254 255 /******** memory exhausted callback management (memExhaustedCallback) ********/ 256 257 // Default memExhaustedCallback function 258 static void *memExhaustedCallbackDefault(size_t size) 259 { 260 return NULL; 261 } 262 263 static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault; 264 265 psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func) 266 { 267 // this function is rarely called in a given program 268 MUTEX_LOCK(&memBlockListMutex); 269 270 psMemExhaustedCallback old = memExhaustedCallback; 271 272 if (func != NULL) { 273 memExhaustedCallback = func; 274 } else { 275 memExhaustedCallback = memExhaustedCallbackDefault; 276 } 277 278 MUTEX_UNLOCK(&memBlockListMutex); 279 280 return old; 281 } 282 283 /* An example callback function to check the state of the memory system; may be registered 284 * with psMem{Alloc,Free}CallbackSet 285 */ 286 psMemId memAllocCallbackCheckCorruption(const psMemBlock *memBlock) 287 { 288 static psMemId incr = 10; // "p_psMemAllocID += incr" 289 290 if (psMemCheckCorruption(stderr, false) > 0) { 291 fprintf(stderr, "Detected memory corruption\n"); // somewhere to set a breakpoint 292 } 293 294 return incr; 295 } 296 297 /**** Unique ID for allocated blocks and associated accessor functions 108 298 */ 109 299 static psMemId memid = 0; 110 300 111 /** 112 * Default memExhausted callback. 301 /* Return memory ID counter for next block to be allocated 113 302 */ 114 static void *memExhaustedCallbackDefault(size_t size) 115 { 116 return NULL; 117 } 118 119 /* 120 * Default callback for both allocate and free. Note that the 121 * value of p_psMemAllocID/p_psMemFreeID is incremented 122 * by the return value (so returning 0 means that the callback 123 * isn't resignalled) 303 psMemId psMemGetId(void) 304 { 305 // this function is only occasionally called in a given program 306 MUTEX_LOCK(&memBlockListMutex); 307 308 psMemId id = memid + 1; 309 310 MUTEX_UNLOCK(&memBlockListMutex); 311 312 return id; 313 } 314 315 /* Return memory ID counter for last block allocated 124 316 */ 125 static psMemId memAllocCallbackDefault(const psMemBlock *memBlock) 126 { 127 static psMemId incr = 0; // "p_psMemAllocID += incr" 128 129 return incr; 130 } 131 132 static psMemId memFreeCallbackDefault(const psMemBlock *memBlock) 133 { 134 static psMemId incr = 0; // "p_psMemFreeID += incr" 135 136 return incr; 137 } 138 139 /* 140 * Routines to check the consistency of the allocated and/or free memory arena 141 * 317 psMemId psMemGetLastId(void) 318 { 319 // this function is only occasionally called in a given program 320 MUTEX_LOCK(&memBlockListMutex); 321 322 psMemId id = memid; 323 324 MUTEX_UNLOCK(&memBlockListMutex); 325 326 return id; 327 } 328 329 // pointer to the last mem block that was allocated. 330 // This is the root of the entire memory list 331 static psMemBlock *lastMemBlockAllocated = NULL; 332 333 /* Actually allocate memory 334 */ 335 void *p_psAlloc(const char *file, 336 unsigned int lineno, 337 const char *func, 338 size_t size) 339 { 340 341 psMemBlock *memBlock = malloc(sizeof(psMemBlock) + size + sizeof(void *)); 342 if (memBlock == NULL) { 343 // this lock is only occasionally called in a given program (rarely fail malloc) 344 MUTEX_LOCK(&memBlockListMutex); 345 memBlock = memExhaustedCallback(size); 346 MUTEX_UNLOCK(&memBlockListMutex); 347 if (memBlock == NULL) { 348 PS_MEM_ABORT(__func__, "Failed to allocate %zd bytes at %s (%s:%d)", size, func, file, lineno); 349 } 350 } 351 352 // posts 353 *(psU32 *)&memBlock->startblock = P_PS_MEMMAGIC; 354 *(psU32 *)&memBlock->endblock = P_PS_MEMMAGIC; 355 *(psU32 *)((char *) (memBlock + 1) + size) = P_PS_MEMMAGIC; 356 357 // size of memory allocated 358 memBlock->userMemorySize = size; 359 360 // alloc request by: 361 // thread 362 *(pthread_t *)&memBlock->tid = pthread_self(); 363 // file 364 memBlock->file = file; 365 // line number 366 *(unsigned int *)&memBlock->lineno = (unsigned int)lineno; 367 // function 368 memBlock->func = func; 369 370 #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE) 371 #define BACKTRACE_BUFFER_SIZE 32 372 // psMemBlock.func is a 'const char *', so basically we're going to abuse 373 // that and treat it as a void ** to carry around backtrace information. 374 // psMemBlock is not ifdef'd to make sure that psMemBlock is always the 375 // same size & layout reguardless of the pslib .so that's being linked 376 // against 377 void **bt = malloc(BACKTRACE_BUFFER_SIZE * sizeof(void *)); 378 if (bt == NULL) { 379 PS_MEM_ABORT(__func__, "Failed to allocate memory for backtrace buffer: %zd bytes at %s (%s:%d)", 32 * sizeof(void *), func, file, lineno); 380 } 381 *(size_t *)&memBlock->backtraceSize = backtrace(bt, BACKTRACE_BUFFER_SIZE); 382 *(void ***)&memBlock->backtrace = bt; 383 #endif // ifdef HAVE_BACKTRACE 384 385 // free function 386 memBlock->freeFunc = NULL; 387 388 // persistent memory flag 389 memBlock->persistent = memory_is_persistent; 390 391 // this block will be add as the last mem block in the list 392 memBlock->previousBlock = NULL; 393 394 // ref count 395 memBlock->refCounter = 1; // one user so far 396 397 // need exclusive access of the memory block list now... 398 // this lock is very frequently called in a given program 399 MUTEX_LOCK(&memBlockListMutex); 400 401 // increment the memory id only after we've grabbed the memBlockListMutex 402 *(psMemId* )&memBlock->id = ++memid; 403 404 // insert the new block to the front of the memBlock linked-list 405 if (lastMemBlockAllocated != NULL) { 406 // exchange forward and backward references with the last allocated block 407 lastMemBlockAllocated->previousBlock = memBlock; 408 memBlock->nextBlock = lastMemBlockAllocated; 409 } 410 lastMemBlockAllocated = memBlock; 411 412 // Did the user ask to be informed about this allocation? 413 if (memBlock->id == p_psMemAllocID) { 414 // p_psMemAllocID can only be changed while the memBlockList mutex is 415 // held 416 p_psMemAllocID += memAllocCallback(memBlock); 417 } 418 419 MUTEX_UNLOCK(&memBlockListMutex); 420 421 // And return the user the memory that they allocated 422 return memBlock + 1; // user memory 423 } 424 425 /* internal routine to check the consistency of the allocated and/or free memory arena. 426 * this is used by the user functions below (psMem{Set,Get}Deallocator, 142 427 * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted 143 428 */ … … 201 486 // users responsiblity) so all we're really risking is a garbage value. 202 487 488 // XXX EAM : is this the error I'm catching in multithreaded processing? 203 489 if (memBlock == memBlock->nextBlock) { 204 490 if (!blockPrinted) { … … 225 511 return bad; 226 512 } 227 228 229 /*230 * A callback function to check the state of the memory system; may be registered231 * with psMem{Alloc,Free}CallbackSet232 */233 static psMemId memAllocCallbackCheckCorruption(const psMemBlock *memBlock)234 {235 static psMemId incr = 10; // "p_psMemAllocID += incr"236 237 if (psMemCheckCorruption(stderr, false) > 0) {238 fprintf(stderr, "Detected memory corruption\n"); // somewhere to set a breakpoint239 }240 241 return incr;242 }243 244 /*245 * The default callbacks246 */247 static psMemAllocCallback memAllocCallback = memAllocCallbackDefault;248 static psMemFreeCallback memFreeCallback = memFreeCallbackDefault;249 static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;250 251 psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func)252 {253 MUTEX_LOCK(&memBlockListMutex);254 255 psMemExhaustedCallback old = memExhaustedCallback;256 257 if (func != NULL) {258 memExhaustedCallback = func;259 } else {260 memExhaustedCallback = memExhaustedCallbackDefault;261 }262 263 MUTEX_UNLOCK(&memBlockListMutex);264 265 return old;266 }267 268 /*269 * And now the I-want-to-be-informed callbacks270 *271 * Call the callbacks when these IDs are allocated/freed272 */273 psMemId p_psMemAllocID = 0; // notify user this block is allocated274 psMemId p_psMemFreeID = 0; // notify user this block is freed275 276 psMemId psMemAllocCallbackSetID(psMemId id)277 {278 MUTEX_LOCK(&memBlockListMutex);279 280 psMemId old = p_psMemAllocID;281 282 /*283 * This is here purely to stop gcc complaining284 */285 assert (memAllocCallbackCheckCorruption != NULL);286 287 p_psMemAllocID = id;288 289 MUTEX_UNLOCK(&memBlockListMutex);290 291 return old;292 }293 294 psMemId psMemFreeCallbackSetID(psMemId id)295 {296 MUTEX_LOCK(&memBlockListMutex);297 298 psMemId old = p_psMemFreeID;299 300 p_psMemFreeID = id;301 302 MUTEX_UNLOCK(&memBlockListMutex);303 304 return old;305 }306 307 psMemAllocCallback psMemAllocCallbackSet(psMemAllocCallback func)308 {309 MUTEX_LOCK(&memBlockListMutex);310 311 psMemFreeCallback old = memAllocCallback;312 313 if (func != NULL) {314 memAllocCallback = func;315 } else {316 memAllocCallback = memAllocCallbackDefault;317 }318 319 MUTEX_UNLOCK(&memBlockListMutex);320 321 return old;322 }323 324 psMemFreeCallback psMemFreeCallbackSet(psMemFreeCallback func)325 {326 MUTEX_LOCK(&memBlockListMutex);327 328 psMemFreeCallback old = memFreeCallback;329 330 if (func != NULL) {331 memFreeCallback = func;332 } else {333 memFreeCallback = memFreeCallbackDefault;334 }335 336 MUTEX_UNLOCK(&memBlockListMutex);337 338 return old;339 }340 341 /*342 * Return memory ID counter for next block to be allocated343 */344 psMemId psMemGetId(void)345 {346 return psMemGetLastId() + 1;347 }348 349 psMemId psMemGetLastId(void)350 {351 MUTEX_LOCK(&memBlockListMutex);352 353 psMemId id = memid;354 355 MUTEX_UNLOCK(&memBlockListMutex);356 357 return id;358 }359 360 int p_psMemCheckCorruption(const char *file,361 unsigned int lineno,362 const char *func,363 FILE *output,364 bool abort_on_error)365 {366 // get exclusive access to the memBlock list to avoid it changing on us367 // while we use it.368 MUTEX_LOCK(&memBlockListMutex);369 370 psS32 nbad = 0; // number of bad blocks371 for (psMemBlock *memBlock = lastMemBlockAllocated; memBlock != NULL; memBlock = memBlock->nextBlock) {372 if (isBadMemBlock(output, memBlock, __FILE__, __LINE__, __func__)) {373 nbad++;374 375 if (abort_on_error) {376 // release the lock on the memblock list377 MUTEX_UNLOCK(&memBlockListMutex);378 PS_MEM_ABORT(__func__, "Detected memory corruption");379 }380 }381 }382 383 // release the lock on the memblock list384 MUTEX_UNLOCK(&memBlockListMutex);385 386 return nbad;387 }388 389 bool p_psMemIsAlloced(const char *file,390 unsigned int lineno,391 const char *func,392 const void *ptr)393 {394 // if ptr is a psAlloc()'d memory, find the actual address of the memBlock395 psMemBlock *addr = ((psMemBlock *)ptr) - 1;396 397 // get exclusive access to the memBlock list to avoid it changing on us398 // while we use it.399 MUTEX_LOCK(&memBlockListMutex);400 401 // loop through the linked list of memBlocks looking for a matching pointer402 for (psMemBlock *memBlock = lastMemBlockAllocated; memBlock != NULL; memBlock = memBlock->nextBlock) {403 if (memBlock == addr) {404 // we found the memBlock405 HANDLE_BAD_BLOCK(memBlock, file, lineno, func);406 407 MUTEX_UNLOCK(&memBlockListMutex);408 return true;409 }410 }411 412 // release the lock on the memblock list413 MUTEX_UNLOCK(&memBlockListMutex);414 415 return false;416 }417 418 419 /*420 * Set whether allocated memory is persistent421 */422 bool p_psMemAllocatePersistent(bool is_persistent)423 {424 MUTEX_LOCK(&memBlockListMutex);425 426 const bool old = memory_is_persistent;427 memory_is_persistent = is_persistent;428 429 MUTEX_UNLOCK(&memBlockListMutex);430 431 return old;432 }433 434 435 /*436 * Actually allocate memory437 */438 void *p_psAlloc(const char *file,439 unsigned int lineno,440 const char *func,441 size_t size)442 {443 444 psMemBlock *memBlock = malloc(sizeof(psMemBlock) + size + sizeof(void *));445 if (memBlock == NULL) {446 MUTEX_LOCK(&memBlockListMutex);447 memBlock = memExhaustedCallback(size);448 MUTEX_UNLOCK(&memBlockListMutex);449 if (memBlock == NULL) {450 PS_MEM_ABORT(__func__, "Failed to allocate %zd bytes at %s (%s:%d)", size, func, file, lineno);451 }452 }453 454 // posts455 *(psU32 *)&memBlock->startblock = P_PS_MEMMAGIC;456 *(psU32 *)&memBlock->endblock = P_PS_MEMMAGIC;457 *(psU32 *)((char *) (memBlock + 1) + size) = P_PS_MEMMAGIC;458 459 // size of memory allocated460 memBlock->userMemorySize = size;461 462 // alloc request by:463 // thread464 *(pthread_t *)&memBlock->tid = pthread_self();465 // file466 memBlock->file = file;467 // line number468 *(unsigned int *)&memBlock->lineno = (unsigned int)lineno;469 // function470 memBlock->func = func;471 472 #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)473 #define BACKTRACE_BUFFER_SIZE 32474 // psMemBlock.func is a 'const char *', so basically we're going to abuse475 // that and treat it as a void ** to carry around backtrace information.476 // psMemBlock is not ifdef'd to make sure that psMemBlock is always the477 // same size & layout reguardless of the pslib .so that's being linked478 // against479 void **bt = malloc(BACKTRACE_BUFFER_SIZE * sizeof(void *));480 if (bt == NULL) {481 PS_MEM_ABORT(__func__, "Failed to allocate memmory for backtrace buffer: %zd bytes at %s (%s:%d)", 32 * sizeof(void *), func, file, lineno);482 }483 *(size_t *)&memBlock->backtraceSize = backtrace(bt, BACKTRACE_BUFFER_SIZE);484 *(void ***)&memBlock->backtrace = bt;485 #endif // ifdef HAVE_BACKTRACE486 487 // free function488 memBlock->freeFunc = NULL;489 490 // persistent memory flag491 memBlock->persistent = memory_is_persistent;492 493 // this block will be add as the last mem block in the list494 memBlock->previousBlock = NULL;495 496 // ref count497 memBlock->refCounter = 1; // one user so far498 499 // need exclusive access of the memory block list now...500 MUTEX_LOCK(&memBlockListMutex);501 502 // increment the memory id only after we've grabbed the memBlockListMutex503 *(psMemId* )&memBlock->id = ++memid;504 505 // insert the new block to the front of the memBlock linked-list506 memBlock->nextBlock = lastMemBlockAllocated;507 if (memBlock->nextBlock != NULL) {508 memBlock->nextBlock->previousBlock = memBlock;509 }510 lastMemBlockAllocated = memBlock;511 512 // Did the user ask to be informed about this allocation?513 if (memBlock->id == p_psMemAllocID) {514 // p_psMemAllocID can only be changed while the memBlockList mutex is515 // held516 p_psMemAllocID += memAllocCallback(memBlock);517 }518 519 MUTEX_UNLOCK(&memBlockListMutex);520 521 // And return the user the memory that they allocated522 return memBlock + 1; // user memory523 }524 525 513 526 514 void *p_psRealloc(const char *file, … … 545 533 // Reallocate the memory 546 534 535 // we need to lock this whole section because we need to be able to adjust 536 // lastMemBlockAllocated if needed (ie, this IS lastMemBlockAllocated) 537 // this lock is frequently called in a given program 538 MUTEX_LOCK(&memBlockListMutex); 539 540 psMemBlock *nextBlock = memBlock->nextBlock; 541 psMemBlock *previousBlock = memBlock->previousBlock; 542 547 543 // Is this the last block we allocated? If it is, we need to keep track of 548 544 // this fact and update lastMemBlockAllocated *after* the realloc or … … 551 547 552 548 memBlock = (psMemBlock *)realloc(memBlock, sizeof(psMemBlock) + size + sizeof(void *)); 553 if (memBlock== NULL) { 554 MUTEX_LOCK(&memBlockListMutex); 549 if (memBlock == NULL) { 555 550 memBlock = memExhaustedCallback(size); 556 551 if (memBlock == NULL) { 557 MUTEX_UNLOCK(&memBlockListMutex);558 552 psMemBlockPrint(stderr, ((psMemBlock *)ptr) - 1); 559 553 fprintf(stderr, "Problem reallocating block\n"); … … 562 556 } 563 557 564 // realloc() successed so need to update lastMemBlockAllocated if we just 565 // mucked with the last mem block 558 memBlock->userMemorySize = size; 559 *(psU32 *)((char *)(memBlock + 1) + size) = P_PS_MEMMAGIC; 560 561 // update the references on the list: 562 563 // is we are modifying the last mem block, we need to update lastMemBlockAllocated 566 564 if (isBlockLast) { 567 565 lastMemBlockAllocated = memBlock; 568 566 } 569 567 570 memBlock->userMemorySize = size;571 *(psU32 *)((char *)(memBlock + 1) + size) = P_PS_MEMMAGIC;572 573 MUTEX_LOCK(&memBlockListMutex);574 575 // Is this the last block we allocated?576 if (memBlock== lastMemBlockAllocated) {577 lastMemBlockAllocated = memBlock;578 }579 580 568 // the block location may have changed, so fix the linked list addresses. 581 if ( memBlock->nextBlock != NULL) {582 memBlock->nextBlock->previousBlock = memBlock;583 } 584 if ( memBlock->previousBlock != NULL) {585 memBlock->previousBlock->nextBlock = memBlock;569 if (nextBlock != NULL) { 570 nextBlock->previousBlock = memBlock; 571 } 572 if (previousBlock != NULL) { 573 previousBlock->nextBlock = memBlock; 586 574 } 587 575 … … 615 603 p_psMemCheckCorruption(file, lineno, func, fd, true); 616 604 605 // this lock is rarely called in a given program 617 606 MUTEX_LOCK(&memBlockListMutex); 618 607 … … 690 679 *array = psAlloc(nleak * sizeof(psMemBlock)); 691 680 681 // this lock is rarely called in a given program 692 682 MUTEX_LOCK(&memBlockListMutex); 693 683 … … 747 737 748 738 // Did the user ask to be informed about this allocation? 749 MUTEX_LOCK(&memBlockListMutex); 739 // this lock is frequently called in a given program 740 // this lock is probably not needed: if someone changes the callback ID in a different thread, 741 // do we really care about really rarely getting this wrong? 742 // MUTEX_LOCK(&memBlockListMutex); 750 743 if (memBlock->id == p_psMemAllocID) { 751 p_psMemAllocID += memAllocCallback(memBlock); 752 } 753 MUTEX_UNLOCK(&memBlockListMutex); 744 // XXX this is seriously bogus: why are we changing this value?? 745 // p_psMemAllocID += memAllocCallback(memBlock); 746 memAllocCallback(memBlock); 747 } 748 // MUTEX_UNLOCK(&memBlockListMutex); 754 749 755 750 return ptr; … … 810 805 811 806 // Did the user ask to be informed about this deallocation? 812 MUTEX_LOCK(&memBlockListMutex);807 // MUTEX_LOCK(&memBlockListMutex); 813 808 if (memBlock->id == p_psMemFreeID) { 814 p_psMemFreeID += memFreeCallback(memBlock); 815 } 816 MUTEX_UNLOCK(&memBlockListMutex); 817 809 // XXX why modify this? this seems bogus 810 // p_psMemFreeID += memFreeCallback(memBlock); 811 memFreeCallback(memBlock); 812 } 813 // MUTEX_UNLOCK(&memBlockListMutex); 818 814 return ptr; 819 815 } … … 825 821 } 826 822 823 // this lock is frequently set in a given program 827 824 MUTEX_LOCK(&memBlockListMutex); 828 825 829 826 // Did the user ask to be informed about this deallocation? 830 827 if (memBlock->id == p_psMemFreeID) { 831 p_psMemFreeID += memFreeCallback(ptr); 832 } 828 // p_psMemFreeID += memFreeCallback(ptr); 829 memFreeCallback(ptr); 830 } 831 832 psMemBlock *nextBlock = memBlock->nextBlock; 833 psMemBlock *previousBlock = memBlock->previousBlock; 833 834 834 835 // cut the memBlock out of the memBlock list 835 if ( memBlock->nextBlock != NULL) {836 memBlock->nextBlock->previousBlock = memBlock->previousBlock;837 } 838 if ( memBlock->previousBlock != NULL) {839 memBlock->previousBlock->nextBlock = memBlock->nextBlock;836 if (nextBlock != NULL) { 837 nextBlock->previousBlock = previousBlock; 838 } 839 if (previousBlock != NULL) { 840 previousBlock->nextBlock = nextBlock; 840 841 } 841 842 if (lastMemBlockAllocated == memBlock) { 842 lastMemBlockAllocated = memBlock->nextBlock; 843 } 843 lastMemBlockAllocated = nextBlock; 844 } 845 846 // NULL out the refs so no one can get confused 847 memBlock->nextBlock = NULL; 848 memBlock->previousBlock = NULL; 844 849 845 850 MUTEX_UNLOCK(&memBlockListMutex); … … 860 865 861 866 867 /**** user functions to manage memory references ****/ 862 868 void p_psMemSetDeallocator(const char *file, 863 869 unsigned int lineno, … … 895 901 896 902 897 bool psMemSetThreadSafety(bool safe)898 {899 MUTEX_LOCK(&memBlockListMutex);900 901 bool oldState = safeThreads;902 safeThreads = safe;903 904 MUTEX_UNLOCK(&memBlockListMutex);905 906 return oldState;907 }908 909 910 bool psMemGetThreadSafety(void)911 {912 MUTEX_LOCK(&memBlockListMutex);913 914 bool oldState = safeThreads;915 916 MUTEX_UNLOCK(&memBlockListMutex);917 918 return oldState;919 }920 921 922 903 bool p_psMemGetPersistent(const char *file, 923 904 unsigned int lineno, … … 954 935 } 955 936 956 957 /******************************************************************************/ 937 int p_psMemCheckCorruption(const char *file, 938 unsigned int lineno, 939 const char *func, 940 FILE *output, 941 bool abort_on_error) 942 { 943 // get exclusive access to the memBlock list to avoid it changing on us while we check it. 944 945 // this lock is rarely called in a given program 946 MUTEX_LOCK(&memBlockListMutex); 947 948 psS32 nbad = 0; // number of bad blocks 949 for (psMemBlock *memBlock = lastMemBlockAllocated; memBlock != NULL; memBlock = memBlock->nextBlock) { 950 if (isBadMemBlock(output, memBlock, __FILE__, __LINE__, __func__)) { 951 nbad++; 952 953 if (abort_on_error) { 954 // release the lock on the memblock list 955 MUTEX_UNLOCK(&memBlockListMutex); 956 PS_MEM_ABORT(__func__, "Detected memory corruption"); 957 } 958 } 959 } 960 961 // release the lock on the memblock list 962 MUTEX_UNLOCK(&memBlockListMutex); 963 964 return nbad; 965 } 966 967 bool p_psMemIsAlloced(const char *file, 968 unsigned int lineno, 969 const char *func, 970 const void *ptr) 971 { 972 // if ptr is a psAlloc()'d memory, find the actual address of the memBlock 973 psMemBlock *addr = ((psMemBlock *)ptr) - 1; 974 975 // get exclusive access to the memBlock list to avoid it changing on us 976 // this lock is only occasionally called in a given program 977 MUTEX_LOCK(&memBlockListMutex); 978 979 // loop through the linked list of memBlocks looking for a matching pointer 980 for (psMemBlock *memBlock = lastMemBlockAllocated; memBlock != NULL; memBlock = memBlock->nextBlock) { 981 if (memBlock == addr) { 982 // we found the memBlock 983 HANDLE_BAD_BLOCK(memBlock, file, lineno, func); 984 985 MUTEX_UNLOCK(&memBlockListMutex); 986 return true; 987 } 988 } 989 990 // release the lock on the memblock list 991 MUTEX_UNLOCK(&memBlockListMutex); 992 993 return false; 994 } 995 996 997 /**** memory usage statistics functions ****/ 998 958 999 /* 959 1000 * Return the total amount of memory owned by psLib; if non-NULL also provide a … … 973 1014 } 974 1015 1016 // this lock is rarely called in a given program 975 1017 MUTEX_LOCK(&memBlockListMutex); 976 1018 /*
Note:
See TracChangeset
for help on using the changeset viewer.
