IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jan 24, 2007, 12:14:48 PM (19 years ago)
Author:
jhoblitt
Message:

merge jch-memory branch - overhaul of memory subsystem

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/sys/psMemory.c

    r10547 r11265  
    33*  @brief Contains the definitions for the memory management system
    44*
    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.
    67*
    78*  @author Robert DeSonia, MHPCC
    89*  @author Robert Lupton, Princeton University
     10*  @author Joshua Hoblitt, University of Hawaii
    911*
    10 *  @version $Revision: 1.88 $ $Name: not supported by cvs2svn $
    11 *  @date $Date: 2006-12-08 11:35:54 $
     12*  @version $Revision: 1.89 $ $Name: not supported by cvs2svn $
     13*  @date $Date: 2007-01-24 22:14:48 $
    1214*
    1315*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
    1416*/
     17
     18#if HAVE_CONFIG_H
     19# include "config.h"
     20#endif
    1521
    1622#define PS_ALLOW_MALLOC                    // we're allowed to call malloc()
     
    2228#include <assert.h>
    2329
     30#if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)
     31# include <execinfo.h>
     32#endif
     33
    2434#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) \
     38if (safeThreads) { \
     39    pthread_mutex_lock(mutexPtr); \
     40}
     41
     42#define MUTEX_UNLOCK(mutexPtr) \
     43if (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, ...) \
     54P_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, ...) \
     59fprintf(stderr, "%s (%s:%d) ", func, filename, lineno); \
     60fprintf(stderr, __VA_ARGS__);\
     61psErrorStackPrint(stderr, "\nAborting.  Error stack:\n"); \
     62fprintf(stderr, "\n");\
     63abort();
     64
     65#define HANDLE_BAD_BLOCK(memBlock, file, lineo, func) \
     66if (isBadMemBlock(stderr, memBlock, file, lineo, func)) { \
     67    PS_MEM_ABORT(__func__, "Unsafe to Continue\n"); \
     68}
     69
     70static 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
     73static 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//
    4495static pthread_mutex_t memBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
    45 static pthread_mutex_t memIdMutex = PTHREAD_MUTEX_INITIALIZER;
    4696
    4797//private boolean for enabling/disabling thread safety.  Default = enabled.
     
    51101static bool memory_is_persistent = false;
    52102
    53 #ifdef PS_MEM_USE_RECYCLE               // Only use recycling if this is set
    54 #define N_RECYCLE_BINS 14               // number of recycle bins
    55 #define MAX_RECYCLE 100                 // Maximum number permitted in a recycle bin
    56 static pthread_mutex_t recycleMemBlockListMutex = PTHREAD_MUTEX_INITIALIZER; // Mutex for recycle bins
    57 static const psS32 recycleBinSize[N_RECYCLE_BINS] = // Size of each bin
    58     {
    59         8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, P_PS_LARGE_BLOCK_SIZE
    60     };
    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 bin
    63 static psMemBlock* recycleMemBlockList[N_RECYCLE_BINS] = // Contents of the bins
    64     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
    65 #endif // #ifdef PS_MEM_USE_RECYCLE
    66 
    67 #ifdef PS_MEM_DEBUG
    68 static psMemBlock* deadBlockList;       // a place to put dead memBlocks in debug mode.
    69 #endif // #ifdef PS_MEM_DEBUG
    70 
    71103/**
    72104 * Unique ID for allocated blocks
     
    79111static psPtr memExhaustedCallbackDefault(size_t size)
    80112{
    81     #if PS_MEM_USE_RECYCLE
    82     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 ptr
    87     int bin = N_RECYCLE_BINS - 1;       // Recycle bin
    88 
    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_RECYCLE
    104 
    105113    return NULL;
    106     #endif // #ifdef PS_MEM_USE_RECYCLE
    107114}
    108115
     
    113120 * isn't resignalled)
    114121 */
    115 static psMemId memAllocCallbackDefault(const psMemBlock* ptr)
     122static psMemId memAllocCallbackDefault(const psMemBlock *memBlock)
    116123{
    117124    static psMemId incr = 0; // "p_psMemAllocID += incr"
     
    120127}
    121128
    122 static psMemId memFreeCallbackDefault(const psMemBlock* ptr)
     129static psMemId memFreeCallbackDefault(const psMemBlock *memBlock)
    123130{
    124131    static psMemId incr = 0; // "p_psMemFreeID += incr"
    125132
    126133    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     }
    142134}
    143135
     
    147139 * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted
    148140 */
    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) {
     141static 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) {
    162170        // 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;
    183223}
    184224
     
    188228 * with psMem{Alloc,Free}CallbackSet
    189229 */
    190 static psMemId memAllocCallbackCheckCorruption(const psMemBlock *ptr)
     230static psMemId memAllocCallbackCheckCorruption(const psMemBlock *memBlock)
    191231{
    192232    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
    197236    }
    198237
     
    205244static psMemAllocCallback memAllocCallback = memAllocCallbackDefault;
    206245static psMemFreeCallback memFreeCallback = memFreeCallbackDefault;
    207 static psMemProblemCallback memProblemCallback = memProblemCallbackDefault;
    208246static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;
    209247
    210248psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func)
    211249{
     250    MUTEX_LOCK(&memBlockListMutex);
     251
    212252    psMemExhaustedCallback old = memExhaustedCallback;
    213253
     
    218258    }
    219259
    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);
    232261
    233262    return old;
     
    244273psMemId psMemAllocCallbackSetID(psMemId id)
    245274{
     275    MUTEX_LOCK(&memBlockListMutex);
     276
    246277    psMemId old = p_psMemAllocID;
    247278
     
    253284    p_psMemAllocID = id;
    254285
     286    MUTEX_UNLOCK(&memBlockListMutex);
     287
    255288    return old;
    256289}
     
    258291psMemId psMemFreeCallbackSetID(psMemId id)
    259292{
     293    MUTEX_LOCK(&memBlockListMutex);
     294
    260295    psMemId old = p_psMemFreeID;
    261296
    262297    p_psMemFreeID = id;
    263298
     299    MUTEX_UNLOCK(&memBlockListMutex);
     300
    264301    return old;
    265302}
     
    267304psMemAllocCallback psMemAllocCallbackSet(psMemAllocCallback func)
    268305{
     306    MUTEX_LOCK(&memBlockListMutex);
     307
    269308    psMemFreeCallback old = memAllocCallback;
    270309
     
    275314    }
    276315
     316    MUTEX_UNLOCK(&memBlockListMutex);
     317
    277318    return old;
    278319}
     
    280321psMemFreeCallback psMemFreeCallbackSet(psMemFreeCallback func)
    281322{
     323    MUTEX_LOCK(&memBlockListMutex);
     324
    282325    psMemFreeCallback old = memFreeCallback;
    283326
     
    288331    }
    289332
     333    MUTEX_UNLOCK(&memBlockListMutex);
     334
    290335    return old;
    291336}
     
    301346psMemId psMemGetLastId(void)
    302347{
    303     if (safeThreads) {
    304         pthread_mutex_lock(&memIdMutex);
    305     }
     348    MUTEX_LOCK(&memBlockListMutex);
    306349
    307350    psMemId id = memid;
    308351
    309     if (safeThreads) {
    310         pthread_mutex_unlock(&memIdMutex);
    311     }
     352    MUTEX_UNLOCK(&memBlockListMutex);
    312353
    313354    return id;
    314355}
    315356
    316 int psMemCheckCorruption(bool abort_on_error)
    317 {
     357int 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
    318363    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__)) {
    333366            nbad++;
    334 
    335             memProblemCallback(iter, __func__, __LINE__);
    336367
    337368            if (abort_on_error) {
    338369                // 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");
    343372                return nbad;
    344373            }
     
    347376
    348377    // release the lock on the memblock list
    349     if (safeThreads) {
    350         pthread_mutex_unlock(&memBlockListMutex);
    351     }
     378    MUTEX_UNLOCK(&memBlockListMutex);
     379
    352380    return nbad;
    353381}
     
    358386bool p_psMemAllocatePersistent(bool is_persistent)
    359387{
     388    MUTEX_LOCK(&memBlockListMutex);
     389
    360390    const bool old = memory_is_persistent;
    361391    memory_is_persistent = is_persistent;
    362392
     393    MUTEX_UNLOCK(&memBlockListMutex);
     394
    363395    return old;
    364396}
    365 
    366 #ifdef PS_MEM_USE_RECYCLE
    367 // Return the appropriate recycle bin number
    368 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 number
    374     while (size > recycleBinSize[binNum]) {
    375         binNum++;
    376     }
    377     return binNum;
    378 }
    379 
    380 // Push a pointer onto the recycle bin
    381 static void recyclePush(psMemBlock *mb, // Pointer to push
    382                         int bin         // Recycling bin
    383                        )
    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 bin
    409 static psMemBlock *recyclePop(int bin   // Recycling bin
    410                              )
    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 bin
    421 
    422     if (mb) {
    423         // We pull it off the list
    424         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_RECYCLE
    438397
    439398/*
     
    442401psPtr p_psAlloc(size_t size,
    443402                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
    491461
    492462    // 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;
    496467
    497468    // 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;
    507474
    508475    // 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
    512484    // And return the user the memory that they allocated
    513     return ptr + 1;                        // user memory
    514 }
    515 
    516 psPtr p_psRealloc(psPtr vptr,
     485    return memBlock + 1;                        // user memory
     486}
     487
     488psPtr p_psRealloc(psPtr ptr,
    517489                  size_t size,
    518490                  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) {
    542503        // Nothing to do
    543         return vptr;
     504        return ptr;
    544505    }
    545506
    546507    // Reallocate the memory
    547508
    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
    564528    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;
    566540    }
    567541
    568542    // 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;
    578548    }
    579549
    580550    // 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
    609558}
    610559
     
    619568    psS32 nleak = 0;
    620569    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)) {
    631583
    632584            nleak++;
     
    634586            if (fd != NULL) {
    635587                if (nleak == 1) {
    636                     fprintf(fd, "   %20s:line ID\n", "file");
     588                    fprintf(fd, "# func at (file:line)  ID: X\n");
    637589                }
    638590
    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
    640629            }
    641630        }
    642631    }
    643632
    644     if (safeThreads) {
    645         pthread_mutex_unlock(&memBlockListMutex);
    646     }
     633    MUTEX_UNLOCK(&memBlockListMutex);
    647634
    648635    if (nleak == 0 || array == NULL) {
     
    650637    }
    651638
    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;
    663649            if (j == nleak) {              // found them all
    664650                break;
     
    667653    }
    668654
    669     if (safeThreads) {
    670         pthread_mutex_unlock(&memBlockListMutex);
    671     }
     655    MUTEX_UNLOCK(&memBlockListMutex);
    672656
    673657    return nleak;
     
    679663
    680664// return refCounter
    681 psReferenceCount psMemGetRefCounter(const psPtr ptr)
    682 {
    683     psMemBlock* ptr2;
    684     psU32 refCount;
    685 
     665psReferenceCount p_psMemGetRefCounter(const psPtr ptr,
     666                                      const char *file,
     667                                      unsigned int lineno,
     668                                      const char *func)
     669{
    686670    if (ptr == NULL) {
    687671        return 0;
    688672    }
    689673
    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;
    705679}
    706680
    707681// increment and return refCounter
    708 psPtr p_psMemIncrRefCounter(const psPtr vptr,
     682psPtr p_psMemIncrRefCounter(const psPtr ptr,
    709683                            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++;
    731696
    732697    // 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
    740708psPtr p_psMemSetRefCounter(psPtr vptr,
    741709                           psReferenceCount count,
     
    755723    ptr = ((psMemBlock* ) vptr) - 1;
    756724
    757     if (checkMemBlock(ptr, __func__)) {
     725    if (isBadMemBlock(ptr, __func__)) {
     726        (void)p_psMemDecrRefCounter(vptr, filename, lineno);
    758727        memProblemCallback(ptr, file, lineno);
    759728    }
    760729
    761     if (safeThreads) {
    762         pthread_mutex_lock(&ptr->refCounterMutex);
    763     }
    764730    ptr->refCounter = count;
    765     if (safeThreads) {
    766         pthread_mutex_unlock(&ptr->refCounterMutex);
    767     }
    768731
    769732    if (count < 1) {
     
    773736    return vptr;
    774737}
     738#endif
    775739
    776740// decrement and return refCounter
    777 psPtr p_psMemDecrRefCounter(psPtr vptr,
     741psPtr p_psMemDecrRefCounter(psPtr ptr,
    778742                            const char *file,
    779                             psS32 lineno)
    780 {
    781     if (vptr == NULL) {
     743                            unsigned int lineno,
     744                            const char *func)
     745{
     746    if (ptr == NULL) {
    782747        return NULL;
    783748    }
    784749
    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);
    791775
    792776    // Did the user ask to be informed about this deallocation?
    793     if (ptr->id == p_psMemFreeID) {
     777    if (memBlock->id == p_psMemFreeID) {
    794778        p_psMemFreeID += memFreeCallback(ptr);
    795779    }
    796780
    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
     808void p_psMemSetDeallocator(psPtr ptr,
     809                           psFreeFunc freeFunc,
     810                           const char *file,
     811                           unsigned int lineno,
     812                           const char *func)
    871813{
    872814    if (ptr == NULL) {
     
    874816    }
    875817
    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
     825psFreeFunc p_psMemGetDeallocator(const psPtr ptr,
     826                                 const char *file,
     827                                 unsigned int lineno,
     828                                 const char *func)
    887829{
    888830    if (ptr == NULL) {
     
    890832    }
    891833
    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;
    1168839}
    1169840
    1170841bool psMemSetThreadSafety(bool safe)
    1171842{
    1172     bool out = safeThreads;
     843    MUTEX_LOCK(&memBlockListMutex);
     844
     845    bool oldState = safeThreads;
    1173846    safeThreads = safe;
    1174     return out;
     847
     848    MUTEX_UNLOCK(&memBlockListMutex);
     849
     850    return oldState;
    1175851}
    1176852
    1177853bool psMemGetThreadSafety(void)
    1178854{
    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
     864bool p_psMemGetPersistent(psPtr ptr,
     865                          const char *file,
     866                          unsigned int lineno,
     867                          const char *func)
     868{
     869    if (ptr == NULL) {
    1185870        return NULL;
    1186871    }
    1187872
    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
     880void p_psMemSetPersistent(psPtr ptr,
     881                          bool value,
     882                          const char *file,
     883                          unsigned int lineno,
     884                          const char *func)
     885{
     886    if (ptr == NULL) {
    1201887        return;
    1202888    }
    1203889
    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;
    1211895}
    1212896
     
    1221905size_t psMemStats(const bool print, // print details as they're found?
    1222906                  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
    1225908{
    1226909    const size_t overhead = sizeof(psMemBlock) + sizeof(psPtr); // overhead on each allocation
     
    1230913    }
    1231914
    1232     if (safeThreads) {
    1233         pthread_mutex_lock(&memBlockListMutex);
    1234     }
     915    MUTEX_LOCK(&memBlockListMutex);
    1235916    /*
    1236917     * All memory that's currently allocated, whether persistent or not
     
    1264945        printf("Persistent %6s  %10zd %8zd\n", "", persist, npersist);
    1265946    }
    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
     953int 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.