Index: trunk/psLib/src/sys/psError.c
===================================================================
--- trunk/psLib/src/sys/psError.c	(revision 8603)
+++ trunk/psLib/src/sys/psError.c	(revision 8792)
@@ -8,8 +8,9 @@
  *  of error detected.
  *
+ *  @author Joshua Hoblitt, University of Hawaii
  *  @author Eric Van Alst, MHPCC
  *
- *  @version $Revision: 1.34 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-08-25 22:04:03 $
+ *  @version $Revision: 1.35 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-09-12 03:16:51 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -25,32 +26,105 @@
 #include "psString.h"
 #include "psTrace.h"
+#include "psAbort.h"
 
 #define MAX_STRING_LENGTH 2048
-
-
 #define MAX_ERROR_STACK_SIZE 64
-static psErr* errorStack[MAX_ERROR_STACK_SIZE];
-static psU32 errorStackSize = 0;
-pthread_mutex_t lockErrorStack = PTHREAD_MUTEX_INITIALIZER;
-
-static void pushErrorStack(psErr* err);
-
-static void pushErrorStack(psErr* err)
-{
-
+
+static pthread_mutex_t lockErrorStack = PTHREAD_MUTEX_INITIALIZER;
+static bool errorStackKeyInitialized = false;
+static pthread_key_t errorStack_key;
+
+typedef struct
+{
+    int n;
+    psErr **stack;
+}
+psErrorStack;
+
+static psErrorStack *psErrorStackAlloc(void);
+static void psErrorStackFree(psErrorStack *errorStack);
+static void psFreeWrapper(void *ptr);
+static void psErrorStackPush(psErr* err);
+static psErrorStack *psErrorStackGet(void);
+static void psErrFree(psErr* err);
+
+static psErrorStack *psErrorStackAlloc(void)
+{
+    psErrorStack *errorStack = psAlloc(sizeof(psErrorStack));
+    errorStack->n = 0;
+    errorStack->stack = psAlloc(sizeof(psErr*) * MAX_ERROR_STACK_SIZE);
+
+    psMemSetDeallocator(errorStack, (psFreeFunc)psErrorStackFree);
+
+    return errorStack;
+}
+
+static void psErrorStackFree(psErrorStack *errorStack)
+{
+    if (!errorStack) {
+        return;
+    }
+
+    psFree(errorStack->stack);
+}
+
+// needed for pthread_key_create() because p_psFree() does not match free()'s
+// prototype
+// XXX does something like this need to be global in psMmemory.h
+static void psFreeWrapper(void *ptr)
+{
+    psFree(ptr);
+}
+
+static void psErrorStackPush(psErr* err)
+{
+    psErrorStack *errorStack = psErrorStackGet();
+
+    // push the item onto the stack and increment the error count
+    if (errorStack->n < MAX_ERROR_STACK_SIZE) {
+        errorStack->stack[errorStack->n] = psMemIncrRefCounter(err);
+        (errorStack->n)++;
+        p_psMemSetPersistent(err, true);
+        p_psMemSetPersistent(err->msg, true);
+        p_psMemSetPersistent(err->name, true);
+    } else {
+        psAbort(__func__, "attempt to exceed maximum error stack depth of %d",
+                MAX_ERROR_STACK_SIZE);
+    }
+}
+
+static psErrorStack *psErrorStackGet(void)
+{
+    // check to see if the error stack key has been initialized
     pthread_mutex_lock(&lockErrorStack);
-
-    if (errorStackSize < MAX_ERROR_STACK_SIZE) {
-        errorStack[errorStackSize] = psMemIncrRefCounter(err);
-        errorStackSize++;
-        p_psMemSetPersistent(err,true);
-        p_psMemSetPersistent(err->msg,true);
-        p_psMemSetPersistent(err->name,true);
-    }
-
+    if (errorStackKeyInitialized == false) {
+        // note that each error stack will automatically be free'd when it's
+        // thread exits
+        if (pthread_key_create(&errorStack_key, psFreeWrapper)) {
+            psAbort(__func__, "pthread_key_create() failed");
+        }
+        errorStackKeyInitialized = true;
+    }
     pthread_mutex_unlock(&lockErrorStack);
-}
-
-static void errFree(psErr* err)
+
+    // check to see if the error stack for this thread has been allocated
+    psErrorStack *errorStack = NULL;
+    if ((errorStack = pthread_getspecific(errorStack_key)) == NULL) {
+        // allocate the error stack
+        errorStack = psErrorStackAlloc();
+        p_psMemSetPersistent(errorStack, true);
+        p_psMemSetPersistent(errorStack->stack, true);
+        // store this threads error stack
+        // note that pthread_setspecifc() does not take a pointer as the first
+        // param
+        if (pthread_setspecific(errorStack_key, errorStack)) {
+            psAbort(__func__, "pthread_setspecific() failed");
+        }
+    }
+
+    return errorStack;
+}
+
+static void psErrFree(psErr* err)
 {
     if (err != NULL) {
@@ -63,9 +137,9 @@
 {
     psErr* err = psAlloc(sizeof(psErr));
-    err->msg = strcpy(psAlloc(strlen(msg) + 1), msg);
-    err->name = strcpy(psAlloc(strlen(name) + 1), name);
+    err->msg = psStringCopy(msg);
+    err->name = psStringCopy(name);
     err->code = code;
 
-    psMemSetDeallocator(err,(psFreeFunc)errFree);
+    psMemSetDeallocator(err,(psFreeFunc)psErrFree);
 
     return err;
@@ -84,4 +158,5 @@
     char msgName[MAX_STRING_LENGTH];
 
+    // XXX a VLA should be used here instead of a fixed size buffer
     snprintf(msgName, MAX_STRING_LENGTH, "%s (%s:%d)", func, filename, lineno);
 
@@ -90,5 +165,6 @@
     }
 
-    // Get the variable list parameters to pass to logging function
+    //XXX this could go away if we had a p_psTraceV() that accept file,
+    //lieno, etc.  Get the variable list parameters to pass to logging function
     va_list argPtr;             // variable list arguement pointer
     va_start(argPtr, format);
@@ -104,5 +180,5 @@
 
     err = psErrAlloc(msgName,code,errMsg);
-    pushErrorStack(err);
+    psErrorStackPush(err);
 
     #ifndef PS_NO_TRACE
@@ -125,7 +201,7 @@
                  ...)
 {
-    char msgName[1024];
-
-    snprintf(msgName,1024,"%s (%s:%d)",func,file,lineno);
+    char msgName[MAX_STRING_LENGTH];
+
+    snprintf(msgName, MAX_STRING_LENGTH, "%s (%s:%d)", func, file, lineno);
 
     va_list argPtr;             // variable list argument pointer
@@ -142,9 +218,9 @@
 }
 
-psErr* psErrorGet(psS32 which)
+psErr* psErrorGet(int which)
 {
     psErr* result;
 
-    pthread_mutex_lock(&lockErrorStack);
+    psErrorStack *errorStack = psErrorStackGet();
 
     // Check for negative reference and if found return PS_ERR_NONE
@@ -153,20 +229,20 @@
     } else {
 
-        which = errorStackSize-1-which;     // the which input is from the end of errorStack
-        if (which < 0 || which >= errorStackSize) {
+        which = errorStack->n - 1 - which;     // the which input is from the end of errorStack
+        if (which < 0 || which >= errorStack->n) {
             result = psErrAlloc("",PS_ERR_NONE,"");    // no error at the given location
         } else {
-            result = psMemIncrRefCounter(errorStack[which]); // a new reference passed back
+            result = psMemIncrRefCounter(errorStack->stack[which]); // a new reference passed back
         }
     }
 
-    pthread_mutex_unlock(&lockErrorStack);
-
     return result;
 }
 
-unsigned int psErrorGetStackSize()
-{
-    return errorStackSize;
+int psErrorGetStackSize()
+{
+    psErrorStack *errorStack = psErrorStackGet();
+
+    return errorStack->n;
 }
 
@@ -187,17 +263,16 @@
 void psErrorClear(void)
 {
-    pthread_mutex_lock(&lockErrorStack);
-
-    for (int lcv=0;lcv < errorStackSize; lcv++) {
-        p_psMemSetPersistent(errorStack[lcv],false);
-        p_psMemSetPersistent(errorStack[lcv]->msg,false);
-        p_psMemSetPersistent(errorStack[lcv]->name,false);
-        psFree(errorStack[lcv]);
-    }
-    errorStackSize = 0;
-
-    pthread_mutex_unlock(&lockErrorStack);
-
-}
+    psErrorStack *errorStack = psErrorStackGet();
+
+    for (int i = 0; i < errorStack->n; i++) {
+        p_psMemSetPersistent(errorStack->stack[i], false);
+        p_psMemSetPersistent((errorStack->stack[i])->msg, false);
+        p_psMemSetPersistent((errorStack->stack[i])->name, false);
+        psFree(errorStack->stack[i]);
+    }
+
+    errorStack->n = 0;
+}
+
 void psErrorStackPrint(FILE *fd, const char *format, ...)
 {
@@ -214,26 +289,23 @@
 void psErrorStackPrintV(FILE *fd, const char *format, va_list va)
 {
-
-    pthread_mutex_lock(&lockErrorStack);
-
-    if (errorStackSize > 0) {
+    psErrorStack *errorStack = psErrorStackGet();
+
+    if (errorStack->n > 0) {
         vfprintf(fd,format,va);
 
-        for (psS32 lcv=0;lcv<errorStackSize;lcv++) {
-            if(errorStack[lcv]->code >= PS_ERR_BASE) {
+        for (int i = 0; i < errorStack->n; i++) {
+            if(errorStack->stack[i]->code >= PS_ERR_BASE) {
                 fprintf(fd," -> %s: %s\n     %s\n",
-                        errorStack[lcv]->name,
-                        psErrorCodeString(errorStack[lcv]->code),
-                        errorStack[lcv]->msg);
+                        errorStack->stack[i]->name,
+                        psErrorCodeString(errorStack->stack[i]->code),
+                        errorStack->stack[i]->msg);
             } else {
                 fprintf(fd," -> %s: %s\n     %s\n",
-                        errorStack[lcv]->name,
-                        strerror(errorStack[lcv]->code),
-                        errorStack[lcv]->msg);
+                        errorStack->stack[i]->name,
+                        strerror(errorStack->stack[i]->code),
+                        errorStack->stack[i]->msg);
             }
         }
     }
-
-    pthread_mutex_unlock(&lockErrorStack);
-}
-
+}
+
