Index: trunk/psLib/src/sysUtils/psMemory.c
===================================================================
--- trunk/psLib/src/sysUtils/psMemory.c	(revision 1233)
+++ trunk/psLib/src/sysUtils/psMemory.c	(revision 1240)
@@ -8,6 +8,6 @@
  *  @author Robert Lupton, Princeton University
  *
- *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-15 23:52:34 $
+ *  @version $Revision: 1.29 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-19 20:45:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -28,4 +28,6 @@
 #define P_PS_MEMMAGIC (void *)0xdeadbeef // Magic number in psMemBlock header
 
+#define P_PS_LARGE_BLOCK_SIZE 65536    // size where under, we try to recycle
+
 static int checkMemBlock(const psMemBlock *m, const char* funcName);
 static psMemBlock *lastMemBlockAllocated = NULL;
@@ -33,4 +35,14 @@
 static pthread_mutex_t memIdMutex = PTHREAD_MUTEX_INITIALIZER;
 
+static pthread_mutex_t recycleMemBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int recycleBins = 13;
+static int recycleBinSize[14] = {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 psMemBlock* recycleMemBlockList[13] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+
+#ifdef PS_MEM_DEBUG
+static psMemBlock* deadBlockList;    // a place to put dead memBlocks in debug mode.
+#endif
 /**
  * Unique ID for allocated blocks
@@ -43,5 +55,20 @@
 static void *memExhaustedCallbackDefault(size_t size)
 {
-    return NULL;
+    void* ptr = NULL;
+
+    pthread_mutex_lock(&recycleMemBlockListMutex);
+    int level=recycleBins-1;
+    while (level >= 0 && ptr == NULL) {
+        while (recycleMemBlockList[level] != NULL && ptr == NULL) {
+            psMemBlock* old = recycleMemBlockList[level];
+            recycleMemBlockList[level] = recycleMemBlockList[level]->nextBlock;
+            free(old);
+            ptr = malloc(size);
+        }
+        level--;
+    }
+    pthread_mutex_unlock(&recycleMemBlockListMutex);
+
+    return ptr;
 }
 
@@ -243,12 +270,49 @@
 void *p_psAlloc(size_t size, const char *file, int lineno)
 {
-    psMemBlock *ptr = malloc(sizeof(psMemBlock) + size + sizeof(void*));
+
+    psMemBlock *ptr = NULL;
+
+    // memory is of the size I want to bother recycling?
+    if (size < P_PS_LARGE_BLOCK_SIZE) {
+        // find the bin we need.
+        int level = 0;
+        while (size > recycleBinSize[level]) {
+            level++;
+        }
+        // Are we in one of the bins
+        if (level<recycleBins) {
+
+            size = recycleBinSize[level];  // round-up size to next sized bin.
+
+            pthread_mutex_lock(&recycleMemBlockListMutex);
+
+            if (recycleMemBlockList[level] != NULL) {
+                ptr = recycleMemBlockList[level];
+                recycleMemBlockList[level] = ptr->nextBlock;
+                if (recycleMemBlockList[level] != NULL) {
+                    recycleMemBlockList[level]->previousBlock = NULL;
+                }
+                size = ptr->userMemorySize;
+            }
+
+            pthread_mutex_unlock(&recycleMemBlockListMutex);
+        }
+    }
 
     if (ptr == NULL) {
-        ptr = memExhaustedCallback(size);
+        ptr = malloc(sizeof(psMemBlock) + size + sizeof(void*));
+
         if (ptr == NULL) {
-            psAbort(__func__, "Failed to allocate %u bytes at %s:%d",
-                    size, file, lineno);
-        }
+            ptr = memExhaustedCallback(size);
+            if (ptr == NULL) {
+                psAbort(__func__, "Failed to allocate %u bytes at %s:%d",
+                        size, file, lineno);
+            }
+        }
+
+        ptr->startblock = P_PS_MEMMAGIC;
+        ptr->endblock = P_PS_MEMMAGIC;
+        ptr->userMemorySize = size;
+        pthread_mutex_init(&ptr->refCounterMutex, NULL);
     }
 
@@ -261,11 +325,7 @@
     ptr->freeFcn = NULL;
     *(unsigned int*)&ptr->lineno = lineno;
-    ptr->startblock = P_PS_MEMMAGIC;
-    ptr->endblock = P_PS_MEMMAGIC;
-    ptr->userMemorySize = size;
     *(void**)((int8_t*)(ptr+1)+size) = P_PS_MEMMAGIC;
     ptr->previousBlock = NULL;
 
-    pthread_mutex_init(&ptr->refCounterMutex, NULL);
     ptr->refCounter = 1;                // one user so far
 
@@ -475,10 +535,4 @@
         }
 
-        #ifdef PS_MEM_DEBUG
-        // for debug mode, we should keep the memBlock around and mark as not referenced.
-        ptr->refCounter = 0;
-        (void)p_psRealloc(vptr,0,file,lineno);
-        #else
-
         pthread_mutex_lock(&memBlockListMutex);
 
@@ -496,8 +550,46 @@
         pthread_mutex_unlock(&memBlockListMutex);
 
+
+        // do we need to recycle?
+        if (ptr->userMemorySize < P_PS_LARGE_BLOCK_SIZE) {
+
+            int level = 1;
+            while (ptr->userMemorySize >= recycleBinSize[level]) {
+                level++;
+            }
+            level--;
+
+            ptr->refCounter = 0;
+            ptr->previousBlock = NULL;
+
+            pthread_mutex_lock(&recycleMemBlockListMutex);
+            ptr->nextBlock = recycleMemBlockList[level];
+            if (recycleMemBlockList[level] != NULL) {
+                recycleMemBlockList[level]->previousBlock = ptr;
+            }
+            recycleMemBlockList[level] = ptr;
+            pthread_mutex_unlock(&recycleMemBlockListMutex);
+
+        } else {
+            // 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
+
+            pthread_mutex_destroy(&ptr->refCounterMutex);
+            free(ptr);
+            #endif
+
+        }
+
+
         pthread_mutex_destroy(&ptr->refCounterMutex);
 
-        free(ptr);
-        #endif
 
         vptr = NULL;    // since we freed it, make sure we return NULL.
