Index: trunk/psLib/src/sys/psMemory.c
===================================================================
--- trunk/psLib/src/sys/psMemory.c	(revision 10547)
+++ trunk/psLib/src/sys/psMemory.c	(revision 11265)
@@ -3,14 +3,20 @@
 *  @brief Contains the definitions for the memory management system
 *
-*  psMemory.h has additional information and documentation of the routines found in this file.
+*  psMemory.h has additional information and documentation of the routines
+*  found in this file.
 *
 *  @author Robert DeSonia, MHPCC
 *  @author Robert Lupton, Princeton University
+*  @author Joshua Hoblitt, University of Hawaii
 *
-*  @version $Revision: 1.88 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-12-08 11:35:54 $
+*  @version $Revision: 1.89 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2007-01-24 22:14:48 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
 
 #define PS_ALLOW_MALLOC                    // we're allowed to call malloc()
@@ -22,26 +28,70 @@
 #include <assert.h>
 
+#if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)
+# include <execinfo.h>
+#endif
+
 #include "psMemory.h"
-#include "psError.h"
-#include "psAssert.h"
-#include "psAbort.h"
-#include "psLogMsg.h"
-#include "psBitSet.h"
-#include "psFits.h"
-#include "psPixels.h"
-#include "psSphereOps.h"
-#include "psMinimizeLMM.h"
-#include "psImageConvolve.h"
-#include "psTime.h"
-#include "psLine.h"
-#include "psRegion.h"
-#include "psHistogram.h"
-
-#define P_PS_LARGE_BLOCK_SIZE 65536        // size where under, we try to recycle
-
-static psS32 checkMemBlock(const psMemBlock* m, const char *funcName);
-static psMemBlock* lastMemBlockAllocated = NULL;
+#include "psError.h"    // for psErrorStackPrint() only
+
+#define MUTEX_LOCK(mutexPtr) \
+if (safeThreads) { \
+    pthread_mutex_lock(mutexPtr); \
+}
+
+#define MUTEX_UNLOCK(mutexPtr) \
+if (safeThreads) { \
+    pthread_mutex_unlock(mutexPtr); \
+}
+
+// psAbort() calls functions that call psAlloc() so it is *UNSAFE* to use it
+// from within the memory subsystem.  Previous implementations tried to do
+// this and would deadlock while trying to allocate memory.
+//
+// Note that psError() is also *UNSAFE* to use from within the memory
+// subsystem.
+#define PS_MEM_ABORT(name, ...) \
+P_PS_MEM_ABORT(__FILE__, __LINE__, __func__, name, __VA_ARGS__)
+
+// psErrorStackPrint() was specifically modified to be safe to call from inside
+// psMemory.c.
+#define P_PS_MEM_ABORT(filename, lineno, func, name, ...) \
+fprintf(stderr, "%s (%s:%d) ", func, filename, lineno); \
+fprintf(stderr, __VA_ARGS__);\
+psErrorStackPrint(stderr, "\nAborting.  Error stack:\n"); \
+fprintf(stderr, "\n");\
+abort();
+
+#define HANDLE_BAD_BLOCK(memBlock, file, lineo, func) \
+if (isBadMemBlock(stderr, memBlock, file, lineo, func)) { \
+    PS_MEM_ABORT(__func__, "Unsafe to Continue\n"); \
+}
+
+static bool isBadMemBlock(FILE *output, const psMemBlock *memBlock, const char *file, unsigned int lineo, const char *func);
+
+// pointer to the last mem block that was allocated
+static psMemBlock *lastMemBlockAllocated = NULL;
+
+// memBlockListMutex protects access to:
+//      lastMemBlockAllocated
+//      safeThreads
+//      memid
+//      memory_is_persistent
+//      "the linked list of mem blocks"
+//      p_psMemAllocID
+//      p_psMemFreeID
+//      memAllocCallback
+//      memFreeCallback
+//      memExhaustedCallback
+//
+// This is a fair ammount of stuff to protect with a single mutex but most of
+// these items are *VERY* low contention items.  The only item that should be
+// performance issue is "the linked list of mem blocks".  If this does become a
+// problem in production use of the list should be disabled as it is really a
+// debugging feature.
+//
+// XXX make the mem block list a build time option
+//
 static pthread_mutex_t memBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t memIdMutex = PTHREAD_MUTEX_INITIALIZER;
 
 //private boolean for enabling/disabling thread safety.  Default = enabled.
@@ -51,22 +101,4 @@
 static bool memory_is_persistent = false;
 
