Index: trunk/psLib/src/sys/psMemory.c
===================================================================
--- trunk/psLib/src/sys/psMemory.c	(revision 8808)
+++ trunk/psLib/src/sys/psMemory.c	(revision 8809)
@@ -8,6 +8,6 @@
 *  @author Robert Lupton, Princeton University
 *
-*  @version $Revision: 1.83 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-09-13 21:11:11 $
+*  @version $Revision: 1.84 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-09-13 21:14:48 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -38,4 +38,5 @@
 #define P_PS_MEMMAGIC (psPtr )0xdeadbeef   // Magic number in psMemBlock header
 
+#define P_PS_LARGE_BLOCK_SIZE 65536        // size where under, we try to recycle
 
 static psS32 checkMemBlock(const psMemBlock* m, const char *funcName);
@@ -50,4 +51,18 @@
 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.
@@ -58,4 +73,37 @@
  */
 static psMemId memid = 0;
+
+/**
+ *  Default memExhausted callback.
+ */
+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
+}
 
 /*
@@ -102,7 +150,6 @@
                            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.
+    // 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) {
@@ -142,4 +189,18 @@
 static psMemFreeCallback memFreeCallback = memFreeCallbackDefault;
 static psMemProblemCallback memProblemCallback = memProblemCallbackDefault;
+static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;
+
+psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func)
+{
+    psMemExhaustedCallback old = memExhaustedCallback;
+
+    if (func != NULL) {
+        memExhaustedCallback = func;
+    } else {
+        memExhaustedCallback = memExhaustedCallbackDefault;
+    }
+
+    return old;
+}
 
 psMemProblemCallback psMemProblemCallbackSet(psMemProblemCallback func)
@@ -216,5 +277,4 @@
 
     if (safeThreads) {
-        // LOCK: id
         pthread_mutex_lock(&memIdMutex);
     }
@@ -223,5 +283,4 @@
 
     if (safeThreads) {
-        // UNLOCK: id
         pthread_mutex_unlock(&memIdMutex);
     }
@@ -232,19 +291,5 @@
 psMemId psMemGetLastId(void)
 {
-    psMemId id;
-
-    if (safeThreads) {
-        // LOCK: id
-        pthread_mutex_lock(&memIdMutex);
-    }
-
-    id = memid;
-
-    if (safeThreads) {
-        // UNLOCK: id
-        pthread_mutex_unlock(&memIdMutex);
-    }
-
-    return id;
+    return memid;
 }
 
@@ -252,14 +297,18 @@
 {
     psS32 nbad = 0;               // number of bad blocks
-
-    // get exclusive access to the memBlock list to avoid it changing on us
-    // while we use it.
-    if (safeThreads) {
-        // LOCK: block list
-        pthread_mutex_unlock(&memBlockListMutex);
-    }
+    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 (checkMemBlock(iter, __func__)) {
+        if (safeThreads) {
+            pthread_mutex_unlock(&memBlockListMutex);
+        }
+        failure = checkMemBlock(iter, __func__);
+        if (safeThreads) {
+            pthread_mutex_lock(&memBlockListMutex);
+        }
+        if ( failure ) {
             nbad++;
 
@@ -267,6 +316,6 @@
 
             if (abort_on_error) {
+                // release the lock on the memblock list
                 if (safeThreads) {
-                    // UNLOCK: block list
                     pthread_mutex_unlock(&memBlockListMutex);
                 }
@@ -277,9 +326,8 @@
     }
 
-    if (safeThreads) {
-        // UNLOCK: block list
+    // release the lock on the memblock list
+    if (safeThreads) {
         pthread_mutex_unlock(&memBlockListMutex);
     }
-
     return nbad;
 }
@@ -379,9 +427,21 @@
     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) {
-            psAbort(__func__, "Failed to allocate %zd bytes at %s:%d", size, file, lineno);
+            ptr = memExhaustedCallback(size);
+            if (ptr == NULL) {
+                psAbort(__func__, "Failed to allocate %zd bytes at %s:%d", size, file, lineno);
+            }
         }
 
@@ -473,5 +533,8 @@
     ptr = (psMemBlock *)realloc(ptr, sizeof(psMemBlock) + size + sizeof(psPtr));
     if (ptr == NULL) {
-        psAbort(__func__, "Failed to reallocate %zd bytes at %s:%d", size, file, lineno);
+        ptr = memExhaustedCallback(size);
+        if (ptr == NULL) {
+            psAbort(__func__, "Failed to reallocate %zd bytes at %s:%d", size, file, lineno);
+        }
     }
 
