/* gef_test: A demonstration/test program for the GEF (General Exception- Handling Facility) library. Copyright (C) 1998-2006 Bruce W. Bigby, bbigby@alum.MIT.edu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #ifdef GEF_POSIX #include #endif #include #include #include #include #include #ifdef GEF_POSIX #ifdef GEF_PTHREADS #include #else #include #endif #else #include #endif #ifdef GEF_PTHREADS #include #endif #include #if 0 #define CLOCK #endif #define MAX(a, b) ((a) > (b) ? (a) : (b)) #ifdef GEF_PTHREADS static pthread_t *threads; static int* status; #endif static char *threadName; #ifndef GEF_LINUX #ifdef GEF_PTHREADS #if 1 static int *signalNotificationList; #else static int (*signalNotificationList)[NSIG]; #endif static pthread_mutex_t signalNotificationListMutex; #endif #endif static int numberOfThreads = 1; typedef struct { int threadNumber; int asyncSupport; } *ThreadArgs_t; #define EXCEPT_FAILURE 0 #define EXCEPT_OS_VIOLATION 1 #define EXCEPT_INSUFFICIENT_MEMORY 2 #define EXCEPT_ASSERTION_VIOLATION 3 #define EXCEPT_PRECONDITION_VIOLATION 4 #define EXCEPT_POSTCONDITION_VIOLATION 5 #define EXCEPT_PREINVARIANT_VIOLATION 6 #define EXCEPT_POSTINVARIANT_VIOLATION 7 #define EXCEPT_ARITHMETIC_VIOLATION 8 #define EXCEPT_USER1_VIOLATION 9 #define EXCEPT_USER2_VIOLATION 10 #define EXCEPT_ALARM_EXPIRED 11 #ifdef GEF_POSIX static int sigsetprint(sigset_t* set) { int signo; for (signo = NSIG; signo > 0; signo--) { if (sigismember(set, signo)) { putchar('1'); } else putchar('0'); } return(1); } #endif static int PrintMask(void) { #ifdef GEF_POSIX #ifndef NDEBUG #ifdef DEBUG sigset_t mask; printf("\tsignal mask = "); #ifdef GEF_PTHREADS pthread_sigmask(SIG_SETMASK, NULL, &mask); #else sigprocmask(SIG_SETMASK, NULL, &mask); #endif sigsetprint(&mask); putchar('\n'); #endif #endif #endif } static void TestMalloc(int threadNumber) { unsigned int size = 1024; void* memory; printf("***** Thread %d: Test gef_malloc(%u) ****\n", threadNumber, size); memory = gef_malloc(size); gef_free(&memory); if (memory != NULL) { printf("***** ERROR!!! After gef_free() of memory, memory container should be NULL!\n"); } printf("\tDONE\n"); fflush(stdout); } static void TestBasicTry (int threadNumber) { printf("**** Thread %d: Test Basic Try ****\n", threadNumber); gef_try { printf("\tTRY...\n"); } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestTry(int threadNumber) { printf("**** Thread %d: Test Try Finally ****\n", threadNumber); gef_try { printf("\tTRY...\n"); } gef_invariants { printf("\tINVARIANTS...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_finalize { printf("\tFINALIZE...\n"); } gef_end; printf("\tDONE...\n"); fflush(stdout); } #ifdef GEF_POSIX static void TestPosixTry(int threadNumber) { printf("**** Thread %d: Test Posix Try Finally ****\n", threadNumber); printf("\tCurrent state of Posix support is %s...\n", GEFGetAsyncSupport() ? "true" : "false"); gef_posix_try { printf("\tTRY...\n"); PrintMask(); printf("\t\tCurrent state of Posix support is %s...\n", GEFGetAsyncSupport() ? "true" : "false"); } gef_invariants { printf("\tINVARIANTS...\n"); PrintMask(); } gef_preconditions { printf("\tPRECONDITIONS...\n"); PrintMask(); } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); PrintMask(); } gef_finalize { printf("\tFINALIZE...\n"); PrintMask(); } gef_end; printf("\t\tCurrent state of Posix support is %s...\n", GEFGetAsyncSupport() ? "true" : "false"); PrintMask(); printf("\tDONE...\n"); fflush(stdout); } #endif static void TestBreakFromTry(int threadNumber) { printf("**** Thread %d: Test Break from Try ***\n", threadNumber); gef_volatile_try { printf("\tTRY...\n"); printf("\tIssuing gef_break now...\n"); gef_break; } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestBreakFromCatch(int threadNumber) { printf("**** Thread %d: Test Break from Catch ***\n", threadNumber); gef_volatile_try { printf("\tTRY...\n"); printf("\tThrowing exception...\n"); gef_throw((void*) 0); } gef_catch(exception) { printf("\tCaught exception; issuing break...\n"); gef_break; } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestThrowFromCatch(int threadNumber) { printf("**** Thread %d: Test Throw from Catch ****\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_volatile_try { gef_volatile_try { printf("\tTRY...\n"); gef_throw((void*) 0); } gef_invariants { printf("\tINVARIANTS...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_finalize { printf("\tFINALIZE...\n"); } gef_catch(e) { printf("\tCATCH...\n"); switch((int) e) { case 0: printf("\tCaught exception, %d...\n", (int) e); printf("\tThrowing user2 violation from CATCH!\n"); gef_throw((void*) EXCEPT_USER2_VIOLATION); break; case EXCEPT_USER2_VIOLATION: printf("\tCaught user2 violation in same exception-handler...\n"); break; default: break; } } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_end; } gef_catch(e) { switch((int) e) { case EXCEPT_USER2_VIOLATION: printf("\tIgnoring user2 exception...\n"); break; default: printf("\tTest failed!\n"); break; } gef_break; } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestPreInvariantViolation(int threadNumber) { printf("*** Thread %d: Test PreInvariant Violation ***\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_volatile_try_with_invariants { gef_volatile_try { printf("\tTRY...\n"); } gef_invariants { printf("\tINVARIANTS...\n"); fflush(stdout); gef_assert_invariant(0); } gef_end; } gef_catch(e) { /* Normally, e would be an assertion object with a "Line Number" and "File Name" attribute. One would be able to print that information here, or reraise the exception. If no one catches the exception, GEF could unparse the exception, using a multinational routine and display it to the user. */ switch ((int) e) { case EXCEPT_PREINVARIANT_VIOLATION: printf("\tCaught preinvariant violation!\n"); printf("\tLine number and filename information currently"); printf(" unavailable.\n"); break; default: break; } gef_break; } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestPostInvariantViolation(int threadNumber) { int count = 0; printf("*** Thread %d: Test Post-Invariant Violation ***\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_volatile_try { gef_volatile_try_with_invariants { printf("\tTRY...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_invariants { printf("\tINVARIANTS...\n"); fflush(stdout); if (count++ > 0) { gef_assert_invariant(0); } } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_catch(e) { /* Normally, e would be an assertion object with a "Line Number" and "File Name" attribute. One would be able to print that information here, or reraise the exception. If no one catches the exception, GEF could unparse the exception, using a multinational routine and display it to the user. */ switch ((int) e) { case EXCEPT_POSTINVARIANT_VIOLATION: printf("\tCATCH...\n"); printf("\tPost-invariant violation!\n"); printf("\tLine number and filename information currently"); printf(" unavailable.\n"); break; } } gef_finalize { printf("\tFINALIZE...\n"); } gef_end; } gef_catch(e) { switch((int) e) { case EXCEPT_POSTINVARIANT_VIOLATION: printf("\tIgnoring post-invariant violation!\n"); break; default: printf("\tTest failed!\n"); break; } gef_break; } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestAssert(int threadNumber) { printf("*** Thread %d: Test Assert ***\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_volatile_try { gef_volatile_try_with_preconditions { printf("\tTRY...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); fflush(stdout); gef_assert_precondition(0); } gef_end; } gef_catch(e) { /* Normally, e would be an assertion object with a "Line Number" and "File Name" attribute. One would be able to print that information here, or reraise the exception. If no one catches the exception, GEF could unparse the exception, using a multinational routine and display it to the user. */ switch ((int) e) { case EXCEPT_ASSERTION_VIOLATION: printf("\tTestAssert: Caught assertion violation!\n"); printf("\tAssertion, line number, function, and filename information currently"); printf(" unavailable.\n"); break; case EXCEPT_PRECONDITION_VIOLATION: printf("\tTestAssert: Caught precondition violation!\n"); printf("\tAssertion, line number, function, and filename information currently"); printf(" unavailable.\n"); break; case EXCEPT_POSTCONDITION_VIOLATION: printf("\tTestAssert: Caught postcondition violation!\n"); printf("\tAssertion, line number, function, and filename information currently"); printf(" unavailable.\n"); break; case EXCEPT_PREINVARIANT_VIOLATION: printf("\tTestAssert: Caught pre-invariant violation!\n"); printf("\tAssertion, line number, function, and filename information currently"); printf(" unavailable.\n"); break; case EXCEPT_POSTINVARIANT_VIOLATION: printf("\tTestAssert: Caught post-invariant violation!\n"); printf("\tAssertion, line number, function, and filename information currently"); printf(" unavailable.\n"); break; default: printf("\tTest failed!\n"); break; } gef_break; } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestRequireInvariants(int threadNumber) { printf("*** Thread %d: Test Require Invariants ***\n", threadNumber); gef_volatile_try_with_invariants { printf("\tTRY...\n"); } gef_invariants { printf("\tINVARIANTS...\n"); fflush(stdout); } gef_preconditions { printf("\tPRECONDITIONS...\n"); fflush(stdout); } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); fflush(stdout); } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestRepeatTry(int threadNumber, int n) { printf("**** Thread %d: Test Repeat Try (%d) ****\n", threadNumber, n); printf("**** GEF is required for this test.... ***\n"); gef_volatile_repeat_try(n) { printf("\tTRY...\n"); gef_throw((void*) EXCEPT_FAILURE); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_catch(e) { if (--n == 0) gef_break; } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestTryCatch(int threadNumber, int value) { volatile int once = value; printf("**** Thread %d: Test Try, Catch, and Retry ****\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_volatile_try { printf("\tTRY...\n"); if (once) gef_throw((void*) EXCEPT_FAILURE); } gef_invariants { printf("\tINVARIANTS...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_catch(e) { printf("\tCATCH exception, %d...\n", (int) e); once = 0; gef_retry; } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void TestPostconditionViolation(int threadNumber) { printf("**** Thread %d: Test Postcondition Violation ****\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_volatile_try { gef_volatile_try_with_postconditions { printf("\tTRY...\n"); } gef_invariants { printf("\tINVARIANTS...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_catch(e) { switch((int) e) { case EXCEPT_POSTCONDITION_VIOLATION: printf("\tCaught postcondition violation, %d...\n", (int) e); printf("\tLine number and filename information currently"); printf(" unavailable.\n"); break; default: break; } } gef_finalize { printf("\tFINALIZE...\n"); } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); fflush(stdout); gef_assert_postcondition(0); } gef_end; } gef_catch(e) { switch((int) e) { case EXCEPT_POSTCONDITION_VIOLATION: printf("\tIgnoring postcondition violation!\n"); break; default: printf("\tTest failed!\n"); break; } gef_break; } gef_end; printf("\tDONE...\n"); fflush(stdout); } #ifdef GEF_POSIX static void TestDivideByZero(int threadNumber) { volatile int x = 10; printf("**** Thread %d: Test Divide By Zero ****\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_posix_try { printf("\tTRY...\n"); x = x / 0; } gef_invariants { printf("\tINVARIANTS...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_catch(e) { if (((int) e) == EXCEPT_ARITHMETIC_VIOLATION) { printf("\tCATCH exception ARITHMETIC VIOLATION...\n"); PrintMask(); gef_break; } else { printf("\tCATCH exception, %d...\n", (int) e); } } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_end; printf("\tDONE...\n"); fflush(stdout); } #endif static void TestTryCatchAndFinally(int threadNumber) { volatile int once = 1; printf("**** Thread"); printf(" %d: Test Try, Catch, Try, and Finally ****\n", threadNumber); printf("**** GEF is required for this test.... ***\n"); gef_volatile_try { printf("\tTRY...\n"); if (once) gef_throw((void*) EXCEPT_FAILURE); } gef_invariants { printf("\tINVARIANTS...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_catch(e) { printf("\tCATCH exception, %d...\n", (int) e); once = 0; gef_retry; } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_finalize { printf("\tFINALIZE...\n"); } gef_end; printf("\tDONE...\n"); fflush(stdout); } static void OutOfMemory() { gef_throw((void*) EXCEPT_INSUFFICIENT_MEMORY); } static void AssertionViolation(const char* expString, const char* fileName, const char* function, int lineNumber) { /* Normally, one would throw an object, or a pointer to a structure, that a catch block could use to obtain the line number and fileName, instead of printing information right here. */ fprintf(stderr, "\tAssertion Violation: (%s) Occurrence on", expString); fprintf(stderr, " line %d of function %s of file %s.\n", lineNumber, function, fileName); gef_throw((void*) EXCEPT_ASSERTION_VIOLATION); } static void PreconditionViolation(const char* expString, const char* fileName, const char* function, int lineNumber) { /* Can only transfer fileName, function, and lineNumber info via a pointer to a structure. For now, simply throw the integer value. */ fprintf(stderr, "\tPrecondition Violation: (%s) ", expString); fprintf(stderr, "Filename: %s\nFunction: %s\nLine number: %d\n", fileName, function, lineNumber); gef_throw((void*) EXCEPT_PRECONDITION_VIOLATION); } static void PostconditionViolation(const char* expString, const char* fileName, const char* function, int lineNumber) { /* Can only transfer fileName and lineNumber info via a pointer to a structure. For now, simply throw the integer value. */ fprintf(stderr, "Postcondition Violation: (%s) ", expString); fprintf(stderr, "Filename: %s\nFunction: %s\nLine number: %d\n", fileName, function, lineNumber); gef_throw((void*) EXCEPT_POSTCONDITION_VIOLATION); } static void PreInvariantViolation(const char* expString, const char* fileName, const char* function, int lineNumber) { /* Can only transfer fileName and lineNumber info via a pointer to a structure. For now, simply throw the integer value. */ fprintf(stderr, "Pre-Invariant Violation: (%s) ", expString); fprintf(stderr, "Filename: %s\nFunction: %s\nLine number: %d\n", fileName, function, lineNumber); gef_throw((void*) EXCEPT_PREINVARIANT_VIOLATION); } static void PostInvariantViolation(const char* expString, const char* fileName, const char* function, int lineNumber) { /* Can only transfer fileName and lineNumber info via a pointer to a structure. For now, simply throw the integer value. */ fprintf(stderr, "Post-Invariant Violation: (%s) ", expString); fprintf(stderr, "Filename: %s\nFunction: %s\nLine number: %d\n", fileName, function, lineNumber); gef_throw((void*) EXCEPT_POSTINVARIANT_VIOLATION); } static void UnhandledException(void* exceptionID) { fprintf(stderr, "\tUnhandled exception,"); fprintf(stderr, " %d, occurred, while excecuting in process, %d.\n\007\n", ((int) exceptionID), (int) getpid()); } #ifdef GEF_POSIX static void* OSSignalToException(int signum) { /* Map signum into application specific exception id, if necessary */ switch (signum) { case SIGALRM: return((void*) EXCEPT_ALARM_EXPIRED); case SIGFPE: return((void*) EXCEPT_ARITHMETIC_VIOLATION); case SIGUSR1: return((void*) EXCEPT_USER1_VIOLATION); default: return((void*) EXCEPT_OS_VIOLATION); } } #endif static void* SynchronousPerformanceMain(void* arg) { ThreadArgs_t parms = (ThreadArgs_t) arg; int exception = 0; volatile int stop = 300000; int stopold = stop; struct rusage usage; double elapsed_time = 0.0; struct timeval t1 = {0, 0}; struct timezone tz1 = {0, 0}; struct timeval t2 = {0, 0}; struct timezone tz2 = {0, 0}; #ifdef GEF_PTHREADS GEFAttr_t gefattrs; GEFAttr_Init(&gefattrs); GEFAttr_SetAssertionViolation(&gefattrs, AssertionViolation); GEFAttr_SetPreconditionViolation(&gefattrs, PreconditionViolation); GEFAttr_SetPostconditionViolation(&gefattrs, PostconditionViolation); GEFAttr_SetPreInvariantViolation(&gefattrs, PreInvariantViolation); GEFAttr_SetPostInvariantViolation(&gefattrs, PostInvariantViolation); GEFAttr_SetUnhandledException(&gefattrs, UnhandledException); GEFAttr_SetOutOfMemory(&gefattrs, OutOfMemory); #ifdef GEF_POSIX GEFAttr_SetOSSignalToException(&gefattrs, OSSignalToException); #endif GEFInitializeThread(gefattrs); #endif #ifdef GEF_POSIX if (parms->asyncSupport) gef_enable_async_support; #endif printf("Synchronous Performance Thread End!\n"); gettimeofday(&t1, NULL); while (stop > 0) { gef_try_without_finalize { stop--; } gef_end; } gettimeofday(&t2, NULL); elapsed_time = ((t2.tv_sec * 1000000 + t2.tv_usec) - (t1.tv_sec * 1000000 + t1.tv_usec)) / 1000000.0; printf("\tElapsed time (seconds) = %lf\n", elapsed_time); if (elapsed_time > 0.0) { printf("\tIterations = %d\n", stopold); printf("\tIterations per second <= %d\n", (int) (((double) stopold) / elapsed_time)); } else { printf("\tIterations per second = %d\n", (int) ((double) stopold)); } printf("Synchronous Performance Thread End!\n"); #ifdef GEF_PTHREADS pthread_exit((void*) exception); #else return((void*) exception); #endif } static void TestTryPerformance(ThreadArgs_t parms) { volatile int count = 0; volatile int seconds; int stop = 500000; int stopold = stop; clock_t begin, end; time_t beginTime, endTime; double elapsed_time; int threadNumber = parms->threadNumber; #ifdef NDEBUG stop *= 10; stopold = stop; #else if (!gef_is_enabled) { stop *= 10; stopold = stop; } #endif printf("**** Thread %d: Test to determine Try iterations per second ****\n", threadNumber); printf("**** GEF is required only when -async is true.... ***\n"); gef_volatile_try { printf("\tTRY...\n"); #ifdef GEF_POSIX if (gef_async_support_is_enabled) { #else if (0) { #endif seconds = 1; gef_begin_critical_section; #ifndef GEF_LINUX #ifdef GEF_PTHREADS pthread_mutex_lock(&signalNotificationListMutex); #if 1 signalNotificationList[threadNumber * NSIG + SIGUSR1] = 1; #else signalNotificationList[threadNumber][SIGUSR1] = 1; #endif pthread_mutex_unlock(&signalNotificationListMutex); #endif #endif printf("\tIterating for %d seconds!\n", seconds); alarm(seconds); gef_end_critical_section; printf("Checkpoint 1:\n"); while (1) { gef_volatile_try_without_finalize { count++; } gef_end; } printf("Checkpoint 1 END:\n"); } else { #ifdef CLOCK begin = clock(); beginTime = time((time_t*) NULL); printf("Checkpoint 2:\n"); while (stop > 0) { gef_try_without_finalize { stop--; } gef_end; } printf("Checkpoint 2 END:\n"); #else #ifdef GEF_PTHREADS pthread_t threadID; pthread_attr_t attr; #endif int status; int rc = EINTR; gef_volatile_try { #ifdef GEF_PTHREADS pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); #endif printf("\tTRY...\n"); gef_begin_critical_section; #ifdef GEF_PTHREADS if (pthread_create(&threadID, &attr, SynchronousPerformanceMain, (void*) parms) != 0) { gef_throw((void*) EXCEPT_FAILURE); } rc = pthread_join(threadID, (void**) &status); #else SynchronousPerformanceMain((void*) parms); #endif gef_end_critical_section; } gef_invariants { printf("\tINVARIANTS...\n"); } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_catch(exception) { switch ((int) exception) { case EXCEPT_FAILURE: fprintf(stderr, "Thread %d: Unable to create Synchronous Performance thread!\n", threadNumber); gef_break; default: break; } /* switch */ } gef_finalize { #ifdef GEF_PTHREADS pthread_attr_destroy(&attr); #endif } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_end; #endif #ifdef CLOCK end = clock(); endTime = time((time_t*) NULL); #ifdef GEF_LINUX #ifdef GEF_PTHREADS if (numberOfThreads == 1) { elapsed_time = ((double) (end - begin)) / ((double) CLOCKS_PER_SEC); } else elapsed_time = ((double) (endTime - beginTime)); #else elapsed_time = ((double) (end - begin)) / ((double) CLOCKS_PER_SEC); #endif #else elapsed_time = ((double) (end - begin)) / ((double) CLOCKS_PER_SEC); #endif #ifdef GEF_POSIX if (!gef_async_support_is_enabled) { #else if (1) { #endif printf("Checkpoint 5\n"); if (elapsed_time > 0.0) { printf("\tIterations per second <= %d\n", (int) (((double) stopold) / elapsed_time)); } else { printf("\tIterations per second <= %d\n", (int) ((double) stopold)); } printf("Checkpoint 5: END\n"); } #endif } } gef_preconditions { printf("\tPRECONDITIONS...\n"); } gef_catch(signum) { #ifndef GEF_LINUX #ifdef GEF_PTHREADS if (((int) signum) == EXCEPT_USER1_VIOLATION) { #else if (((int) signum) == EXCEPT_ALARM_EXPIRED) { #endif #else if (((int) signum) == EXCEPT_ALARM_EXPIRED) { #endif int iterations = ((double) count) / ((double) seconds); printf("\tcount = %d, seconds = %d\n", count, seconds); printf("\tIterations per second = %d\n", iterations); #ifndef GEF_LINUX #ifdef GEF_PTHREADS pthread_mutex_lock(&signalNotificationListMutex); #if 1 signalNotificationList[threadNumber * NSIG + SIGUSR1] = 0; #else signalNotificationList[threadNumber][ SIGUSR1] = 0; #endif pthread_mutex_unlock(&signalNotificationListMutex); #endif #endif gef_break; } } gef_postconditions { printf("\tPOSTCONDITIONS...\n"); } gef_end; printf("\tDONE...\n"); fflush(stdout); } static int GrowStack(int depth) { int maxDepth = 0; gef_try { if (depth > 1) { maxDepth = GrowStack(depth - 1); } else maxDepth = gef_depth; } gef_end; return(maxDepth); } static void TestStackGrowth(int threadNumber, int depth) { int currentDepth = gef_depth; int achievedDepth; printf("**** Thread %d: Test to determine stack depth.\n", threadNumber); printf("Note: When GEF is disabled, depth should be zero (0) ****\n"); achievedDepth = GrowStack(depth); printf("\tGEF exception depth is %d\n", achievedDepth - currentDepth); printf("\tDONE...\n"); fflush(stdout); } void* ThreadMain(void* arg) { int exception = 0; ThreadArgs_t parms = (ThreadArgs_t) arg; int threadNumber = parms->threadNumber; #ifdef GEF_PTHREADS GEFAttr_t gefattrs; GEFAttr_Init(&gefattrs); GEFAttr_SetAssertionViolation(&gefattrs, AssertionViolation); GEFAttr_SetUnhandledException(&gefattrs, UnhandledException); GEFAttr_SetOutOfMemory(&gefattrs, OutOfMemory); #ifdef GEF_POSIX GEFAttr_SetOSSignalToException(&gefattrs, OSSignalToException); #endif GEFInitializeThread(gefattrs); #endif #ifdef GEF_POSIX if (parms->asyncSupport) gef_enable_async_support; #endif gef_volatile_try { PrintMask(); TestBasicTry(threadNumber); TestTry(threadNumber); PrintMask(); #ifdef GEF_POSIX TestPosixTry(threadNumber); #endif PrintMask(); TestThrowFromCatch(threadNumber); PrintMask(); TestAssert(threadNumber); PrintMask(); TestPreInvariantViolation(threadNumber); PrintMask(); TestPostInvariantViolation(threadNumber); PrintMask(); TestRequireInvariants(threadNumber); PrintMask(); TestRepeatTry(threadNumber, 5); PrintMask(); TestBreakFromTry(threadNumber); PrintMask(); TestBreakFromCatch(threadNumber); PrintMask(); TestTryCatch(threadNumber, 1); PrintMask(); TestPostconditionViolation(threadNumber); PrintMask(); TestTryCatchAndFinally(threadNumber); PrintMask(); TestStackGrowth(threadNumber, 513); PrintMask(); #ifdef GEF_POSIX TestDivideByZero(threadNumber); #endif PrintMask(); TestTryPerformance(parms); PrintMask(); TestMalloc(threadNumber); PrintMask(); } gef_catch_with(e, (void*) NULL) { switch ((int) e) { #ifdef GEF_POSIX case SIGUSR1: fprintf(stderr, "Thread, %d, Interrupted!\007\n", threadNumber); gef_break; #endif case EXCEPT_ARITHMETIC_VIOLATION: fprintf(stderr, "Thread, %d, Caught late arithmetic violation!\007\n", threadNumber); gef_break; default: break; } } gef_end; #ifdef GEF_POSIX if (parms->asyncSupport) gef_disable_async_support; #endif if (exception == 0) { printf("**** Thread %d: DONE ****\n", threadNumber); fflush(stdout); } free((void*) parms); #ifdef GEF_PTHREADS pthread_exit((void*) exception); #else return((void*) exception); #endif } #ifndef GEF_LINUX #ifdef GEF_PTHREADS static void* sig_hand(void* arg) { pthread_t* parentThreadID = (pthread_t*) arg; sigset_t set; int sig; int rc; int i; /* The problem with this function is that, if a program registers for a */ /* signal, such as SIGALRM, and if two alarms arrive before this handler */ /* responds, the OS does not queue alarm calls. As a result, we have to */ /* create a timer service, which keeps track of the times for each thread */ /* When one expires, it notifies all threads whose timers have expired. */ sigfillset(&set); /* Catch all signals */ while (1) { #ifdef GEF_SOLARIS sig = sigwait(&set); #else rc = sigwait(&set, &sig); #endif if (rc == -1) { fprintf(stderr, "sigwait failed!\n"); exit(1); } switch (sig) { case SIGABRT: sigdelset(&set, SIGABRT); /* Remove SIGABRT so that we can core dump when we send it to ourselves */ pthread_sigmask(SIG_SETMASK, &set, NULL); kill(getpid(), sig); /* exit(sig); */ break; case SIGTERM: case SIGINT: case SIGQUIT: case SIGALRM: /* printf("sig_hand: Caught signal %d!\n", sig); */ for (i = 0; i < numberOfThreads; i++) { pthread_mutex_lock(&signalNotificationListMutex); #if 1 if (signalNotificationList[i * NSIG + SIGUSR1]) { (void) pthread_kill(threads[i], SIGUSR1); } #else if (signalNotificationList[i][SIGUSR1]) { (void) pthread_kill(threads[i], SIGUSR1); } #endif pthread_mutex_unlock(&signalNotificationListMutex); } break; default: printf("sig_hand: Interrupted with signal %d...exiting\n", sig); exit(0); } } } #endif #endif int main(int argc, char** argv) { #ifdef GEF_PTHREADS pthread_t sig_hand_thread; pthread_attr_t attr; pthread_t parentThreadID = pthread_self(); #endif int i = 0; int j = 0; GEFAttr_t gefattrs; #ifdef GEF_POSIX sigset_t set; sigset_t oset; #endif int rc = EINTR; int asyncSupport = 0; int syncSupport = 0; ThreadArgs_t parms; #ifdef GEF_POSIX int sentSignalToChildren = 0; sigset_t signalSet; #endif GEFInitialize(&argc, &argv); for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-async") == 0) { asyncSupport = 1; } else if (strcmp(argv[i], "-sync") == 0) { syncSupport = 1; } else if (strcmp(argv[i], "-?") == 0) { fprintf(stderr, "Usage: %s [-async] [-sync] number-of-threads\n", argv[0]); return(0); } else { fprintf(stderr, "Usage: %s [-async] [-sync] number-of-threads\n", argv[0]); return(-1); } } else { numberOfThreads = atoi(argv[i]); } } #ifdef GEF_PTHREADS if (numberOfThreads <= 0) numberOfThreads = 1; #else numberOfThreads = 1; #endif #ifndef GEF_LINUX #ifdef GEF_PTHREADS pthread_mutex_init(&signalNotificationListMutex, NULL); #endif #endif printf("%s: PID = %d\n", argv[0], getpid()); #ifdef GEF_PTHREADS threads = malloc(numberOfThreads * sizeof(pthread_t)); status = malloc(sizeof(int) * numberOfThreads); #endif threadName = malloc(numberOfThreads * sizeof(char) * 16); #ifndef GEF_LINUX #ifdef GEF_PTHREADS #if 1 signalNotificationList = malloc(sizeof(int) * numberOfThreads * NSIG); memset(signalNotificationList, '\0', sizeof(int) * NSIG * numberOfThreads); #else signalNotificationList = malloc(sizeof(signalNotificationList[0][0]) * numberOfThreads * NSIG); memset(signalNotificationList, '\0', sizeof(signalNotificationList[0][0]) * numberOfThreads * NSIG); #endif #endif #endif #ifndef GEF_LINUX #ifdef GEF_POSIX sigfillset(&set); #ifdef GEF_PTHREADS pthread_sigmask(SIG_SETMASK, &set, NULL); #else sigprocmask(SIG_SETMASK, &set, NULL); #endif #endif #endif #ifdef GEF_PTHREADS pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #endif #ifndef GEF_LINUX #ifdef GEF_PTHREADS rc= pthread_create(&sig_hand_thread, &attr, sig_hand, (void*) &parentThreadID); #endif #endif #ifdef GEF_PTHREADS pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); #endif /* Initialize GEF with the signals that you want GEF to handle for the process. */ #ifdef GEF_POSIX sigemptyset(&signalSet); #ifndef GEF_LINUX #ifdef GEF_PTHREADS sigaddset(&signalSet, SIGUSR1); #else sigaddset(&signalSet, SIGALRM); #endif #else sigaddset(&signalSet, SIGALRM); sigaddset(&signalSet, SIGQUIT); sigaddset(&signalSet, SIGINT); sigaddset(&signalSet, SIGTERM); #endif #endif #ifdef GEF_POSIX sigaddset(&signalSet, SIGFPE); GEFInitializeSignals(signalSet); #endif /* Initialize the specific call-backs, if any, for this thread. */ GEFAttr_Init(&gefattrs); GEFAttr_SetAssertionViolation(&gefattrs, AssertionViolation); GEFAttr_SetUnhandledException(&gefattrs, UnhandledException); GEFAttr_SetOutOfMemory(&gefattrs, OutOfMemory); #ifdef GEF_POSIX GEFAttr_SetOSSignalToException(&gefattrs, OSSignalToException); #endif GEFInitializeThread(gefattrs); #ifndef GEF_LINUX #ifdef GEF_PTHREADS #ifdef GEF_POSIX pthread_sigmask(SIG_SETMASK, &set, &oset); #endif #else #ifdef GEF_POSIX sigprocmask(SIG_SETMASK, &set, &oset); #endif #endif #endif #if 0 printf("%s: Number of threads is %d.\n", argv[0], numberOfThreads); #endif for (i = 0; i < numberOfThreads; i++) { sprintf(&threadName[i * 16], "%d", i + 1); parms = malloc(sizeof(*parms)); parms->threadNumber = i; if (syncSupport && asyncSupport) { if (parms->threadNumber % 2) { parms->asyncSupport = 1; } else parms->asyncSupport = 0; } else if (asyncSupport) { parms->asyncSupport = 1; } else parms->asyncSupport = 0; #ifdef GEF_PTHREADS if (pthread_create(&threads[i], &attr, ThreadMain, (void*) parms) != 0) { numberOfThreads = i; fprintf(stderr, "%s: Could only create %d threads!\n", argv[0], numberOfThreads); break; } #endif } #ifndef GEF_LINUX #ifdef GEF_PTHREADS #ifdef GEF_POSIX pthread_sigmask(SIG_SETMASK, &oset, NULL); #endif #else #ifdef GEF_POSIX sigprocmask(SIG_SETMASK, &oset, NULL); #endif #endif #endif #ifndef GEF_PTHREADS ThreadMain((void*) parms); #endif #ifdef GEF_POSIX gef_enable_async_support; #endif #ifdef GEF_PTHREADS j = 0; gef_try { for (; j < i; j++) { gef_begin_critical_section; rc = pthread_join(threads[j], (void**) &status[j]); if (rc == 0) { printf("\n%s: Thread %d returned with status %d\n\n", argv[0], j, status[j]); } else fprintf(stderr, "%s: Join with thread %d failed!\n", argv[0], j); gef_end_critical_section; } } gef_catch(e) { fprintf(stderr, "%s: Exception, %d, occurred while joining with thread, %d, ...ignoring.\n", argv[0], e, j); if (rc != EINTR) { /* This means that the thread did not enter the critical section. */ j++; } rc = EINTR; gef_retry; } gef_end; #endif #ifndef GEF_LINUX #ifdef GEF_PTHREADS pthread_attr_destroy(&attr); pthread_mutex_destroy(&signalNotificationListMutex); #endif #endif #ifdef GEF_PTHREADS free((void*) threadName); free((void*) status); #endif #ifndef GEF_LINUX #ifdef GEF_PTHREADS free((void*) signalNotificationList); #endif #endif return(0); }