-#ifdef PS_MEM_USE_RECYCLE               // Only use recycling if this is set
-#define N_RECYCLE_BINS 14               // number of recycle bins
-#define MAX_RECYCLE 100                 // Maximum number permitted in a recycle bin
-static pthread_mutex_t recycleMemBlockListMutex = PTHREAD_MUTEX_INITIALIZER; // Mutex for recycle bins
-static const psS32 recycleBinSize[N_RECYCLE_BINS] = // Size of each bin
-    {
-        8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, P_PS_LARGE_BLOCK_SIZE
-    };
-// N.B. recycleBinSize should be terminated by P_PS_LARGE_BLOCK_SIZE (simplifies search loops)
-static psS32 recycleBinNums[N_RECYCLE_BINS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Number in each bin
-static psMemBlock* recycleMemBlockList[N_RECYCLE_BINS] = // Contents of the bins
-    { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-#endif // #ifdef PS_MEM_USE_RECYCLE
-
-#ifdef PS_MEM_DEBUG
-static psMemBlock* deadBlockList;       // a place to put dead memBlocks in debug mode.
-#endif // #ifdef PS_MEM_DEBUG
-
 /**
  * Unique ID for allocated blocks
@@ -79,30 +111,5 @@
 static psPtr memExhaustedCallbackDefault(size_t size)
 {
-    #if PS_MEM_USE_RECYCLE
-    psPtr ptr = NULL;
-    if (safeThreads) {
-        pthread_mutex_lock(&recycleMemBlockListMutex);
-    }
-    // Attempt to free up everything I can find so I can alloc my ptr
-    int bin = N_RECYCLE_BINS - 1;       // Recycle bin
-
-    while (bin >= 0 && ptr == NULL) {
-        while (recycleMemBlockList[bin] != NULL && ptr == NULL) {
-            psMemBlock *old = recycleMemBlockList[bin];
-            recycleMemBlockList[bin] = recycleMemBlockList[bin]->nextBlock;
-            free(old);
-            ptr = malloc(size);
-        }
-        bin--;
-    }
-
-    if (safeThreads) {
-        pthread_mutex_unlock(&recycleMemBlockListMutex);
-    }
-    return ptr;
-    #else  // #ifdef PS_MEM_USE_RECYCLE
-
     return NULL;
-    #endif // #ifdef PS_MEM_USE_RECYCLE
 }
 
@@ -113,5 +120,5 @@
  * isn't resignalled)
  */
-static psMemId memAllocCallbackDefault(const psMemBlock* ptr)
+static psMemId memAllocCallbackDefault(const psMemBlock *memBlock)
 {
     static psMemId incr = 0; // "p_psMemAllocID += incr"
@@ -120,24 +127,9 @@
 }
 
-static psMemId memFreeCallbackDefault(const psMemBlock* ptr)
+static psMemId memFreeCallbackDefault(const psMemBlock *memBlock)
 {
     static psMemId incr = 0; // "p_psMemFreeID += incr"
 
     return incr;
-}
-
-static void memProblemCallbackDefault(psMemBlock* ptr,
-                                      const char *file,
-                                      unsigned int lineno)
-{
-    if (ptr->refCounter < 1) {
-        psError(PS_ERR_MEMORY_CORRUPTION, false,
-                _("Block %lu, allocated at %s:%d, freed multiple times at %s:%d."),
-                (unsigned long)ptr->id, ptr->file, ptr->lineno, file, lineno);
-    }
-
-    if (lineno > 0) {
-        psAbort(__func__, "Detected a problem in the memory system at %s:%d", file, lineno);
-    }
 }
 
@@ -147,38 +139,86 @@
  * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted
  */
-static psS32 checkMemBlock(const psMemBlock* m,
-                           const char *funcName)
-{
-    // n.b. since this is called by psMemCheckCorruption while the memblock list is mutex locked,
-    // we shouldn't call such things as p_psAlloc/p_psFree here.
-
-    if (m == NULL) {
-        psError(PS_ERR_MEMORY_CORRUPTION, true,
-                _("NULL memory block found."));
-        return 1;
-    }
-
-    if (m->refCounter == 0) {
+static bool isBadMemBlock(FILE *output, const psMemBlock *memBlock, const char *file, unsigned int lineno, const char *func)
+{
+    // n.b. since this is called by psMemCheckCorruption while the memblock
+    // list is mutex locked, we shouldn't call such things as
+    // p_psAlloc/p_psFree here.
+
+    bool bad = false;
+    bool blockPrinted = false;
+
+    if (memBlock == NULL) {
+        fprintf(output, _("NULL memory block.\n"
+                          "Caught in %s at (%s:%d.).\n\n"), func, file, lineno);
+        // return now as we can't do anything else
+        return true;
+    }
+
+    #if 0
+    // Currently psAlloc()/psRealloc() will blindly create memBlock's with a
+    // size of 0.  This test is in here to check if this is really
+    // happening/being use as a feature in the wild.
+    if (memBlock->userMemorySize < 1) {
+        psMemBlockPrint(output, memBlock);
+        blockPrinted = true;
+        fprintf(output, _("\n\tMemory block has a size of less than 1.\n"));
+        bad = true;
+    }
+    #endif
+
+    if (memBlock->refCounter < 1) {
         // using an unreferenced block of memory, are you?
-        psError(PS_ERR_MEMORY_CORRUPTION, true,
-                _("Memory block %lu was freed but still being used."),
-                (unsigned long)m->id);
-        return 1;
-    }
-
-    if (m->startblock != P_PS_MEMMAGIC || m->endblock != P_PS_MEMMAGIC) {
-        psError(PS_ERR_MEMORY_CORRUPTION, true,
-                _("Memory block %lu is corrupted; buffer underflow detected."),
-                (unsigned long)m->id);
-        return 1;
-    }
-    if (*(psPtr *)((int8_t *) (m + 1) + m->userMemorySize) != P_PS_MEMMAGIC) {
-        psError(PS_ERR_MEMORY_CORRUPTION, true,
-                _("Memory block %lu is corrupted; buffer overflow detected."),
-                (unsigned long)m->id);
-        return 1;
-    }
-
-    return 0;
+        psMemBlockPrint(output, memBlock);
+        blockPrinted = true;
+        fprintf(output, _("\n\tMemory block was freed but still being used.\n"));
+        bad = true;
+    }
+
+    if (memBlock->startblock != P_PS_MEMMAGIC || memBlock->endblock != P_PS_MEMMAGIC) {
+        if (!blockPrinted) {
+            psMemBlockPrint(output, memBlock);
+            blockPrinted = true;
+        }
+        fprintf(output, _("\n\tMemory block is corrupted; buffer underflow detected.\n"));
+        bad = true;
+    }
+
+    if (*(psU32 *)((char *)(memBlock + 1) + memBlock->userMemorySize) != P_PS_MEMMAGIC) {
+        if (!blockPrinted) {
+            psMemBlockPrint(output, memBlock);
+            blockPrinted = true;
+        }
+        fprintf(output, _("\n\tMemory block is corrupted; buffer overflow detected.\n"));
+        bad = true;
+    }
+
+    //  XXX ->nextBlock, & -> prevousBlock really should not be looked at by
+    //  this function as they may be changed out from underneath us by new
+    //  memory allocation.  However, the memBlock itself shouldn't go away (end
+    //  users responsiblity) so all we're really risking is a garbage value.
+
+    if (memBlock == memBlock->nextBlock) {
+        if (!blockPrinted) {
+            psMemBlockPrint(output, memBlock);
+            blockPrinted = true;
+        }
+        fprintf(output, _("\n\tMemory block's ->nextBlock pointer refers to itself.\n"));
+        bad = true;
+    }
+
+    if (memBlock == memBlock->previousBlock) {
+        if (!blockPrinted) {
+            psMemBlockPrint(output, memBlock);
+            blockPrinted = true;
+        }
+        fprintf(output, _("\n\tMemory block's ->previousBlock pointer refers to itself.\n"));
+        bad = true;
+    }
+
+    if (bad) {
+        fprintf(output, _("\tCaught in %s at (%s:%d).\n\n"), func, file, lineno);
+    }
+
+    return bad;
 }
 
@@ -188,11 +228,10 @@
  * with psMem{Alloc,Free}CallbackSet
  */
-static psMemId memAllocCallbackCheckCorruption(const psMemBlock *ptr)
+static psMemId memAllocCallbackCheckCorruption(const psMemBlock *memBlock)
 {
     static psMemId incr = 10; // "p_psMemAllocID += incr"
-    bool abort_on_error = false;
-
-    if (psMemCheckCorruption(abort_on_error) > 0) {
-        fprintf(stderr,"Detected memory corruption\n"); // somewhere to set a breakpoint
+
+    if (psMemCheckCorruption(stderr, false) > 0) {
+        fprintf(stderr, "Detected memory corruption\n"); // somewhere to set a breakpoint
     }
 
@@ -205,9 +244,10 @@
 static psMemAllocCallback memAllocCallback = memAllocCallbackDefault;
 static psMemFreeCallback memFreeCallback = memFreeCallbackDefault;
-static psMemProblemCallback memProblemCallback = memProblemCallbackDefault;
 static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;
 
 psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func)
 {
+    MUTEX_LOCK(&memBlockListMutex);
+
     psMemExhaustedCallback old = memExhaustedCallback;
 
@@ -218,16 +258,5 @@
     }
 
-    return old;
-}
-
-psMemProblemCallback psMemProblemCallbackSet(psMemProblemCallback func)
-{
-    psMemProblemCallback old = memProblemCallback;
-
-    if (func != NULL) {
-        memProblemCallback = func;
-    } else {
-        memProblemCallback = memProblemCallbackDefault;
-    }
+    MUTEX_UNLOCK(&memBlockListMutex);
 
     return old;
@@ -244,4 +273,6 @@
 psMemId psMemAllocCallbackSetID(psMemId id)
 {
+    MUTEX_LOCK(&memBlockListMutex);
+
     psMemId old = p_psMemAllocID;
 
@@ -253,4 +284,6 @@
     p_psMemAllocID = id;
 
+    MUTEX_UNLOCK(&memBlockListMutex);
+
     return old;
 }
@@ -258,8 +291,12 @@
 psMemId psMemFreeCallbackSetID(psMemId id)
 {
+    MUTEX_LOCK(&memBlockListMutex);
+
     psMemId old = p_psMemFreeID;
 
     p_psMemFreeID = id;
 
+    MUTEX_UNLOCK(&memBlockListMutex);
+
     return old;
 }
@@ -267,4 +304,6 @@
 psMemAllocCallback psMemAllocCallbackSet(psMemAllocCallback func)
 {
+    MUTEX_LOCK(&memBlockListMutex);
+
     psMemFreeCallback old = memAllocCallback;
 
@@ -275,4 +314,6 @@
     }
 
+    MUTEX_UNLOCK(&memBlockListMutex);
+
     return old;
 }
@@ -280,4 +321,6 @@
 psMemFreeCallback psMemFreeCallbackSet(psMemFreeCallback func)
 {
+    MUTEX_LOCK(&memBlockListMutex);
+
     psMemFreeCallback old = memFreeCallback;
 
@@ -288,4 +331,6 @@
     }
 
+    MUTEX_UNLOCK(&memBlockListMutex);
+
     return old;
 }
@@ -301,44 +346,28 @@
 psMemId psMemGetLastId(void)
 {
-    if (safeThreads) {
-        pthread_mutex_lock(&memIdMutex);
-    }
+    MUTEX_LOCK(&memBlockListMutex);
 
     psMemId id = memid;
 
-    if (safeThreads) {
-        pthread_mutex_unlock(&memIdMutex);
-    }
+    MUTEX_UNLOCK(&memBlockListMutex);
 
     return id;
 }
 
-int psMemCheckCorruption(bool abort_on_error)
-{
+int psMemCheckCorruption(FILE *output, bool abort_on_error)
+{
+    // get exclusive access to the memBlock list to avoid it changing on us
+    // while we use it.
+    MUTEX_LOCK(&memBlockListMutex);
+
     psS32 nbad = 0;               // number of bad blocks
-    psBool failure = false;
-
-    // get exclusive access to the memBlock list to avoid it changing on us while we use it.
-    //    pthread_mutex_lock(&memBlockListMutex);
-
-    for (psMemBlock* iter = lastMemBlockAllocated; iter != NULL; iter = iter->nextBlock) {
-        if (safeThreads) {
-            pthread_mutex_unlock(&memBlockListMutex);
-        }
-        failure = checkMemBlock(iter, __func__);
-        if (safeThreads) {
-            pthread_mutex_lock(&memBlockListMutex);
-        }
-        if ( failure ) {
+    for (psMemBlock *memBlock = lastMemBlockAllocated; memBlock != NULL; memBlock = memBlock->nextBlock) {
+        if (isBadMemBlock(output, memBlock, __FILE__, __LINE__, __func__)) {
             nbad++;
-
-            memProblemCallback(iter, __func__, __LINE__);
 
             if (abort_on_error) {
                 // release the lock on the memblock list
-                if (safeThreads) {
-                    pthread_mutex_unlock(&memBlockListMutex);
-                }
-                psAbort(__func__, "Detected memory corruption");
+                MUTEX_UNLOCK(&memBlockListMutex);
+                PS_MEM_ABORT(__func__, "Detected memory corruption");
                 return nbad;
             }
@@ -347,7 +376,6 @@
 
     // release the lock on the memblock list
-    if (safeThreads) {
-        pthread_mutex_unlock(&memBlockListMutex);
-    }
+    MUTEX_UNLOCK(&memBlockListMutex);
+
     return nbad;
 }
@@ -358,82 +386,13 @@
 bool p_psMemAllocatePersistent(bool is_persistent)
 {
+    MUTEX_LOCK(&memBlockListMutex);
+
     const bool old = memory_is_persistent;
     memory_is_persistent = is_persistent;
 
+    MUTEX_UNLOCK(&memBlockListMutex);
+
     return old;
 }
-
-#ifdef PS_MEM_USE_RECYCLE
-// Return the appropriate recycle bin number
-static int getRecycleBin(size_t size)
-{
-    if (size >= P_PS_LARGE_BLOCK_SIZE) {
-        return N_RECYCLE_BINS;
-    }
-    int binNum = 0;                     // Recycle bin number
-    while (size > recycleBinSize[binNum]) {
-        binNum++;
-    }
-    return binNum;
-}
-
-// Push a pointer onto the recycle bin
-static void recyclePush(psMemBlock *mb, // Pointer to push
-                        int bin         // Recycling bin
-                       )
-{
-    assert(mb);
-    assert(bin < N_RECYCLE_BINS);
-
-    mb->previousBlock = NULL;
-
-    if (safeThreads) {
-        pthread_mutex_lock(&recycleMemBlockListMutex);
-    }
-
-    mb->nextBlock = recycleMemBlockList[bin];
-    if (recycleMemBlockList[bin] != NULL) {
-        recycleMemBlockList[bin]->previousBlock = mb;
-    }
-    recycleMemBlockList[bin] = mb;
-    recycleBinNums[bin]++;
-
-    if (safeThreads) {
-        pthread_mutex_unlock(&recycleMemBlockListMutex);
-    }
-
-    return;
-}
-
-// Pop a pointer from the recycle bin
-static psMemBlock *recyclePop(int bin   // Recycling bin
-                             )
-{
-    if (bin >= N_RECYCLE_BINS) {
-        return NULL;
-    }
-
-    if (safeThreads) {
-        pthread_mutex_lock(&recycleMemBlockListMutex);
-    }
-
-    psMemBlock *mb = recycleMemBlockList[bin]; // Pointer popped from recycle bin
-
-    if (mb) {
-        // We pull it off the list
-        recycleMemBlockList[bin] = mb->nextBlock;
-        if (recycleMemBlockList[bin] != NULL) {
-            recycleMemBlockList[bin]->previousBlock = NULL;
-        }
-        recycleBinNums[bin]--;
-    }
-
-    if (safeThreads) {
-        pthread_mutex_unlock(&recycleMemBlockListMutex);
-    }
-
-    return mb;
-}
-#endif // #ifdef PS_MEM_USE_RECYCLE
 
 /*
@@ -442,169 +401,159 @@
 psPtr p_psAlloc(size_t size,
                 const char *file,
-                unsigned int lineno)
-{
-
-    psMemBlock *ptr = NULL;
-
-    #ifdef PS_MEM_USE_RECYCLE
-    // Are we in one of the recycle bins?
-    int bin = getRecycleBin(size);
-    if (bin < N_RECYCLE_BINS) {
-        size = recycleBinSize[bin];     // round-up size to next sized bin.
-        ptr = recyclePop(bin);          // grab out of the recycle bin
-    }
-    #endif // #ifdef PS_MEM_USE_RECYCLE
-
-    if (ptr == NULL) {
-        ptr = malloc(sizeof(psMemBlock) + size + sizeof(psPtr ));
-
-        if (ptr == NULL) {
-            ptr = memExhaustedCallback(size);
-            if (ptr == NULL) {
-                psAbort(__func__, "Failed to allocate %zd bytes at %s:%d", size, file, lineno);
-            }
-        }
-
-        *(psPtr*)&ptr->startblock = P_PS_MEMMAGIC;
-        *(psPtr*)&ptr->endblock = P_PS_MEMMAGIC;
-        ptr->userMemorySize = size;
-        if (safeThreads) {
-            pthread_mutex_init(&ptr->refCounterMutex, NULL);
-        }
-    }
-    // increment the memory id safely.
-    if (safeThreads) {
-        pthread_mutex_lock(&memBlockListMutex);
-    }
-    *(psMemId* ) & ptr->id = ++memid;
-    if (safeThreads) {
-        pthread_mutex_unlock(&memBlockListMutex);
-    }
-    ptr->file = file;
-    ptr->freeFunc = NULL;
-    ptr->persistent = memory_is_persistent;
-    *(psU32 *)&ptr->lineno = lineno;
-    *(psPtr *)((int8_t *) (ptr + 1) + size) = P_PS_MEMMAGIC;
-    ptr->previousBlock = NULL;
-
-    ptr->refCounter = 1;                   // one user so far
+                unsigned int lineno,
+                const char *func)
+{
+
+    psMemBlock *memBlock = malloc(sizeof(psMemBlock) + size + sizeof(psPtr));
+    if (memBlock == NULL) {
+        MUTEX_LOCK(&memBlockListMutex);
+        memBlock = memExhaustedCallback(size);
+        MUTEX_UNLOCK(&memBlockListMutex);
+        if (memBlock == NULL) {
+            PS_MEM_ABORT(__func__, "Failed to allocate %zd bytes at %s (%s:%d)", size, func, file, lineno);
+        }
+    }
+
+    // posts
+    *(psU32 *)&memBlock->startblock = P_PS_MEMMAGIC;
+    *(psU32 *)&memBlock->endblock   = P_PS_MEMMAGIC;
+    *(psU32 *)((char *) (memBlock + 1) + size) = P_PS_MEMMAGIC;
+
+    // size of memory allocated
+    memBlock->userMemorySize = size;
+
+    // alloc request by:
+    // thread
+    *(pthread_t *)&memBlock->tid = pthread_self();
+    // file
+    memBlock->file = file;
+    // line number
+    *(unsigned int *)&memBlock->lineno = (unsigned int)lineno;
+    // function
+    memBlock->func = func;
+
+    #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)
+    #define BACKTRACE_BUFFER_SIZE 32
+    // psMemBlock.func is a 'const char *', so basically we're going to abuse
+    // that and treat it as a void ** to carry around backtrace information.
+    // psMemBlock is not ifdef'd to make sure that psMemBlock is always the
+    // same size & layout reguardless of the pslib .so that's being linked
+    // against
+    void **bt = malloc(BACKTRACE_BUFFER_SIZE * sizeof(void *));
+    if (bt == NULL) {
+        PS_MEM_ABORT(__func__, "Failed to allocate memmory for backtrace buffer: %zd bytes at %s (%s:%d)", 32 * sizeof(void *), func, file, lineno);
+    }
+    *(size_t *)&memBlock->backtraceSize = backtrace(bt, BACKTRACE_BUFFER_SIZE);
+    *(void ***)&memBlock->backtrace = bt;
+    #endif // ifdef HAVE_BACKTRACE
+
+    // free function
+    memBlock->freeFunc = NULL;
+
+    // persistent memory flag
+    memBlock->persistent = memory_is_persistent;
+
+    // this block will be add as the last mem block in the list
+    memBlock->previousBlock = NULL;
+
+    // ref count
+    memBlock->refCounter = 1;                   // one user so far
 
     // need exclusive access of the memory block list now...
-    if (safeThreads) {
-        pthread_mutex_lock(&memBlockListMutex);
-    }
+    MUTEX_LOCK(&memBlockListMutex);
+
+    // increment the memory id only after we've grabbed the memBlockListMutex
+    *(psMemId* )&memBlock->id = ++memid;
 
     // insert the new block to the front of the memBlock linked-list
-    ptr->nextBlock = lastMemBlockAllocated;
-    if (ptr->nextBlock != NULL) {
-        ptr->nextBlock->previousBlock = ptr;
-    }
-    lastMemBlockAllocated = ptr;
-
-    if (safeThreads) {
-        pthread_mutex_unlock(&memBlockListMutex);
-    }
+    memBlock->nextBlock = lastMemBlockAllocated;
+    if (memBlock->nextBlock != NULL) {
+        memBlock->nextBlock->previousBlock = memBlock;
+    }
+    lastMemBlockAllocated = memBlock;
 
     // Did the user ask to be informed about this allocation?
-    if (ptr->id == p_psMemAllocID) {
-        p_psMemAllocID += memAllocCallback(ptr);
-    }
+    if (memBlock->id == p_psMemAllocID) {
+        // p_psMemAllocID can only be changed while the memBlockList mutex is
+        // held
+        p_psMemAllocID += memAllocCallback(memBlock);
+    }
+
+    MUTEX_UNLOCK(&memBlockListMutex);
+
     // And return the user the memory that they allocated
-    return ptr + 1;                        // user memory
-}
-
-psPtr p_psRealloc(psPtr vptr,
+    return memBlock + 1;                        // user memory
+}
+
+psPtr p_psRealloc(psPtr ptr,
                   size_t size,
                   const char *file,
-                  unsigned int lineno)
-{
-    if (vptr == NULL) {
-        return p_psAlloc(size, file, lineno);
-    }
-
-    psMemBlock *ptr = ((psMemBlock*)vptr) - 1;
-
-    if (checkMemBlock(ptr, __func__) != 0) {
-        memProblemCallback(ptr, file, lineno);
-        psAbort(file, "Realloc detected a memory corruption (id %lu @ %s:%d).",
-                (unsigned long)ptr->id, ptr->file, ptr->lineno);
-    }
-
-    #ifdef PS_MEM_USE_RECYCLE
-    // Ensure the size matches that of the recycle bin
-    int bin = getRecycleBin(size);
-    if (bin < N_RECYCLE_BINS) {
-        size = recycleBinSize[bin];     // round-up size to next sized bin.
-    }
-    #endif // #ifdef PS_MEM_USE_RECYCLE
-
-    if (size == ptr->userMemorySize) {
+                  unsigned int lineno,
+                  const char *func)
+{
+    if (ptr == NULL) {
+        return p_psAlloc(size, file, lineno, func);
+    }
+
+    psMemBlock *memBlock = ((psMemBlock *)ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    if (size == memBlock->userMemorySize) {
         // Nothing to do
-        return vptr;
+        return ptr;
     }
 
     // Reallocate the memory
 
-    if (safeThreads) {
-        pthread_mutex_lock(&memBlockListMutex);
-    }
-
-    bool isBlockLast = (ptr == lastMemBlockAllocated); // Is this the last block we allocated?
-    ptr = (psMemBlock *)realloc(ptr, sizeof(psMemBlock) + size + sizeof(psPtr));
-    if (ptr == NULL) {
-        ptr = memExhaustedCallback(size);
-        if (ptr == NULL) {
-            psAbort(__func__, "Failed to reallocate %zd bytes at %s:%d", size, file, lineno);
-        }
-    }
-
-    ptr->userMemorySize = size;
-    *(psPtr *)((int8_t *) (ptr + 1) + size) = P_PS_MEMMAGIC;
-
+    // Is this the last block we allocated?  If it is, we need to keep track of
+    // this fact and update lastMemBlockAllocated *after* the realloc or
+    // lastMemBlockAllocated will be left with a bogus value
+    bool isBlockLast = (memBlock == lastMemBlockAllocated);
+
+    memBlock = (psMemBlock *)realloc(memBlock, sizeof(psMemBlock) + size + sizeof(psPtr));
+    if (memBlock== NULL) {
+        MUTEX_LOCK(&memBlockListMutex);
+        memBlock = memExhaustedCallback(size);
+        if (memBlock == NULL) {
+            MUTEX_UNLOCK(&memBlockListMutex);
+            psMemBlockPrint(stderr,  ((psMemBlock *)ptr) - 1);
+            fprintf(stderr, "Problem reallocating block\n");
+            PS_MEM_ABORT(__func__, "Failed to reallocate to %zd bytes at %s (%s:%d)", size, func, file, lineno);
+        }
+    }
+
+    // realloc() successed so need to update lastMemBlockAllocated if we just
+    // mucked with the last mem block
     if (isBlockLast) {
-        lastMemBlockAllocated = ptr;
+        lastMemBlockAllocated = memBlock;
+    }
+
+    memBlock->userMemorySize = size;
+    *(psU32 *)((char *)(memBlock + 1) + size) = P_PS_MEMMAGIC;
+
+    MUTEX_LOCK(&memBlockListMutex);
+
+    // Is this the last block we allocated?
+    if (memBlock== lastMemBlockAllocated) {
+        lastMemBlockAllocated = memBlock;
     }
 
     // the block location may have changed, so fix the linked list addresses.
-    if (ptr->nextBlock != NULL) {
-        ptr->nextBlock->previousBlock = ptr;
-    }
-    if (ptr->previousBlock != NULL) {
-        ptr->previousBlock->nextBlock = ptr;
-    }
-
-    if (safeThreads) {
-        pthread_mutex_unlock(&memBlockListMutex);
+    if (memBlock->nextBlock != NULL) {
+        memBlock->nextBlock->previousBlock = memBlock;
+    }
+    if (memBlock->previousBlock != NULL) {
+        memBlock->previousBlock->nextBlock = memBlock;
     }
 
     // Did the user ask to be informed about this allocation?
-    if (ptr->id == p_psMemAllocID) {
-        p_psMemAllocID += memAllocCallback(ptr);
-    }
-
-    return ptr + 1;                    // usr memory
-}
-
-void p_psFree(psPtr vptr,
-              const char *filename,
-              unsigned int lineno)
-{
-    if (vptr == NULL) {
-        return;
-    }
-    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
-    if (ptr->refCounter < 1) {
-        psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
-
-        psAbort(__func__,_("Block %lu, allocated at %s:%d, freed multiple times at %s:%d."),
-                (unsigned long)ptr->id, ptr->file, ptr->lineno, filename, lineno);
-    }
-
-    if (checkMemBlock(ptr, __func__) != 0) {
-        memProblemCallback(ptr, filename, lineno);
-        psAbort(__func__,"Memory Corruption Detected.");
-    }
-
-    (void)p_psMemDecrRefCounter(vptr, filename, lineno);    // this handles the free, if required.
+    if (memBlock->id == p_psMemAllocID) {
+        p_psMemAllocID += memAllocCallback(memBlock);
+    }
+
+    MUTEX_UNLOCK(&memBlockListMutex);
+
+    return memBlock + 1;                    // usr memory
 }
 
@@ -619,14 +568,17 @@
     psS32 nleak = 0;
     psS32 j = 0;
-    psMemBlock* topBlock = lastMemBlockAllocated;
-
-    if (safeThreads) {
-        pthread_mutex_lock(&memBlockListMutex);
-    }
-
-    for (psMemBlock* iter = topBlock; iter != NULL; iter = iter->nextBlock) {
-        if ( (iter->refCounter > 0) &&
-                ( (persistence) || (!persistence && !iter->persistent) ) &&
-                (iter->id >= id0)) {
+    psMemBlock *topBlock = lastMemBlockAllocated;
+
+    MUTEX_LOCK(&memBlockListMutex);
+
+    // find the very first memblock
+    psMemBlock *memBlock = NULL;
+    for (memBlock = topBlock; memBlock->nextBlock != NULL; memBlock = memBlock->nextBlock) { }
+
+    // iterate through the block list starting with the oldest block
+    for (; memBlock != NULL; memBlock = memBlock->previousBlock) {
+        if ( (memBlock->refCounter > 0) &&
+                ( (persistence) || (!persistence && !memBlock->persistent) ) &&
+                (memBlock->id >= id0)) {
 
             nleak++;
@@ -634,15 +586,50 @@
             if (fd != NULL) {
                 if (nleak == 1) {
-                    fprintf(fd, "   %20s:line ID\n", "file");
+                    fprintf(fd, "# func at (file:line)  ID: X\n");
                 }
 
-                fprintf(fd, "   %20s:%-4d %lu\n", iter->file, (int)iter->lineno, (unsigned long)iter->id);
+                fprintf(fd, "%s at (%s:%d)  ID: %lu", memBlock->func, memBlock->file, (int)memBlock->lineno, (unsigned long)memBlock->id);
+                #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)
+
+                size_t size = memBlock->backtraceSize;
+                char **strings = backtrace_symbols((void *const *)memBlock->backtrace, size);
+
+                fprintf(fd, "  Alloc Call Depth: %zd\n", size);
+
+                for (int i = 0; i < size; i++) {
+                    // always ident
+                    int ident = 4;  // initial indent
+                    ident += 2 * i; // nesting depth
+                    fprintf(fd, "%*s", ident, "");
+
+                    // if the caller was an anon function then strchr won't
+                    // find a '(' in the string and will return NULL
+                    char *caller = caller = strchr(strings[i], '(');
+                    if (caller) {
+                        // skip over the '('
+                        caller++;
+                        // find the end of the symbol name
+                        size_t callerLength = abs(strchr(caller, '+') - caller);
+                        // print just the symbol name
+                        for (int i = 0; i < callerLength; i++) {
+                            fputc(caller[i],fd);
+                        }
+                        fprintf(fd, "\n");
+                    } else {
+                        fprintf(fd, "(unknown)\n");
+                    }
+                }
+
+                free (strings);
+                #else // ifdef HAVE_BACKTRACE
+                // \n after "Memory Block ID"
+                fprintf(fd, "\n");
+                #endif // ifdef HAVE_BACKTRACE
+
             }
         }
     }
 
-    if (safeThreads) {
-        pthread_mutex_unlock(&memBlockListMutex);
-    }
+    MUTEX_UNLOCK(&memBlockListMutex);
 
     if (nleak == 0 || array == NULL) {
@@ -650,15 +637,14 @@
     }
 
-    *array = p_psAlloc(nleak * sizeof(psMemBlock), __FILE__, __LINE__);
-    if (safeThreads) {
-        pthread_mutex_lock(&memBlockListMutex);
-    }
-
-    for (psMemBlock* iter = topBlock; iter != NULL; iter = iter->nextBlock) {
-        if ( (iter->refCounter > 0) &&
-                ( (persistence) || (!persistence && !iter->persistent) ) &&
-                (iter->id >= id0)) {
-
-            (*array)[j++] = iter;
+    *array = psAlloc(nleak * sizeof(psMemBlock));
+
+    MUTEX_LOCK(&memBlockListMutex);
+
+    for (psMemBlock *memBlock = topBlock; memBlock != NULL; memBlock = memBlock ->nextBlock) {
+        if ( (memBlock->refCounter > 0) &&
+                ( (persistence) || (!persistence && !memBlock->persistent) ) &&
+                (memBlock->id >= id0)) {
+
+            (*array)[j++] = memBlock;
             if (j == nleak) {              // found them all
                 break;
@@ -667,7 +653,5 @@
     }
 
-    if (safeThreads) {
-        pthread_mutex_unlock(&memBlockListMutex);
-    }
+    MUTEX_UNLOCK(&memBlockListMutex);
 
     return nleak;
@@ -679,63 +663,47 @@
 
 // return refCounter
-psReferenceCount psMemGetRefCounter(const psPtr ptr)
-{
-    psMemBlock* ptr2;
-    psU32 refCount;
-
+psReferenceCount p_psMemGetRefCounter(const psPtr ptr,
+                                      const char *file,
+                                      unsigned int lineno,
+                                      const char *func)
+{
     if (ptr == NULL) {
         return 0;
     }
 
-    ptr2 = ((psMemBlock* ) ptr) - 1;
-
-    if (checkMemBlock(ptr2, __func__) != 0) {
-        memProblemCallback(ptr2, __func__, __LINE__);
-    }
-
-    if (safeThreads) {
-        pthread_mutex_lock(&ptr2->refCounterMutex);
-    }
-    refCount = ptr2->refCounter;
-    if (safeThreads) {
-        pthread_mutex_unlock(&ptr2->refCounterMutex);
-    }
-
-    return refCount;
+    psMemBlock *memBlock = ((psMemBlock *) ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    return memBlock->refCounter;
 }
 
 // increment and return refCounter
-psPtr p_psMemIncrRefCounter(const psPtr vptr,
+psPtr p_psMemIncrRefCounter(const psPtr ptr,
                             const char *file,
-                            psS32 lineno)
-{
-    psMemBlock* ptr;
-
-    if (vptr == NULL) {
-        return vptr;
-    }
-
-    ptr = ((psMemBlock* ) vptr) - 1;
-
-    if (checkMemBlock(ptr, __func__)) {
-        memProblemCallback(ptr, file, lineno);
-    }
-
-    if (safeThreads) {
-        pthread_mutex_lock(&ptr->refCounterMutex);
-    }
-    ptr->refCounter++;
-    if (safeThreads) {
-        pthread_mutex_unlock(&ptr->refCounterMutex);
-    }
+                            unsigned int lineno,
+                            const char *func)
+{
+    if (ptr == NULL) {
+        return ptr;
+    }
+
+    psMemBlock* memBlock = ((psMemBlock *) ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    memBlock->refCounter++;
 
     // Did the user ask to be informed about this allocation?
-    if (ptr->id == p_psMemAllocID) {
-        p_psMemAllocID += memAllocCallback(ptr);
-    }
-
-    return vptr;
-}
-
+    MUTEX_LOCK(&memBlockListMutex);
+    if (memBlock->id == p_psMemAllocID) {
+        p_psMemAllocID += memAllocCallback(memBlock);
+    }
+    MUTEX_UNLOCK(&memBlockListMutex);
+
+    return ptr;
+}
+
+#if 0
 psPtr p_psMemSetRefCounter(psPtr vptr,
                            psReferenceCount count,
@@ -755,15 +723,10 @@
     ptr = ((psMemBlock* ) vptr) - 1;
 
-    if (checkMemBlock(ptr, __func__)) {
+    if (isBadMemBlock(ptr, __func__)) {
+        (void)p_psMemDecrRefCounter(vptr, filename, lineno);
         memProblemCallback(ptr, file, lineno);
     }
 
-    if (safeThreads) {
-        pthread_mutex_lock(&ptr->refCounterMutex);
-    }
     ptr->refCounter = count;
-    if (safeThreads) {
-        pthread_mutex_unlock(&ptr->refCounterMutex);
-    }
 
     if (count < 1) {
@@ -773,100 +736,79 @@
     return vptr;
 }
+#endif
 
 // decrement and return refCounter
-psPtr p_psMemDecrRefCounter(psPtr vptr,
+psPtr p_psMemDecrRefCounter(psPtr ptr,
                             const char *file,
-                            psS32 lineno)
-{
-    if (vptr == NULL) {
+                            unsigned int lineno,
+                            const char *func)
+{
+    if (ptr == NULL) {
         return NULL;
     }
 
-    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
-
-    if (checkMemBlock(ptr, __func__) != 0) {
-        memProblemCallback(ptr, file, lineno);
-        return NULL;
-    }
+    psMemBlock *memBlock = ((psMemBlock *) ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    // if we have multiple references, just decrement the count and return.
+    if (memBlock->refCounter > 1) {
+        memBlock->refCounter--;
+
+        // Did the user ask to be informed about this deallocation?
+        MUTEX_LOCK(&memBlockListMutex);
+        if (memBlock->id == p_psMemFreeID) {
+            p_psMemFreeID += memFreeCallback(memBlock);
+        }
+        MUTEX_UNLOCK(&memBlockListMutex);
+
+        return ptr;
+    }
+
+    // we can't invoke freeFunc() while we're holding memBlockListMutex as it
+    // may invoke psFree() itself
+    if (memBlock->freeFunc != NULL) {
+        memBlock->freeFunc(ptr);
+    }
+
+    MUTEX_LOCK(&memBlockListMutex);
 
     // Did the user ask to be informed about this deallocation?
-    if (ptr->id == p_psMemFreeID) {
+    if (memBlock->id == p_psMemFreeID) {
         p_psMemFreeID += memFreeCallback(ptr);
     }
 
-    if (safeThreads) {
-        pthread_mutex_lock(&ptr->refCounterMutex);
-    }
-
-    if (ptr->refCounter > 1) {
-        ptr->refCounter--;                 // multiple references, just decrement the count.
-        if (safeThreads) {
-            pthread_mutex_unlock(&ptr->refCounterMutex);
-        }
-
-    } else {
-        if (safeThreads) {
-            pthread_mutex_unlock(&ptr->refCounterMutex);
-        }
-
-        if (ptr->freeFunc != NULL) {
-            ptr->freeFunc(vptr);
-        }
-
-        if (safeThreads) {
-            pthread_mutex_lock(&memBlockListMutex);
-        }
-
-        // cut the memBlock out of the memBlock list
-        if (ptr->nextBlock != NULL) {
-            ptr->nextBlock->previousBlock = ptr->previousBlock;
-        }
-        if (ptr->previousBlock != NULL) {
-            ptr->previousBlock->nextBlock = ptr->nextBlock;
-        }
-        if (lastMemBlockAllocated == ptr) {
-            lastMemBlockAllocated = ptr->nextBlock;
-        }
-
-        if (safeThreads) {
-            pthread_mutex_unlock(&memBlockListMutex);
-        }
-
-        #ifdef PS_MEM_USE_RECYCLE
-        // do we recycle?
-        int bin = getRecycleBin(ptr->userMemorySize);
-        if (bin < N_RECYCLE_BINS && recycleBinNums[bin] < MAX_RECYCLE) {
-            ptr->refCounter = 0;
-            recyclePush(ptr, bin);
-        } else
-            #endif  // #ifdef PS_MEM_USE_RECYCLE
-            {
-                // memory is larger than I want to recycle.
-                #ifdef PS_MEM_DEBUG
-                (void)p_psRealloc(vptr, 0, file, lineno);
-                ptr->previousBlock = NULL;
-                ptr->nextBlock = deadBlockList;
-                if (deadBlockList != NULL) {
-                deadBlockList->previous = ptr;
-            }
-        deadBlockList = ptr;
-        #else // #ifdef PS_MEM_DEBUG
-
-        if (safeThreads) {
-            pthread_mutex_destroy(&ptr->refCounterMutex);
-            }
-            free(ptr);
-            #endif // #else - #ifdef PS_MEM_DEBUG
-
-        }
-
-        vptr = NULL;                       // since we freed it, make sure we return NULL.
-    }
-
-    return vptr;
-}
-
-void psMemSetDeallocator(psPtr ptr,
-                         psFreeFunc freeFunc)
+    // cut the memBlock out of the memBlock list
+    if (memBlock->nextBlock != NULL) {
+        memBlock->nextBlock->previousBlock = memBlock->previousBlock;
+    }
+    if (memBlock->previousBlock != NULL) {
+        memBlock->previousBlock->nextBlock = memBlock->nextBlock;
+    }
+    if (lastMemBlockAllocated == memBlock) {
+        lastMemBlockAllocated = memBlock->nextBlock;
+    }
+
+    MUTEX_UNLOCK(&memBlockListMutex);
+
+    // invoke free only after we've released the block list lock as free()
+    // could take awhile.  We can get away with this as at this point the
+    // memBlock is no longer part of the mem block list.
+    #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)
+
+    free(memBlock->backtrace);
+    #endif
+
+    free(memBlock);
+
+    // since we freed it, make sure we return NULL.
+    return NULL;
+}
+
+void p_psMemSetDeallocator(psPtr ptr,
+                           psFreeFunc freeFunc,
+                           const char *file,
+                           unsigned int lineno,
+                           const char *func)
 {
     if (ptr == NULL) {
@@ -874,15 +816,15 @@
     }
 
-    psMemBlock* PTR = ((psMemBlock* ) ptr) - 1;
-
-    if (checkMemBlock(PTR, __func__) != 0) {
-        memProblemCallback(PTR, __func__, __LINE__);
-    }
-
-    PTR->freeFunc = freeFunc;
-
-}
-
-psFreeFunc psMemGetDeallocator(const psPtr ptr)
+    psMemBlock* memBlock = ((psMemBlock *)ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    memBlock->freeFunc = freeFunc;
+}
+
+psFreeFunc p_psMemGetDeallocator(const psPtr ptr,
+                                 const char *file,
+                                 unsigned int lineno,
+                                 const char *func)
 {
     if (ptr == NULL) {
@@ -890,323 +832,65 @@
     }
 
-    psMemBlock* PTR = ((psMemBlock* ) ptr) - 1;
-
-    if (checkMemBlock(PTR, __func__) != 0) {
-        memProblemCallback(PTR, __func__, __LINE__);
-    }
-
-    return PTR->freeFunc;
-}
-
-bool psMemCheckType(psDataType type,
-                    psPtr ptr)
-{
-    PS_ASSERT_PTR(ptr, false);
-
-    switch(type) {
-    case PS_DATA_ARRAY:
-        if ( psMemCheckArray(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_BITSET:
-        if ( psMemCheckBitSet(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_CUBE:
-        if ( psMemCheckCube(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_FITS:
-        if ( psMemCheckFits(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_HASH:
-        if ( psMemCheckHash(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_HISTOGRAM:
-        if ( psMemCheckHistogram(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_IMAGE:
-        if ( psMemCheckImage(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_KERNEL:
-        if ( psMemCheckKernel(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_LINE:
-        if ( psMemCheckLine(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_LIST:
-        if ( psMemCheckList(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_LOOKUPTABLE:
-        if ( psMemCheckLookupTable(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_METADATA:
-        if ( psMemCheckMetadata(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_METADATAITEM:
-        if ( psMemCheckMetadataItem(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_MINIMIZATION:
-        if ( psMemCheckMinimization(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_PIXELS:
-        if ( psMemCheckPixels(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_PLANE:
-        if ( psMemCheckPlane(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_PLANEDISTORT:
-        if ( psMemCheckPlaneDistort(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_PLANETRANSFORM:
-        if ( psMemCheckPlaneTransform(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_POLYNOMIAL1D:
-        if ( psMemCheckPolynomial1D(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_POLYNOMIAL2D:
-        if ( psMemCheckPolynomial2D(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_POLYNOMIAL3D:
-        if ( psMemCheckPolynomial3D(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_POLYNOMIAL4D:
-        if ( psMemCheckPolynomial4D(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_PROJECTION:
-        if ( psMemCheckProjection(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_REGION:
-        if ( psMemCheckRegion(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_SCALAR:
-        if ( psMemCheckScalar(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_SPHERE:
-        if ( psMemCheckSphere(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_SPHEREROT:
-        if ( psMemCheckSphereRot(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_SPLINE1D:
-        if ( psMemCheckSpline1D(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_STATS:
-        if ( psMemCheckStats(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_STRING:
-        if ( psMemCheckString(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_TIME:
-        if ( psMemCheckTime(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    case PS_DATA_VECTOR:
-        if ( psMemCheckVector(ptr) )
-            return true;
-        else {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Incorrect pointer.  Datatypes do not match.\n");
-            break;
-        }
-    default:
-        psError(PS_ERR_BAD_PARAMETER_TYPE, true,
-                "Invalid datatype specified.\n");
-    }
-    return false;
+    psMemBlock* memBlock = ((psMemBlock *)ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    return memBlock->freeFunc;
 }
 
 bool psMemSetThreadSafety(bool safe)
 {
-    bool out = safeThreads;
+    MUTEX_LOCK(&memBlockListMutex);
+
+    bool oldState = safeThreads;
     safeThreads = safe;
-    return out;
+
+    MUTEX_UNLOCK(&memBlockListMutex);
+
+    return oldState;
 }
 
 bool psMemGetThreadSafety(void)
 {
-    return safeThreads;
-}
-
-bool p_psMemGetPersistent(psPtr vptr)
-{
-    if (vptr == NULL) {
+    MUTEX_LOCK(&memBlockListMutex);
+
+    bool oldState = safeThreads;
+
+    MUTEX_UNLOCK(&memBlockListMutex);
+
+    return oldState;
+}
+
+bool p_psMemGetPersistent(psPtr ptr,
+                          const char *file,
+                          unsigned int lineno,
+                          const char *func)
+{
+    if (ptr == NULL) {
         return NULL;
     }
 
-    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
-
-    if (checkMemBlock(ptr, __func__) != 0) {
-        memProblemCallback(ptr, __func__, __LINE__);
-    }
-
-    return ptr->persistent;
-}
-
-void p_psMemSetPersistent(psPtr vptr,
-                          bool value)
-{
-    if (vptr == NULL) {
+    psMemBlock* memBlock = ((psMemBlock *) ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    return memBlock->persistent;
+}
+
+void p_psMemSetPersistent(psPtr ptr,
+                          bool value,
+                          const char *file,
+                          unsigned int lineno,
+                          const char *func)
+{
+    if (ptr == NULL) {
         return;
     }
 
-    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
-
-    if (checkMemBlock(ptr, __func__) != 0) {
-        memProblemCallback(ptr, __func__, __LINE__);
-    }
-
-    ptr->persistent = value;
+    psMemBlock* memBlock = ((psMemBlock *) ptr) - 1;
+
+    HANDLE_BAD_BLOCK(memBlock, file, lineno, func);
+
+    memBlock->persistent = value;
 }
 
@@ -1221,6 +905,5 @@
 size_t psMemStats(const bool print, // print details as they're found?
                   size_t *allocated, // memory that's currently allocated (but not persistent)
-                  size_t *persistent, // persistent memory that's currently allocated
-                  size_t *freelist) // memory that's waiting to be recycled
+                  size_t *persistent) // persistent memory that's currently allocated
 {
     const size_t overhead = sizeof(psMemBlock) + sizeof(psPtr); // overhead on each allocation
@@ -1230,7 +913,5 @@
     }
 
-    if (safeThreads) {
-        pthread_mutex_lock(&memBlockListMutex);
-    }
+    MUTEX_LOCK(&memBlockListMutex);
     /*
      * All memory that's currently allocated, whether persistent or not
@@ -1264,41 +945,26 @@
         printf("Persistent %6s  %10zd %8zd\n", "", persist, npersist);
     }
-    /*
-     * Count the memory on the free list
-     */
-    size_t freelist_s;
-    if (freelist == NULL) {
-        freelist = &freelist_s;
-    }
-
-    *freelist = 0;
-    int nblock_tot = 0;
-    #ifdef PS_MEM_USE_RECYCLE
-
-    for (int i = 0; recycleBinSize[i] < P_PS_LARGE_BLOCK_SIZE; i++) {
-        size_t bin_contents = 0;
-        size_t nblock = 0;
-        for (const psMemBlock *ptr = recycleMemBlockList[i]; ptr != NULL; ptr = ptr->nextBlock) {
-            nblock++;
-            bin_contents += ptr->userMemorySize + overhead;
-        }
-        *freelist += bin_contents;
-        nblock_tot += nblock;
-
-        if (print) {
-            printf("Freelist   %6d  %10d %8d\n", recycleBinSize[i], bin_contents, nblock);
-        }
-    }
-    #endif // #ifdef PS_MEM_USE_RECYCLE
-
-    if (print) {
-        printf("Freelist   %6s  %10zd %8d\n", "", *freelist, nblock_tot);
-    }
-
-
-    if (safeThreads) {
-        pthread_mutex_unlock(&memBlockListMutex);
-    }
-
-    return *freelist + *allocated + *persistent;
-}
+
+    MUTEX_UNLOCK(&memBlockListMutex);
+
+    return *allocated + *persistent;
+}
+
+int psMemBlockPrint(FILE *output, const psMemBlock *memBlock)
+{
+    return fprintf(output,
+                   "Memory Block ID: %lu @ %p\n"
+                   "\tPrevious Block: %p Next Block: %p\n"
+                   "\tFree function: %p\n"
+                   "\tSize: %zd Reference count: %lu Persistent: %s\n"
+                   "\tPosts: %x %x %x\n"
+                   "\tAllocated in %s at (%s:%d)\n"
+                   "\t\tby Thread ID %lu\n",
+                   memBlock->id, memBlock,
+                   memBlock->previousBlock, memBlock->nextBlock,
+                   memBlock->freeFunc,
+                   memBlock->userMemorySize, memBlock->refCounter, (memBlock->persistent ? "Yes" : "No"),
+                   memBlock->startblock, memBlock->endblock,
+                   *(psU32 *)((char *) (memBlock + 1) + memBlock->userMemorySize),
+                   memBlock->func, memBlock->file, memBlock->lineno, memBlock->tid);
+}
