e72cf0100e06d6fadb7282d4e7eb2c592f320951 galt Mon Jul 4 13:08:35 2011 -0700 Adding parallel-fetch loading of remote bigDataUrl tracks using pthreads diff --git src/lib/errabort.c src/lib/errabort.c index 167ea66..64ca2b3 100644 --- src/lib/errabort.c +++ src/lib/errabort.c @@ -2,70 +2,85 @@ * * This maintains two stacks - a warning message printer * stack, and a "abort handler" stack. * * By default the warnings will go to stderr, and * aborts will exit the program. You can push a * function on to the appropriate stack to change * this behavior. The top function on the stack * gets called. * * This file is copyright 2002 Jim Kent, but license is hereby * granted for all use - public, private or commercial. */ // developer: this include is for an occasionally useful means of getting stack info without crashing // however, it is not supported on cygwin. Conditionally compile this in when desired. + //#define BACKTRACE_EXISTS #ifdef BACKTRACE_EXISTS #include <execinfo.h> #endif///def BACKTRACE_EXISTS +#include <pthread.h> #include "common.h" +#include "hash.h" #include "dystring.h" #include "errabort.h" static char const rcsid[] = "$Id: errabort.c,v 1.16 2010/01/12 18:16:27 markd Exp $"; -static boolean debugPushPopErr = FALSE; // generate stack dump on push/pop error -boolean errAbortInProgress = FALSE; /* Flag to indicate that an error abort is in progress. + +#define maxWarnHandlers 20 +#define maxAbortHandlers 12 +struct perThreadAbortVars +/* per thread variables for abort and warn */ + { + boolean debugPushPopErr; // generate stack dump on push/pop error + boolean errAbortInProgress; /* Flag to indicate that an error abort is in progress. * Needed so that a warn handler can tell if it's really * being called because of a warning or an error. */ + // TODO probably have to create a global accessor function for setting errAbortInProgress. + WarnHandler warnArray[maxWarnHandlers]; + int warnIx; + AbortHandler abortArray[maxAbortHandlers]; + int abortIx; + }; + +static struct perThreadAbortVars *getThreadVars(); // forward declaration static void defaultVaWarn(char *format, va_list args) /* Default error message handler. */ { if (format != NULL) { fflush(stdout); vfprintf(stderr, format, args); fprintf(stderr, "\n"); } } static void silentVaWarn(char *format, va_list args) /* Warning handler that just hides it. Useful sometimes when high level code * expects low level code may fail (as in finding a file on the net) but doesn't * want user to be bothered about it. */ { } -#define maxWarnHandlers 20 -static WarnHandler warnArray[maxWarnHandlers] = {defaultVaWarn,}; -static int warnIx = 0; void vaWarn(char *format, va_list args) /* Call top of warning stack to issue warning. */ { -warnArray[warnIx](format, args); +struct perThreadAbortVars *ptav = getThreadVars(); +ptav->warnArray[ptav->warnIx](format, args); } void warn(char *format, ...) /* Issue a warning message. */ { va_list args; va_start(args, format); vaWarn(format, args); va_end(args); } void warnWithBackTrace(char *format, ...) /* Issue a warning message and append backtrace. */ { va_list args; @@ -105,127 +120,130 @@ void errnoWarn(char *format, ...) /* Prints error message from UNIX errno first, then does rest of warning. */ { char fbuf[512]; va_list args; va_start(args, format); sprintf(fbuf, "%s\n%s", strerror(errno), format); vaWarn(fbuf, args); va_end(args); } void pushWarnHandler(WarnHandler handler) /* Set abort handler */ { -if (warnIx >= maxWarnHandlers-1) +struct perThreadAbortVars *ptav = getThreadVars(); +if (ptav->warnIx >= maxWarnHandlers-1) { - if (debugPushPopErr) + if (ptav->debugPushPopErr) dumpStack("pushWarnHandler overflow"); errAbort("Too many pushWarnHandlers, can only handle %d\n", maxWarnHandlers-1); } -warnArray[++warnIx] = handler; +ptav->warnArray[++ptav->warnIx] = handler; } void popWarnHandler() /* Revert to old warn handler. */ { -if (warnIx <= 0) +struct perThreadAbortVars *ptav = getThreadVars(); +if (ptav->warnIx <= 0) { - if (debugPushPopErr) + if (ptav->debugPushPopErr) dumpStack("popWarnHandler underflow"); - errAbort("Too many popWarnHandlers"); + errAbort("Too few popWarnHandlers"); } ---warnIx; +--ptav->warnIx; } static void defaultAbort() /* Default error handler exits program. */ { if ((getenv("ERRASSERT") != NULL) || (getenv("ERRABORT") != NULL)) abort(); else exit(-1); } -#define maxAbortHandlers 12 -static AbortHandler abortArray[maxAbortHandlers] = {defaultAbort,}; -static int abortIx = 0; void noWarnAbort() /* Abort without message. */ { -abortArray[abortIx](); +struct perThreadAbortVars *ptav = getThreadVars(); +ptav->abortArray[ptav->abortIx](); exit(-1); /* This is just to make compiler happy. * We have already exited or longjmped by now. */ } void vaErrAbort(char *format, va_list args) /* Abort function, with optional (vprintf formatted) error message. */ { /* flag is needed because both errAbort and warn generate message * using the warn handler, however sometimes one needed to know * (like when logging), if it's an error or a warning. This is far from * perfect, as this isn't cleared if the error handler continues, * as with an exception mechanism. */ -errAbortInProgress = TRUE; +struct perThreadAbortVars *ptav = getThreadVars(); +ptav->errAbortInProgress = TRUE; vaWarn(format, args); noWarnAbort(); } void errAbort(char *format, ...) /* Abort function, with optional (printf formatted) error message. */ { va_list args; va_start(args, format); vaErrAbort(format, args); va_end(args); } void errnoAbort(char *format, ...) /* Prints error message from UNIX errno first, then does errAbort. */ { char fbuf[512]; va_list args; va_start(args, format); sprintf(fbuf, "%s\n%s", strerror(errno), format); vaErrAbort(fbuf, args); va_end(args); } void pushAbortHandler(AbortHandler handler) /* Set abort handler */ { -if (abortIx >= maxAbortHandlers-1) +struct perThreadAbortVars *ptav = getThreadVars(); +if (ptav->abortIx >= maxAbortHandlers-1) { - if (debugPushPopErr) + if (ptav->debugPushPopErr) dumpStack("pushAbortHandler overflow"); errAbort("Too many pushAbortHandlers, can only handle %d", maxAbortHandlers-1); } -abortArray[++abortIx] = handler; +ptav->abortArray[++ptav->abortIx] = handler; } void popAbortHandler() /* Revert to old abort handler. */ { -if (abortIx <= 0) +struct perThreadAbortVars *ptav = getThreadVars(); +if (ptav->abortIx <= 0) { - if (debugPushPopErr) + if (ptav->debugPushPopErr) dumpStack("popAbortHandler underflow"); errAbort("Too many popAbortHandlers\n"); } ---abortIx; +--ptav->abortIx; } static void debugAbort() /* Call the debugger. */ { fflush(stdout); assert(FALSE); defaultAbort(); } void pushDebugAbort() /* Push abort handler that will invoke debugger. */ { pushAbortHandler(debugAbort); } @@ -240,18 +258,51 @@ void pushWarnAbort() /* Push handler that will abort on warnings. */ { pushWarnHandler(warnAbortHandler); } void pushSilentWarnHandler() /* Set warning handler to be quiet. Do a popWarnHandler to restore. */ { pushWarnHandler(silentVaWarn); } void errAbortDebugnPushPopErr() /* generate stack dump if there is a error in the push/pop functions */ { -debugPushPopErr = TRUE; +struct perThreadAbortVars *ptav = getThreadVars(); +ptav->debugPushPopErr = TRUE; +} + +static struct perThreadAbortVars *getThreadVars() +/* Return a pointer to the perThreadAbortVars for the current pthread. */ +{ +static pthread_mutex_t ptavMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_lock( &ptavMutex ); +static struct hash *perThreadVars = NULL; +pthread_t pid = pthread_self(); // can be a pointer or a number +// A true integer has function would be nicer, but this will do. +// Don't safef, theoretically that could abort. +char key[64]; +snprintf(key, sizeof(key), "%lld", ptrToLL(pid)); +key[ArraySize(key)-1] = '\0'; +if (perThreadVars == NULL) + perThreadVars = hashNew(0); +struct hashEl *hel = hashLookup(perThreadVars, key); +if (hel == NULL) + { + // if it is the first time, initialization the perThreadAbortVars + struct perThreadAbortVars *ptav; + AllocVar(ptav); + ptav->debugPushPopErr = FALSE; + ptav->errAbortInProgress = FALSE; + ptav->warnIx = 0; + ptav->warnArray[0] = defaultVaWarn; + ptav->abortIx = 0; + ptav->abortArray[0] = defaultAbort; + hel = hashAdd(perThreadVars, key, ptav); + } +pthread_mutex_unlock( &ptavMutex ); +return (struct perThreadAbortVars *)(hel->val); }