IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 18809


Ignore:
Timestamp:
Jul 30, 2008, 5:57:31 PM (18 years ago)
Author:
eugene
Message:

substantial cleanup: organized file in common sections; fixed bug in realloc for threading

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branch_20080719/psLib/src/sys/psMemory.c

    r14677 r18809  
    1010*  @author Joshua Hoblitt, University of Hawaii
    1111*
    12 *  @version $Revision: 1.98 $ $Name: not supported by cvs2svn $
    13 *  @date $Date: 2007-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 $
    1414*
    1515*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    7373static bool isBadMemBlock(FILE *output, const psMemBlock *memBlock, const char *file, unsigned int lineo, const char *func);
    7474
    75 // pointer to the last mem block that was allocated
    76 static psMemBlock *lastMemBlockAllocated = NULL;
    77 
    7875// 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
    8385//      "the linked list of mem blocks"
    84 //      p_psMemAllocID
    85 //      p_psMemFreeID
    86 //      memAllocCallback
    87 //      memFreeCallback
    88 //      memExhaustedCallback
    8986//
    9087// This is a fair ammount of stuff to protect with a single mutex but most of
     
    9895static pthread_mutex_t memBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
    9996
    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.
    101100static bool safeThreads = true;
    102101
    103 // private boolean for deciding if allocated memory is persistent
     102// Set the thread-safety state of the memory system: default is true
     103bool 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
     118bool 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
    104133static bool memory_is_persistent = false;
    105134
    106 /**
    107  * Unique ID for allocated blocks
     135/* Set whether allocated memory is persistent
     136 */
     137bool 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
     158static psMemId memAllocCallbackDefault(const psMemBlock *memBlock)
     159{
     160    static psMemId incr = 0; // "p_psMemAllocID += incr"
     161
     162    return incr;
     163}
     164
     165static psMemAllocCallback memAllocCallback = memAllocCallbackDefault;
     166
     167psMemAllocCallback 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?
     187static 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
     191psMemId 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
     208static psMemId memFreeCallbackDefault(const psMemBlock *memBlock)
     209{
     210    static psMemId incr = 0; // "p_psMemFreeID += incr"
     211
     212    return incr;
     213}
     214
     215static psMemFreeCallback memFreeCallback = memFreeCallbackDefault;
     216
     217// this function is called only rarely in a program
     218psMemFreeCallback 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?
     238static psMemId p_psMemFreeID = 0;
     239
     240// the above callback is only called if a specific psMemId is set with this function
     241psMemId 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
     258static void *memExhaustedCallbackDefault(size_t size)
     259{
     260    return NULL;
     261}
     262
     263static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;
     264
     265psMemExhaustedCallback 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 */
     286psMemId 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
    108298 */
    109299static psMemId memid = 0;
    110300
    111 /**
    112  *  Default memExhausted callback.
     301/* Return memory ID counter for next block to be allocated
    113302 */
    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)
     303psMemId 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
    124316 */
    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  *
     317psMemId 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
     331static psMemBlock *lastMemBlockAllocated = NULL;
     332
     333/* Actually allocate memory
     334 */
     335void *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,
    142427 * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted
    143428 */
     
    201486    //  users responsiblity) so all we're really risking is a garbage value.
    202487
     488    //  XXX EAM : is this the error I'm catching in multithreaded processing?
    203489    if (memBlock == memBlock->nextBlock) {
    204490        if (!blockPrinted) {
     
    225511    return bad;
    226512}
    227 
    228 
    229 /*
    230  * A callback function to check the state of the memory system; may be registered
    231  * with psMem{Alloc,Free}CallbackSet
    232  */
    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 breakpoint
    239     }
    240 
    241     return incr;
    242 }
    243 
    244 /*
    245  * The default callbacks
    246  */
    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 callbacks
    270  *
    271  * Call the callbacks when these IDs are allocated/freed
    272  */
    273 psMemId p_psMemAllocID = 0;       // notify user this block is allocated
    274 psMemId p_psMemFreeID = 0;   // notify user this block is freed
    275 
    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 complaining
    284      */
    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 allocated
    343  */
    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 us
    367     // while we use it.
    368     MUTEX_LOCK(&memBlockListMutex);
    369 
    370     psS32 nbad = 0;               // number of bad blocks
    371     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 list
    377                 MUTEX_UNLOCK(&memBlockListMutex);
    378                 PS_MEM_ABORT(__func__, "Detected memory corruption");
    379             }
    380         }
    381     }
    382 
    383     // release the lock on the memblock list
    384     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 memBlock
    395     psMemBlock *addr = ((psMemBlock *)ptr) - 1;
    396 
    397     // get exclusive access to the memBlock list to avoid it changing on us
    398     // while we use it.
    399     MUTEX_LOCK(&memBlockListMutex);
    400 
    401     // loop through the linked list of memBlocks looking for a matching pointer
    402     for (psMemBlock *memBlock = lastMemBlockAllocated; memBlock != NULL; memBlock = memBlock->nextBlock) {
    403         if (memBlock == addr) {
    404             // we found the memBlock
    405             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 list
    413     MUTEX_UNLOCK(&memBlockListMutex);
    414 
    415     return false;
    416 }
    417 
    418 
    419 /*
    420  * Set whether allocated memory is persistent
    421  */
    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 memory
    437  */
    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     // posts
    455     *(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 allocated
    460     memBlock->userMemorySize = size;
    461 
    462     // alloc request by:
    463     // thread
    464     *(pthread_t *)&memBlock->tid = pthread_self();
    465     // file
    466     memBlock->file = file;
    467     // line number
    468     *(unsigned int *)&memBlock->lineno = (unsigned int)lineno;
    469     // function
    470     memBlock->func = func;
    471 
    472     #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)
    473     #define BACKTRACE_BUFFER_SIZE 32
    474     // psMemBlock.func is a 'const char *', so basically we're going to abuse
    475     // 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 the
    477     // same size & layout reguardless of the pslib .so that's being linked
    478     // against
    479     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_BACKTRACE
    486 
    487     // free function
    488     memBlock->freeFunc = NULL;
    489 
    490     // persistent memory flag
    491     memBlock->persistent = memory_is_persistent;
    492 
    493     // this block will be add as the last mem block in the list
    494     memBlock->previousBlock = NULL;
    495 
    496     // ref count
    497     memBlock->refCounter = 1;                   // one user so far
    498 
    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 memBlockListMutex
    503     *(psMemId* )&memBlock->id = ++memid;
    504 
    505     // insert the new block to the front of the memBlock linked-list
    506     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 is
    515         // held
    516         p_psMemAllocID += memAllocCallback(memBlock);
    517     }
    518 
    519     MUTEX_UNLOCK(&memBlockListMutex);
    520 
    521     // And return the user the memory that they allocated
    522     return memBlock + 1;                        // user memory
    523 }
    524 
    525513
    526514void *p_psRealloc(const char *file,
     
    545533    // Reallocate the memory
    546534
     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
    547543    // Is this the last block we allocated?  If it is, we need to keep track of
    548544    // this fact and update lastMemBlockAllocated *after* the realloc or
     
    551547
    552548    memBlock = (psMemBlock *)realloc(memBlock, sizeof(psMemBlock) + size + sizeof(void *));
    553     if (memBlock== NULL) {
    554         MUTEX_LOCK(&memBlockListMutex);
     549    if (memBlock == NULL) {
    555550        memBlock = memExhaustedCallback(size);
    556551        if (memBlock == NULL) {
    557             MUTEX_UNLOCK(&memBlockListMutex);
    558552            psMemBlockPrint(stderr,  ((psMemBlock *)ptr) - 1);
    559553            fprintf(stderr, "Problem reallocating block\n");
     
    562556    }
    563557
    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
    566564    if (isBlockLast) {
    567565        lastMemBlockAllocated = memBlock;
    568566    }
    569567
    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 
    580568    // 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;
    586574    }
    587575
     
    615603    p_psMemCheckCorruption(file, lineno, func, fd, true);
    616604
     605    // this lock is rarely called in a given program
    617606    MUTEX_LOCK(&memBlockListMutex);
    618607
     
    690679    *array = psAlloc(nleak * sizeof(psMemBlock));
    691680
     681    // this lock is rarely called in a given program
    692682    MUTEX_LOCK(&memBlockListMutex);
    693683
     
    747737
    748738    // 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);
    750743    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);
    754749
    755750    return ptr;
     
    810805
    811806        // Did the user ask to be informed about this deallocation?
    812         MUTEX_LOCK(&memBlockListMutex);
     807        // MUTEX_LOCK(&memBlockListMutex);
    813808        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);
    818814        return ptr;
    819815    }
     
    825821    }
    826822
     823    // this lock is frequently set in a given program
    827824    MUTEX_LOCK(&memBlockListMutex);
    828825
    829826    // Did the user ask to be informed about this deallocation?
    830827    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;
    833834
    834835    // 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;
    840841    }
    841842    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;
    844849
    845850    MUTEX_UNLOCK(&memBlockListMutex);
     
    860865
    861866
     867/**** user functions to manage memory references ****/
    862868void p_psMemSetDeallocator(const char *file,
    863869                           unsigned int lineno,
     
    895901
    896902
    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 
    922903bool p_psMemGetPersistent(const char *file,
    923904                          unsigned int lineno,
     
    954935}
    955936
    956 
    957 /******************************************************************************/
     937int 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
     967bool 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
    958999/*
    9591000 * Return the total amount of memory owned by psLib; if non-NULL also provide a
     
    9731014    }
    9741015
     1016    // this lock is rarely called in a given program
    9751017    MUTEX_LOCK(&memBlockListMutex);
    9761018    /*
Note: See TracChangeset for help on using the changeset viewer.