Index: /trunk/psLib/src/sys/psMemory.c
===================================================================
--- /trunk/psLib/src/sys/psMemory.c	(revision 430)
+++ /trunk/psLib/src/sys/psMemory.c	(revision 430)
@@ -0,0 +1,441 @@
+/** @file  psMemory.c
+ *
+ *  @brief Contains the definitions for the memory management system
+ *
+ *  psMemory.h has additional information and documentation of the routines found in this file.
+ *
+ *  @author Robert DeSonia, MHPCC
+ *  @author Robert Lupton, Princeton University
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-04-15 21:22:09 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#define PS_ALLOW_MALLOC                 // we're allowed to call malloc()
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "psMemory.h"
+#include "psError.h"
+
+#define P_PS_MEMMAGIC (void *)0xdeadbeef // Magic number in psMemBlock header
+
+static int bad_memblock(const psMemBlock *m, int quiet);
+static int numMemBlock = 0;             // size of memBlocks
+static psMemBlock **memBlocks = NULL;
+
+/**
+ * Unique ID for allocated blocks
+ */
+static unsigned long memid = 0;
+
+/**
+ *  Default memExhausted callback.
+ */
+static void *memExhaustedCallbackDefault(size_t size)
+{
+    return NULL;
+}
+
+static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;
+
+psMemExhaustedCallback psMemExhaustedSetCallback(psMemExhaustedCallback func)
+{
+    psMemExhaustedCallback old = memExhaustedCallback;
+
+    if (func != NULL) {
+	    memExhaustedCallback = func;
+	} else {
+	    memExhaustedCallback = memExhaustedCallbackDefault;
+	}
+
+    return old;
+}
+
+static void memProblemCallbackDefault(const psMemBlock *ptr,
+                          const char *file, int lineno)
+{
+    if (bad_memblock(ptr, 0)) {
+        fprintf(stderr, "Memory corruption or an attempt to manipulate memory "
+                "not allocated with psAlloc at %s", file);
+        if (lineno > 0) {
+            fprintf(stderr, ":%d", lineno);
+        }
+        fprintf(stderr, "\n");
+    } else if (ptr->refCounter <= 0) {
+        psError(__func__, PS_ERR_BADFREE, PS_NEW_ERROR,
+                "Block %ld allocated at %s:%d freed more than once at %s:%d\n",
+                ptr->id, ptr->file, ptr->lineno, file, lineno);
+    } else if (ptr->refCounter > 1) {
+        psError(__func__,  PS_ERR_BADFREE, PS_NEW_ERROR,
+                "Block %ld allocated at %s:%d freed while still referenced at %s:%d\n",
+                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);
+    }
+}
+static psMemProblemCallback memProblemCallback = memProblemCallbackDefault;
+
+psMemProblemCallback psMemProblemSetCallback(psMemProblemCallback func)
+{
+    psMemProblemCallback old = memProblemCallback;
+
+    if (func != NULL) {
+	    memProblemCallback = func;
+	} else {
+	    memProblemCallback = memProblemCallbackDefault;
+	}
+
+    return old;
+}
+/*
+ * And now the I-want-to-be-informed callbacks
+ *
+ * Call the callbacks when these IDs are allocated/freed
+ */
+long p_psMemAllocateID = 0;  // notify user this block is allocated
+long p_psMemFreeID = 0;   // notify user this block is freed
+
+long psMemSetAllocateID(long id) // set p_psMemAllocateID to id
+{
+    long old = p_psMemAllocateID;
+    p_psMemAllocateID = id;
+
+    return old;
+}
+
+long psMemSetFreeID(long id)  // set p_psMemFreeID to id
+{
+    long old = p_psMemFreeID;
+    p_psMemFreeID = id;
+
+    return old;
+}
+
+/*
+ * Default callback for both allocate and free. Note that the
+ * value of p_psMemAllocateID/p_psMemFreeID is incremented
+ * by the return value (so returning 0 means that the callback
+ * isn't resignalled)
+ */
+static int memAllocateCallbackDefault(const psMemBlock *ptr)
+{
+    static int incr = 0;  // "p_psMemAllocateID += incr"
+
+    assert (ptr != NULL);  // prevent compiler warnings
+
+    return incr;
+}
+
+static int memFreeCallbackDefault(const psMemBlock *ptr)
+{
+    static int incr = 0;  // "p_psMemFreeID += incr"
+
+    assert (ptr != NULL);  // prevent compiler warnings
+
+    return incr;
+}
+
+/*
+ * The default callbacks, and the routines to change them
+ */
+static psMemCallback memAllocateCallback = memAllocateCallbackDefault;
+static psMemCallback memFreeCallback = memFreeCallbackDefault;
+
+psMemCallback psMemAllocateSetCallback(psMemCallback func)
+{
+    psMemCallback old = memAllocateCallback;
+
+    if (func != NULL) {
+	    memAllocateCallback =  func;
+	} else {
+	    memAllocateCallback = memAllocateCallbackDefault;
+	}
+
+    return old;
+}
+
+psMemCallback psMemFreeSetCallback(psMemCallback func)
+{
+    psMemCallback old = memFreeCallback;
+
+    if (func != NULL) {
+	    memFreeCallback = func;
+	} else {
+	    memFreeCallback = memFreeCallbackDefault;
+	}
+
+    return old;
+}
+
+/*****************************************************************************/
+/*
+ * Return memory ID counter for next block to be allocated
+ */
+int psMemGetId(void)
+{
+    return memid + 1;
+}
+
+/*****************************************************************************/
+/*
+ * Routines to check the consistency of the allocated and/or free memory arena
+ *
+ * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted
+ */
+#define ALIGNED(P) ((void *)((long)(P) & ~03) == (P))
+
+static int
+bad_memblock(const psMemBlock *m, // block to check
+             int quiet)   // be quiet?
+{
+    if (m == NULL) {
+        if (!quiet) {
+            psError(__func__,  PS_ERR_MEMORY_CORRUPTION, PS_NEW_ERROR,
+                    "psMemCheckCorruption: NULL memory block\n");
+        }
+        return(1);
+    }
+
+    if (!ALIGNED(m)) {
+        if (!quiet) {
+            psError(__func__,  PS_ERR_MEMORY_CORRUPTION, PS_NEW_ERROR,
+                    "psMemCheckCorruption: non-aligned memory block\n");
+        }
+        return(1);
+    }
+
+    if (m->magic0 != P_PS_MEMMAGIC || m->magic != P_PS_MEMMAGIC) {
+        if (!quiet) {
+            psError(__func__, PS_ERR_MEMORY_CORRUPTION, PS_NEW_ERROR,
+                    "psMemCheckCorruption: memory block %ld is corrupted\n", m->id);
+        }
+        return(1);
+    }
+
+    return(0);
+}
+
+int psMemCheckCorruption(int abort_on_error)
+{
+    int nbad = 0;   // number of bad blocks
+
+    if (memBlocks == NULL) {
+        return 0;   // no memory is allocated to be corrupted
+    }
+
+    for (int i = 1; i <= memid; i++) {
+        if (memBlocks[i] != NULL) {
+            if (bad_memblock(memBlocks[i], 1)) {
+                nbad++;
+
+                memProblemCallback(memBlocks[i], "(psMemCheckCorruption)", 0);
+
+                if (abort_on_error) {
+                    psAbort(__func__, "Detected memory corruption");
+                }
+            }
+        }
+    }
+
+    return nbad;
+}
+
+/*****************************************************************************/
+
+void *p_psAlloc(size_t size, const char *file, int lineno)
+{
+    psMemBlock *ptr = malloc(sizeof(psMemBlock) + size);
+
+    if (ptr == NULL) {
+        ptr = memExhaustedCallback(size);
+        if (ptr == NULL) {
+            psAbort(__func__, "Failed to allocate %ld bytes at %s:%d",
+                    size, file, lineno);
+        }
+    }
+
+    *(unsigned long *)&ptr->id = ++memid;
+    ptr->file = file;
+    *(int *)&ptr->lineno = lineno;
+    *(void **)&ptr->magic0 = *(void **)&ptr->magic = P_PS_MEMMAGIC;
+
+    ptr->refCounter = 1;  // one user so far
+    /*
+     * Did the user ask to be informed about this allocation?
+     */
+
+    if (ptr->id == p_psMemAllocateID && p_psMemAllocateID > 0) {
+        p_psMemAllocateID += memAllocateCallback(ptr);
+    }
+    if (memid >= nMemBlock) {
+        nMemBlock = (nMemBlock == 0) ? 100000 : 2*nMemBlock;
+        memBlocks = realloc(memBlocks, nMemBlock*sizeof(psMemBlock *)); // NOT psRealloc
+    }
+    memBlocks[ptr->id] = ptr;
+    /*
+     * And return the user the memory that they allocated
+     */
+    return ptr + 1;   // usr memory
+}
+
+void *p_psRealloc(void *vptr, size_t size, const char *file, int lineno)
+{
+    if (vptr == NULL) {
+        return p_psAlloc(size, file, lineno);
+    } else {
+        psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+        ptr = (psMemBlock *)realloc(ptr, sizeof(psMemBlock) + size);
+        memBlocks[ptr->id] = ptr;
+
+        return ptr + 1;   // usr memory
+    }
+}
+
+void p_psFree(void *vptr, const char *file, int lineno)
+{
+    if (vptr == NULL) {
+        return;
+    }
+
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+    /*
+     * Did the user ask to be informed about this deallocation?
+     */
+    if (ptr->id == p_psMemFreeID && p_psMemFreeID > 0) {
+        p_psMemFreeID += memFreeCallback(ptr);
+    }
+
+    if (bad_memblock(ptr, 0)) {
+        memProblemCallback(ptr, file, lineno); // we may not own this block; don't free it
+    } else {
+        if (ptr->refCounter != 1) {
+            memProblemCallback(ptr, file, lineno);
+        }
+        ptr->refCounter--;
+        #if 1
+
+        memBlocks[ptr->id] = NULL; // XXX sub-optimal! Can't check
+        // freed blocks for corruption/double frees
+        free(ptr);
+        #endif
+
+    }
+}
+
+/*****************************************************************************/
+/*
+ * Check for memory leaks. Not production quality code
+ */
+int psMemCheckLeaks(
+    int id0,    // don't list blocks with id < id0
+    psMemBlock ***arr,   // pointer to array of pointers to
+    // leaked blocks, or NULL
+    FILE *fd)    // print list of leaks to fd (or NULL)
+{
+    int nleak = 0;
+
+    if (memBlocks == NULL)
+    {  // nothing was allocated
+        return 0;
+    }
+
+    for (int i = id0; i <= memid; i++)
+    {
+        if (memBlocks[i] != NULL) {
+            if (memBlocks[i]->refCounter > 0) {
+                nleak++;
+
+                if (fd != NULL) {
+                    if (nleak == 1) {
+                        fprintf(fd, "   %20s:line ID\n", "file");
+                    }
+
+                    fprintf(fd, "   %20s:%-4d %ld\n",
+                            memBlocks[i]->file, memBlocks[i]->lineno,
+                            memBlocks[i]->id);
+                }
+            }
+        }
+    }
+
+    if (nleak == 0 || arr == NULL)
+    {
+        return nleak;
+    }
+
+    assert (*arr == NULL);  // Don't generate a memory leak!
+
+    *arr = p_psAlloc(nleak*sizeof(psMemBlock), __FILE__, __LINE__);
+    for (int i = id0, j = 0; i < memid; i++)
+    {
+        if (memBlocks[i] != NULL) {
+            if (memBlocks[i]->refCounter > 0) {
+                (*arr)[j++] = memBlocks[i];
+                if (j == nleak) { // found them all
+                    break;
+                }
+            }
+        }
+    }
+
+    return nleak;
+}
+
+/*****************************************************************************/
+/*
+ * Reference counting APIs
+ */
+int psMemGetRefCounter(void *vptr) // return refCounter
+{
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+
+    if (bad_memblock(ptr, 0))
+    {
+        memProblemCallback(ptr, "(psMemGetRefCounter)", -1);
+    }
+
+    return ptr->refCounter;
+}
+
+void *psMemIncrRefCounter(void *vptr) // increment and return refCounter
+{
+    if (vptr == NULL)
+    {
+        return vptr;
+    }
+
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+
+    if (bad_memblock(ptr, 0))
+    {
+        memProblemCallback(ptr, "(psMemIncrRefCounter)", -1);
+    }
+
+    ptr->refCounter++;
+
+    return vptr;
+}
+
+void *psMemDecrRefCounter(void *vptr) // decrement and return refCounter
+{
+    if (vptr == NULL)
+    {
+        return vptr;
+    }
+
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+
+    if (bad_memblock(ptr, 0))
+    {
+        memProblemCallback(ptr, "(psMemDecrRefCounter)", -1);
+    }
+
+    ptr->refCounter--;
+
+    return vptr;
+}
Index: /trunk/psLib/src/sys/psMemory.h
===================================================================
--- /trunk/psLib/src/sys/psMemory.h	(revision 430)
+++ /trunk/psLib/src/sys/psMemory.h	(revision 430)
@@ -0,0 +1,151 @@
+#if !defined(PS_MEMORY_H)
+#define PS_MEMORY_H
+
+#include <stdio.h>    // needed for FILE
+/** @file  psMemory.h
+ *
+ *  @brief Contains the definitions for the memory management system
+ *
+ *  This is the generic memory management system put inbetween the user's high level code and the OS-level
+ *  memory allocation routines.  This system adds such features as callback routines for memory error events,
+ *  tracing capabilities, and reference counting.
+ *
+ *  @author Robert DeSonia, MHPCC
+ *  @author Robert Lupton, Princeton University
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-04-15 21:22:09 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+/** Book-keeping data for storage allocator.
+ *  N.b. sizeof(psMemBlock) must be chosen such that if ptr is a pointer
+ *  returned by malloc, then ((char *)ptr + sizeof(psMemBlock)) is properly
+ *  aligned for all storage types.
+ */
+typedef struct
+{
+    const void *startblock;             ///< initialised to p_psMEMMAGIC
+    const unsigned long id;             ///< a unique ID for this allocation
+    const char *file;                   ///< set from __FILE__ in e.g. p_psAlloc
+    const int lineno;                   ///< set from __LINE__ in e.g. p_psAlloc
+    int refCounter;                     ///< how many times pointer is referenced
+    const void **endpost;               ///< initialised to p_psMEMMAGIC
+    const void *endblock;               ///< initialised to p_psMEMMAGIC
+}
+psMemBlock;
+
+/// prototype of a basic callback used by memory functions
+typedef long (*psMemAllocateCallback)(const psMemBlock *ptr);
+
+/// prototype of memory free callback used by memory functions
+typedef long (*psMemFreeCallback)(const psMemBlock *ptr);
+
+/// prototype of a callback used in error conditions
+typedef void (*psMemProblemCallback)(const psMemBlock *ptr, const char *file, int lineno);
+
+/// prototype of a callback used when memory runs out
+typedef void *(*psMemExhaustedCallback)(size_t size);
+
+/** Private Functions **************************************************************/
+/** \addtogroup sysUtils memory private
+ *  \{
+ */
+
+/// Memory allocation. Underlying private function called by macro psAlloc.
+void *p_psAlloc(size_t size,  ///< Size required
+                const char *file, ///< File of call
+                int lineno)  ///< Line number of call
+;
+
+/// Memory re-allocation.  Underlying private function called by macro psRealloc.
+void *p_psRealloc(void *ptr,  ///< Pointer to re-allocate
+                  size_t size,  ///< Size required
+                  const char *file, ///< File of call
+                  int lineno)  ///< Line number of call
+;
+
+/// Free memory.  Underlying private function called by macro psFree.
+void p_psFree(void *ptr,  ///< Pointer to free
+              const char *file,  ///< File of call
+              int lineno)  ///< Line number of call
+;
+/** Public Functions **************************************************************/
+/** \}
+ *  \addtogroup sysUtils memory psLibAPI
+ *  \{
+ */
+
+/// Check for memory leaks
+int psMemCheckLeaks(int id0,  ///< don't list blocks with id < id0
+                    psMemBlock ***arr, ///< pointer to array of pointers to leaked blocks, or NULL
+                    FILE *fd)  ///< print list of leaks to fd (or NULL)
+;
+
+/// Check for memory corruption
+int psMemCheckCorruption(int abort_on_error) ///< Abort on detecting corruption?
+;
+
+/// Return reference counter
+int psMemGetRefCounter(void *vptr) ///< Pointer to get refCounter for
+;
+
+/// Increment reference counter and return the pointer
+void *psMemIncrRefCounter(void *vptr) ///< Pointer to increment refCounter, and return
+;
+
+/// Decrement reference counter and return the pointer
+void *psMemDecrRefCounter(void *vptr) ///< Pointer to decrement refCounter, and return
+;
+
+/// Set callback for problems
+psMemProblemCallback psMemProblemCallbackSet(psMemProblemCallback func) ///< Function to run
+;
+
+/// Set callback for out-of-memory
+psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func) ///< Function to run
+;
+
+/// Set call back for when a particular memory block is allocated
+psMemCallback psMemAllocateCallbackSet(psMemAllocateCallback func) ///< Function to run
+;
+
+/// Set call back for when a particular memory block is freed
+psMemCallback psMemFreeCallbackSet(psMemFreeCallback func) ///< Function to run
+;
+
+/// get next memory ID
+int psMemGetId(void)
+;
+
+/// set p_psMemAllocateID to id
+long psMemAllocateIDSet(long id) ///< ID to set
+;
+
+/// set p_psMemFreeID to id
+long psMemFreeIDSet(long id)  ///< ID to set
+;
+
+//@} End of public Functions
+
+/// Memory allocation. psAlloc sends file and line number to p_psAlloc.
+#define psAlloc(size) p_psAlloc(size, __FILE__, __LINE__)
+
+/// Memory re-allocation.  psRealloc sends file and line number to p_psRealloc.
+#define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__)
+
+/// Free memory.  psFree sends file and line number to p_psFree.
+#define psFree(size) p_psFree(size, __FILE__, __LINE__)
+
+/*
+ * Ensure that any program using malloc/realloc/free will fail to compile
+ */
+#ifndef PS_ALLOW_MALLOC
+    #define malloc(S)       #pragma error Use of malloc is not allowed.  Use psAlloc instead.
+    #define realloc(P,S)    #pragma error Use of realloc is not allowed.  Use psRealloc instead.
+    #define calloc(S)       #pragma error Use of calloc is not allowed.  Use psAlloc instead.
+    #define free(P)         #pragma error Use of free is not allowed.  Use psFree instead.
+#endif
+
+#endif // end of header file
Index: /trunk/psLib/src/sysUtils/psMemory.c
===================================================================
--- /trunk/psLib/src/sysUtils/psMemory.c	(revision 430)
+++ /trunk/psLib/src/sysUtils/psMemory.c	(revision 430)
@@ -0,0 +1,441 @@
+/** @file  psMemory.c
+ *
+ *  @brief Contains the definitions for the memory management system
+ *
+ *  psMemory.h has additional information and documentation of the routines found in this file.
+ *
+ *  @author Robert DeSonia, MHPCC
+ *  @author Robert Lupton, Princeton University
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-04-15 21:22:09 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#define PS_ALLOW_MALLOC                 // we're allowed to call malloc()
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "psMemory.h"
+#include "psError.h"
+
+#define P_PS_MEMMAGIC (void *)0xdeadbeef // Magic number in psMemBlock header
+
+static int bad_memblock(const psMemBlock *m, int quiet);
+static int numMemBlock = 0;             // size of memBlocks
+static psMemBlock **memBlocks = NULL;
+
+/**
+ * Unique ID for allocated blocks
+ */
+static unsigned long memid = 0;
+
+/**
+ *  Default memExhausted callback.
+ */
+static void *memExhaustedCallbackDefault(size_t size)
+{
+    return NULL;
+}
+
+static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;
+
+psMemExhaustedCallback psMemExhaustedSetCallback(psMemExhaustedCallback func)
+{
+    psMemExhaustedCallback old = memExhaustedCallback;
+
+    if (func != NULL) {
+	    memExhaustedCallback = func;
+	} else {
+	    memExhaustedCallback = memExhaustedCallbackDefault;
+	}
+
+    return old;
+}
+
+static void memProblemCallbackDefault(const psMemBlock *ptr,
+                          const char *file, int lineno)
+{
+    if (bad_memblock(ptr, 0)) {
+        fprintf(stderr, "Memory corruption or an attempt to manipulate memory "
+                "not allocated with psAlloc at %s", file);
+        if (lineno > 0) {
+            fprintf(stderr, ":%d", lineno);
+        }
+        fprintf(stderr, "\n");
+    } else if (ptr->refCounter <= 0) {
+        psError(__func__, PS_ERR_BADFREE, PS_NEW_ERROR,
+                "Block %ld allocated at %s:%d freed more than once at %s:%d\n",
+                ptr->id, ptr->file, ptr->lineno, file, lineno);
+    } else if (ptr->refCounter > 1) {
+        psError(__func__,  PS_ERR_BADFREE, PS_NEW_ERROR,
+                "Block %ld allocated at %s:%d freed while still referenced at %s:%d\n",
+                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);
+    }
+}
+static psMemProblemCallback memProblemCallback = memProblemCallbackDefault;
+
+psMemProblemCallback psMemProblemSetCallback(psMemProblemCallback func)
+{
+    psMemProblemCallback old = memProblemCallback;
+
+    if (func != NULL) {
+	    memProblemCallback = func;
+	} else {
+	    memProblemCallback = memProblemCallbackDefault;
+	}
+
+    return old;
+}
+/*
+ * And now the I-want-to-be-informed callbacks
+ *
+ * Call the callbacks when these IDs are allocated/freed
+ */
+long p_psMemAllocateID = 0;  // notify user this block is allocated
+long p_psMemFreeID = 0;   // notify user this block is freed
+
+long psMemSetAllocateID(long id) // set p_psMemAllocateID to id
+{
+    long old = p_psMemAllocateID;
+    p_psMemAllocateID = id;
+
+    return old;
+}
+
+long psMemSetFreeID(long id)  // set p_psMemFreeID to id
+{
+    long old = p_psMemFreeID;
+    p_psMemFreeID = id;
+
+    return old;
+}
+
+/*
+ * Default callback for both allocate and free. Note that the
+ * value of p_psMemAllocateID/p_psMemFreeID is incremented
+ * by the return value (so returning 0 means that the callback
+ * isn't resignalled)
+ */
+static int memAllocateCallbackDefault(const psMemBlock *ptr)
+{
+    static int incr = 0;  // "p_psMemAllocateID += incr"
+
+    assert (ptr != NULL);  // prevent compiler warnings
+
+    return incr;
+}
+
+static int memFreeCallbackDefault(const psMemBlock *ptr)
+{
+    static int incr = 0;  // "p_psMemFreeID += incr"
+
+    assert (ptr != NULL);  // prevent compiler warnings
+
+    return incr;
+}
+
+/*
+ * The default callbacks, and the routines to change them
+ */
+static psMemCallback memAllocateCallback = memAllocateCallbackDefault;
+static psMemCallback memFreeCallback = memFreeCallbackDefault;
+
+psMemCallback psMemAllocateSetCallback(psMemCallback func)
+{
+    psMemCallback old = memAllocateCallback;
+
+    if (func != NULL) {
+	    memAllocateCallback =  func;
+	} else {
+	    memAllocateCallback = memAllocateCallbackDefault;
+	}
+
+    return old;
+}
+
+psMemCallback psMemFreeSetCallback(psMemCallback func)
+{
+    psMemCallback old = memFreeCallback;
+
+    if (func != NULL) {
+	    memFreeCallback = func;
+	} else {
+	    memFreeCallback = memFreeCallbackDefault;
+	}
+
+    return old;
+}
+
+/*****************************************************************************/
+/*
+ * Return memory ID counter for next block to be allocated
+ */
+int psMemGetId(void)
+{
+    return memid + 1;
+}
+
+/*****************************************************************************/
+/*
+ * Routines to check the consistency of the allocated and/or free memory arena
+ *
+ * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted
+ */
+#define ALIGNED(P) ((void *)((long)(P) & ~03) == (P))
+
+static int
+bad_memblock(const psMemBlock *m, // block to check
+             int quiet)   // be quiet?
+{
+    if (m == NULL) {
+        if (!quiet) {
+            psError(__func__,  PS_ERR_MEMORY_CORRUPTION, PS_NEW_ERROR,
+                    "psMemCheckCorruption: NULL memory block\n");
+        }
+        return(1);
+    }
+
+    if (!ALIGNED(m)) {
+        if (!quiet) {
+            psError(__func__,  PS_ERR_MEMORY_CORRUPTION, PS_NEW_ERROR,
+                    "psMemCheckCorruption: non-aligned memory block\n");
+        }
+        return(1);
+    }
+
+    if (m->magic0 != P_PS_MEMMAGIC || m->magic != P_PS_MEMMAGIC) {
+        if (!quiet) {
+            psError(__func__, PS_ERR_MEMORY_CORRUPTION, PS_NEW_ERROR,
+                    "psMemCheckCorruption: memory block %ld is corrupted\n", m->id);
+        }
+        return(1);
+    }
+
+    return(0);
+}
+
+int psMemCheckCorruption(int abort_on_error)
+{
+    int nbad = 0;   // number of bad blocks
+
+    if (memBlocks == NULL) {
+        return 0;   // no memory is allocated to be corrupted
+    }
+
+    for (int i = 1; i <= memid; i++) {
+        if (memBlocks[i] != NULL) {
+            if (bad_memblock(memBlocks[i], 1)) {
+                nbad++;
+
+                memProblemCallback(memBlocks[i], "(psMemCheckCorruption)", 0);
+
+                if (abort_on_error) {
+                    psAbort(__func__, "Detected memory corruption");
+                }
+            }
+        }
+    }
+
+    return nbad;
+}
+
+/*****************************************************************************/
+
+void *p_psAlloc(size_t size, const char *file, int lineno)
+{
+    psMemBlock *ptr = malloc(sizeof(psMemBlock) + size);
+
+    if (ptr == NULL) {
+        ptr = memExhaustedCallback(size);
+        if (ptr == NULL) {
+            psAbort(__func__, "Failed to allocate %ld bytes at %s:%d",
+                    size, file, lineno);
+        }
+    }
+
+    *(unsigned long *)&ptr->id = ++memid;
+    ptr->file = file;
+    *(int *)&ptr->lineno = lineno;
+    *(void **)&ptr->magic0 = *(void **)&ptr->magic = P_PS_MEMMAGIC;
+
+    ptr->refCounter = 1;  // one user so far
+    /*
+     * Did the user ask to be informed about this allocation?
+     */
+
+    if (ptr->id == p_psMemAllocateID && p_psMemAllocateID > 0) {
+        p_psMemAllocateID += memAllocateCallback(ptr);
+    }
+    if (memid >= nMemBlock) {
+        nMemBlock = (nMemBlock == 0) ? 100000 : 2*nMemBlock;
+        memBlocks = realloc(memBlocks, nMemBlock*sizeof(psMemBlock *)); // NOT psRealloc
+    }
+    memBlocks[ptr->id] = ptr;
+    /*
+     * And return the user the memory that they allocated
+     */
+    return ptr + 1;   // usr memory
+}
+
+void *p_psRealloc(void *vptr, size_t size, const char *file, int lineno)
+{
+    if (vptr == NULL) {
+        return p_psAlloc(size, file, lineno);
+    } else {
+        psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+        ptr = (psMemBlock *)realloc(ptr, sizeof(psMemBlock) + size);
+        memBlocks[ptr->id] = ptr;
+
+        return ptr + 1;   // usr memory
+    }
+}
+
+void p_psFree(void *vptr, const char *file, int lineno)
+{
+    if (vptr == NULL) {
+        return;
+    }
+
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+    /*
+     * Did the user ask to be informed about this deallocation?
+     */
+    if (ptr->id == p_psMemFreeID && p_psMemFreeID > 0) {
+        p_psMemFreeID += memFreeCallback(ptr);
+    }
+
+    if (bad_memblock(ptr, 0)) {
+        memProblemCallback(ptr, file, lineno); // we may not own this block; don't free it
+    } else {
+        if (ptr->refCounter != 1) {
+            memProblemCallback(ptr, file, lineno);
+        }
+        ptr->refCounter--;
+        #if 1
+
+        memBlocks[ptr->id] = NULL; // XXX sub-optimal! Can't check
+        // freed blocks for corruption/double frees
+        free(ptr);
+        #endif
+
+    }
+}
+
+/*****************************************************************************/
+/*
+ * Check for memory leaks. Not production quality code
+ */
+int psMemCheckLeaks(
+    int id0,    // don't list blocks with id < id0
+    psMemBlock ***arr,   // pointer to array of pointers to
+    // leaked blocks, or NULL
+    FILE *fd)    // print list of leaks to fd (or NULL)
+{
+    int nleak = 0;
+
+    if (memBlocks == NULL)
+    {  // nothing was allocated
+        return 0;
+    }
+
+    for (int i = id0; i <= memid; i++)
+    {
+        if (memBlocks[i] != NULL) {
+            if (memBlocks[i]->refCounter > 0) {
+                nleak++;
+
+                if (fd != NULL) {
+                    if (nleak == 1) {
+                        fprintf(fd, "   %20s:line ID\n", "file");
+                    }
+
+                    fprintf(fd, "   %20s:%-4d %ld\n",
+                            memBlocks[i]->file, memBlocks[i]->lineno,
+                            memBlocks[i]->id);
+                }
+            }
+        }
+    }
+
+    if (nleak == 0 || arr == NULL)
+    {
+        return nleak;
+    }
+
+    assert (*arr == NULL);  // Don't generate a memory leak!
+
+    *arr = p_psAlloc(nleak*sizeof(psMemBlock), __FILE__, __LINE__);
+    for (int i = id0, j = 0; i < memid; i++)
+    {
+        if (memBlocks[i] != NULL) {
+            if (memBlocks[i]->refCounter > 0) {
+                (*arr)[j++] = memBlocks[i];
+                if (j == nleak) { // found them all
+                    break;
+                }
+            }
+        }
+    }
+
+    return nleak;
+}
+
+/*****************************************************************************/
+/*
+ * Reference counting APIs
+ */
+int psMemGetRefCounter(void *vptr) // return refCounter
+{
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+
+    if (bad_memblock(ptr, 0))
+    {
+        memProblemCallback(ptr, "(psMemGetRefCounter)", -1);
+    }
+
+    return ptr->refCounter;
+}
+
+void *psMemIncrRefCounter(void *vptr) // increment and return refCounter
+{
+    if (vptr == NULL)
+    {
+        return vptr;
+    }
+
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+
+    if (bad_memblock(ptr, 0))
+    {
+        memProblemCallback(ptr, "(psMemIncrRefCounter)", -1);
+    }
+
+    ptr->refCounter++;
+
+    return vptr;
+}
+
+void *psMemDecrRefCounter(void *vptr) // decrement and return refCounter
+{
+    if (vptr == NULL)
+    {
+        return vptr;
+    }
+
+    psMemBlock *ptr = ((psMemBlock *)vptr) - 1;
+
+    if (bad_memblock(ptr, 0))
+    {
+        memProblemCallback(ptr, "(psMemDecrRefCounter)", -1);
+    }
+
+    ptr->refCounter--;
+
+    return vptr;
+}
Index: /trunk/psLib/src/sysUtils/psMemory.h
===================================================================
--- /trunk/psLib/src/sysUtils/psMemory.h	(revision 430)
+++ /trunk/psLib/src/sysUtils/psMemory.h	(revision 430)
@@ -0,0 +1,151 @@
+#if !defined(PS_MEMORY_H)
+#define PS_MEMORY_H
+
+#include <stdio.h>    // needed for FILE
+/** @file  psMemory.h
+ *
+ *  @brief Contains the definitions for the memory management system
+ *
+ *  This is the generic memory management system put inbetween the user's high level code and the OS-level
+ *  memory allocation routines.  This system adds such features as callback routines for memory error events,
+ *  tracing capabilities, and reference counting.
+ *
+ *  @author Robert DeSonia, MHPCC
+ *  @author Robert Lupton, Princeton University
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-04-15 21:22:09 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+/** Book-keeping data for storage allocator.
+ *  N.b. sizeof(psMemBlock) must be chosen such that if ptr is a pointer
+ *  returned by malloc, then ((char *)ptr + sizeof(psMemBlock)) is properly
+ *  aligned for all storage types.
+ */
+typedef struct
+{
+    const void *startblock;             ///< initialised to p_psMEMMAGIC
+    const unsigned long id;             ///< a unique ID for this allocation
+    const char *file;                   ///< set from __FILE__ in e.g. p_psAlloc
+    const int lineno;                   ///< set from __LINE__ in e.g. p_psAlloc
+    int refCounter;                     ///< how many times pointer is referenced
+    const void **endpost;               ///< initialised to p_psMEMMAGIC
+    const void *endblock;               ///< initialised to p_psMEMMAGIC
+}
+psMemBlock;
+
+/// prototype of a basic callback used by memory functions
+typedef long (*psMemAllocateCallback)(const psMemBlock *ptr);
+
+/// prototype of memory free callback used by memory functions
+typedef long (*psMemFreeCallback)(const psMemBlock *ptr);
+
+/// prototype of a callback used in error conditions
+typedef void (*psMemProblemCallback)(const psMemBlock *ptr, const char *file, int lineno);
+
+/// prototype of a callback used when memory runs out
+typedef void *(*psMemExhaustedCallback)(size_t size);
+
+/** Private Functions **************************************************************/
+/** \addtogroup sysUtils memory private
+ *  \{
+ */
+
+/// Memory allocation. Underlying private function called by macro psAlloc.
+void *p_psAlloc(size_t size,  ///< Size required
+                const char *file, ///< File of call
+                int lineno)  ///< Line number of call
+;
+
+/// Memory re-allocation.  Underlying private function called by macro psRealloc.
+void *p_psRealloc(void *ptr,  ///< Pointer to re-allocate
+                  size_t size,  ///< Size required
+                  const char *file, ///< File of call
+                  int lineno)  ///< Line number of call
+;
+
+/// Free memory.  Underlying private function called by macro psFree.
+void p_psFree(void *ptr,  ///< Pointer to free
+              const char *file,  ///< File of call
+              int lineno)  ///< Line number of call
+;
+/** Public Functions **************************************************************/
+/** \}
+ *  \addtogroup sysUtils memory psLibAPI
+ *  \{
+ */
+
+/// Check for memory leaks
+int psMemCheckLeaks(int id0,  ///< don't list blocks with id < id0
+                    psMemBlock ***arr, ///< pointer to array of pointers to leaked blocks, or NULL
+                    FILE *fd)  ///< print list of leaks to fd (or NULL)
+;
+
+/// Check for memory corruption
+int psMemCheckCorruption(int abort_on_error) ///< Abort on detecting corruption?
+;
+
+/// Return reference counter
+int psMemGetRefCounter(void *vptr) ///< Pointer to get refCounter for
+;
+
+/// Increment reference counter and return the pointer
+void *psMemIncrRefCounter(void *vptr) ///< Pointer to increment refCounter, and return
+;
+
+/// Decrement reference counter and return the pointer
+void *psMemDecrRefCounter(void *vptr) ///< Pointer to decrement refCounter, and return
+;
+
+/// Set callback for problems
+psMemProblemCallback psMemProblemCallbackSet(psMemProblemCallback func) ///< Function to run
+;
+
+/// Set callback for out-of-memory
+psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func) ///< Function to run
+;
+
+/// Set call back for when a particular memory block is allocated
+psMemCallback psMemAllocateCallbackSet(psMemAllocateCallback func) ///< Function to run
+;
+
+/// Set call back for when a particular memory block is freed
+psMemCallback psMemFreeCallbackSet(psMemFreeCallback func) ///< Function to run
+;
+
+/// get next memory ID
+int psMemGetId(void)
+;
+
+/// set p_psMemAllocateID to id
+long psMemAllocateIDSet(long id) ///< ID to set
+;
+
+/// set p_psMemFreeID to id
+long psMemFreeIDSet(long id)  ///< ID to set
+;
+
+//@} End of public Functions
+
+/// Memory allocation. psAlloc sends file and line number to p_psAlloc.
+#define psAlloc(size) p_psAlloc(size, __FILE__, __LINE__)
+
+/// Memory re-allocation.  psRealloc sends file and line number to p_psRealloc.
+#define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__)
+
+/// Free memory.  psFree sends file and line number to p_psFree.
+#define psFree(size) p_psFree(size, __FILE__, __LINE__)
+
+/*
+ * Ensure that any program using malloc/realloc/free will fail to compile
+ */
+#ifndef PS_ALLOW_MALLOC
+    #define malloc(S)       #pragma error Use of malloc is not allowed.  Use psAlloc instead.
+    #define realloc(P,S)    #pragma error Use of realloc is not allowed.  Use psRealloc instead.
+    #define calloc(S)       #pragma error Use of calloc is not allowed.  Use psAlloc instead.
+    #define free(P)         #pragma error Use of free is not allowed.  Use psFree instead.
+#endif
+
+#endif // end of header file
