diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5config.h.in | 9 | ||||
-rw-r--r-- | src/H5detect.c | 259 |
2 files changed, 203 insertions, 65 deletions
diff --git a/src/H5config.h.in b/src/H5config.h.in index ef072de..8210f38 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -253,6 +253,9 @@ /* Define to 1 if you have the `rand_r' function. */ #undef HAVE_RAND_R +/* Define to 1 if you have the `setjmp' function. */ +#undef HAVE_SETJMP + /* Define to 1 if you have the <setjmp.h> header file. */ #undef HAVE_SETJMP_H @@ -265,6 +268,12 @@ /* Define to 1 if you have the `signal' function. */ #undef HAVE_SIGNAL +/* Define to 1 if you have the `sigprocmask' function. */ +#undef HAVE_SIGPROCMASK + +/* Define to 1 if you have the `sigsetjmp' function. */ +#undef HAVE_SIGSETJMP + /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF diff --git a/src/H5detect.c b/src/H5detect.c index ac1185f..1cfce96 100644 --- a/src/H5detect.c +++ b/src/H5detect.c @@ -59,6 +59,32 @@ static const char *FileHeader = "\n\ #include "H5Rpublic.h" #define MAXDETECT 64 + +/* The ALIGNMENT test code may generate the SIGBUS or SIGSEGV signals. We use + * setjmp/longjmp in the signal handlers for recovery. But setjmp/longjmp do + * not necessary restore the signal blocking status while sigsetjmp/siglongjmp + * do. If sigsetjmp/siglongjmp are not supported, need to use sigprocmask to + * unblock the signal before doing longjmp. + */ +/* Define H5SETJMP/H5LONGJMP depending on if sigsetjmp/siglongjmp are */ +/* supported. */ +#if defined(H5_HAVE_SIGSETJMP) && defined(H5_HAVE_SIGLONGJMP) +/* Always save blocked signals to be restore by siglongjmp. */ +#define H5JMP_BUF sigjmp_buf +#define H5SETJMP(buf) sigsetjmp(buf, 1) +#define H5LONGJMP(buf, val) siglongjmp(buf, val) +#define H5HAVE_SIGJMP # sigsetjmp/siglongjmp are supported. +#elif defined(H5_HAVE_LONGJMP) +#define H5JMP_BUF jmp_buf +#define H5SETJMP(buf) setjmp(buf) +#define H5LONGJMP(buf, val) longjmp(buf, val) +#endif + +/* ALIGNMENT and signal-handling status codes */ +#define STA_NoALIGNMENT 0x0001 /* No ALIGNMENT Test */ +#define STA_NoHandlerVerify 0x0002 /* No signal handler Tests */ + + /* * This structure holds information about a type that * was detected. @@ -109,7 +135,16 @@ static void detect_C99_integers32(void); static void detect_C99_integers64(void); static void detect_alignments(void); static size_t align_g[] = {1, 2, 4, 8, 16}; -static jmp_buf jbuf_g; +static int align_status_g = 0; /* ALIGNMENT Signal Status */ +static int sigbus_handler_called_g = 0; /* how many times called */ +static int sigsegv_handler_called_g = 0; /* how many times called */ +static int signal_handler_tested_g = 0; /* how many times tested */ +#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL) +static int verify_signal_handlers(int signum, void (*handler)(int)); +#endif +#ifdef H5JMP_BUF +static H5JMP_BUF jbuf_g; +#endif /*------------------------------------------------------------------------- @@ -350,20 +385,20 @@ precision (detected_t *d) COMP_ALIGN = (size_t)((char*)(&(s.x)) - (char*)(&s)); \ } -#if defined(H5_HAVE_LONGJMP) && defined(H5_HAVE_SIGNAL) +#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL) #define ALIGNMENT(TYPE,INFO) { \ char *volatile _buf = NULL; \ volatile TYPE _val = 1; \ volatile TYPE _val2; \ volatile size_t _ano = 0; \ - void (*_handler)(int) = signal(SIGBUS, sigbus_handler); \ - void (*_handler2)(int) = signal(SIGSEGV, sigsegv_handler); \ + void (*_handler)(int) = HDsignal(SIGBUS, sigbus_handler); \ + void (*_handler2)(int) = HDsignal(SIGSEGV, sigsegv_handler);\ \ _buf = (char*)malloc(sizeof(TYPE) + align_g[NELMTS(align_g) - 1]); \ - if(setjmp(jbuf_g)) _ano++; \ + if(H5SETJMP(jbuf_g)) _ano++; \ if(_ano < NELMTS(align_g)) { \ - *((TYPE*)(_buf+align_g[_ano])) = _val; /*possible SIGBUS or SEGSEGV*/ \ - _val2 = *((TYPE*)(_buf+align_g[_ano])); /*possible SIGBUS or SEGSEGV*/ \ + *((TYPE*)(_buf+align_g[_ano])) = _val; /*possible SIGBUS or SEGSEGV*/ \ + _val2 = *((TYPE*)(_buf+align_g[_ano])); /*possible SIGBUS or SEGSEGV*/\ /* Cray Check: This section helps detect alignment on Cray's */ \ /* vector machines (like the SV1) which mask off */ \ /* pointer values when pointing to non-word aligned */ \ @@ -377,7 +412,7 @@ precision (detected_t *d) memcpy(_buf+align_g[_ano]+(INFO.offset/8),((char *)&_val)+(INFO.offset/8),(size_t)(INFO.precision/8)); \ _val2 = *((TYPE*)(_buf+align_g[_ano])); \ if(_val!=_val2) \ - longjmp(jbuf_g, 1); \ + H5LONGJMP(jbuf_g, 1); \ /* End Cray Check */ \ (INFO.align)=align_g[_ano]; \ } else { \ @@ -385,61 +420,18 @@ precision (detected_t *d) fprintf(stderr, "unable to calculate alignment for %s\n", #TYPE); \ } \ free(_buf); \ - signal(SIGBUS, _handler); /*restore original handler*/ \ - signal(SIGSEGV, _handler2); /*restore original handler*/ \ + HDsignal(SIGBUS, _handler); /*restore original handler*/ \ + HDsignal(SIGSEGV, _handler2); /*restore original handler*/ \ } #else -#define ALIGNMENT(TYPE,INFO) (INFO.align)=0 -#endif - -#if 0 -#if defined(H5_HAVE_FORK) && defined(H5_HAVE_WAITPID) #define ALIGNMENT(TYPE,INFO) { \ - char *_buf; \ - TYPE _val=0; \ - size_t _ano; \ - pid_t _child; \ - int _status; \ - \ - srand((unsigned int)_val); /*suppress "set but unused" warning*/ \ - for (_ano=0; _ano<NELMTS(align_g); _ano++) { \ - fflush(stdout); \ - fflush(stderr); \ - if (0==(_child=fork())) { \ - _buf = malloc(sizeof(TYPE)+align_g[NELMTS(align_g)-1]); \ - *((TYPE*)(_buf+align_g[_ano])) = _val; \ - _val = *((TYPE*)(_buf+align_g[_ano])); \ - free(_buf); \ - exit(0); \ - } else if (_child<0) { \ - perror("fork"); \ - exit(1); \ - } \ - if (waitpid(_child, &_status, 0)<0) { \ - perror("waitpid"); \ - exit(1); \ - } \ - if (WIFEXITED(_status) && 0==WEXITSTATUS(_status)) { \ - INFO.align=align_g[_ano]; \ - break; \ - } \ - if (WIFSIGNALED(_status) && SIGBUS==WTERMSIG(_status)) { \ - continue; \ - } \ - _ano=NELMTS(align_g); \ - break; \ - } \ - if (_ano>=NELMTS(align_g)) { \ - INFO.align=0; \ - fprintf(stderr, "unable to calculate alignment for %s\n", #TYPE); \ - } \ + align_status_g |= STA_NoALIGNMENT; \ + (INFO.align)=0; \ } -#else -#define ALIGNMENT(TYPE,INFO) (INFO.align)=0 -#endif #endif +#if defined(H5LONGJMP) && defined(H5_HAVE_SIGNAL) /*------------------------------------------------------------------------- * Function: sigsegv_handler * @@ -448,7 +440,7 @@ precision (detected_t *d) * it's not nearly as nice to work with, it does the job for * this simple stuff. * - * Return: Returns via longjmp to jbuf_g. + * Return: Returns via H5LONGJMP to jbuf_g. * * Programmer: Robb Matzke * Thursday, March 18, 1999 @@ -460,11 +452,24 @@ precision (detected_t *d) static void sigsegv_handler(int UNUSED signo) { - signal(SIGSEGV, sigsegv_handler); - longjmp(jbuf_g, 1); +#if !defined(H5HAVE_SIGJMP) && defined(H5_HAVE_SIGPROCMASK) + /* Use sigprocmask to unblock the signal if sigsetjmp/siglongjmp are not */ + /* supported. */ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGSEGV); + sigprocmask(SIG_UNBLOCK, &set, NULL); +#endif + + sigsegv_handler_called_g++; + HDsignal(SIGSEGV, sigsegv_handler); + H5LONGJMP(jbuf_g, SIGSEGV); } +#endif +#if defined(H5LONGJMP) && defined(H5_HAVE_SIGNAL) /*------------------------------------------------------------------------- * Function: sigbus_handler * @@ -473,7 +478,7 @@ sigsegv_handler(int UNUSED signo) * it's not nearly as nice to work with, it does the job for * this simple stuff. * - * Return: Returns via longjmp to jbuf_g. + * Return: Returns via H5LONGJMP to jbuf_g. * * Programmer: Robb Matzke * Thursday, March 18, 1999 @@ -485,12 +490,21 @@ sigsegv_handler(int UNUSED signo) static void sigbus_handler(int UNUSED signo) { - signal(SIGBUS, sigbus_handler); - longjmp(jbuf_g, 1); -#ifdef H5_HAVE_SIGLONGJMP - siglongjmp(jbuf_g, 1); -#endif /* H5_HAVE_SIGLONGJMP */ +#if !defined(H5HAVE_SIGJMP) && defined(H5_HAVE_SIGPROCMASK) + /* Use sigprocmask to unblock the signal if sigsetjmp/siglongjmp are not */ + /* supported. */ + sigset_t set; + + HDsigemptyset(&set); + HDsigaddset(&set, SIGBUS); + HDsigprocmask(SIG_UNBLOCK, &set, NULL); +#endif + + sigbus_handler_called_g++; + HDsignal(SIGBUS, sigbus_handler); + H5LONGJMP(jbuf_g, SIGBUS); } +#endif /*------------------------------------------------------------------------- @@ -574,6 +588,7 @@ print_results(int nd, detected_t *d, int na, malign_t *misc_align) /*******************/\n\ \n"); + /* The interface initialization function */ printf("\n\ \n\ @@ -721,6 +736,57 @@ done:\n\ } /* end if */\n\ \n\ FUNC_LEAVE_NOAPI(ret_value);\n} /* end H5TN_init_interface() */\n"); + + /* Print the ALIGNMENT and signal-handling status as comments */ + printf("\n" + "/****************************************/\n" + "/* ALIGNMENT and signal-handling status */\n" + "/****************************************/\n"); + if (align_status_g & STA_NoALIGNMENT) + printf("/* ALIGNAMENT test is not available */\n"); + if (align_status_g & STA_NoHandlerVerify) + printf("/* Signal handlers verify test is not available */\n"); + /* The following is available in H5pubconf.h. Printing them here for */ + /* convenience. */ +#ifdef H5_HAVE_SIGNAL + printf("/* Signal() support: yes */\n"); +#else + printf("/* Signal() support: no */\n"); +#endif +#ifdef H5_HAVE_SETJMP + printf("/* setjmp() support: yes */\n"); +#else + printf("/* setjmp() support: no */\n"); +#endif +#ifdef H5_HAVE_LONGJMP + printf("/* longjmp() support: yes */\n"); +#else + printf("/* longjmp() support: no */\n"); +#endif +#ifdef H5_HAVE_SIGSETJMP + printf("/* sigsetjmp() support: yes */\n"); +#else + printf("/* sigsetjmp() support: no */\n"); +#endif +#ifdef H5_HAVE_SIGLONGJMP + printf("/* siglongjmp() support: yes */\n"); +#else + printf("/* siglongjmp() support: no */\n"); +#endif +#ifdef H5_HAVE_SIGPROCMASK + printf("/* sigprocmask() support: yes */\n"); +#else + printf("/* sigprocmask() support: no */\n"); +#endif + + /* Print the statics of signal handlers called for debugging */ + printf("\n" + "/******************************/\n" + "/* signal handlers statistics */\n" + "/******************************/\n"); + printf("/* signal_handlers tested: %d times */\n", signal_handler_tested_g); + printf("/* sigbus_handler called: %d times */\n", sigbus_handler_called_g); + printf("/* sigsegv_handler called: %d times */\n", sigsegv_handler_called_g); } /* end print_results() */ @@ -1485,6 +1551,55 @@ detect_alignments(void) } +#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL) +/* Verify the signal handler for signal signum works correctly multiple times. + * One possible cause of failure is that the signal handling is blocked or + * changed to SIG_DFL after H5LONGJMP. + * Return 0 for success, -1 for failure. + */ +static int verify_signal_handlers(int signum, void (*handler)(int)) +{ + void (*save_handler)(int) = HDsignal(signum, handler); + int i, val; + int ntries=5; + volatile int nfailures=0; + volatile int nsuccesses=0; + + for (i=0;i<ntries; i++){ + val=H5SETJMP(jbuf_g); + if (val==0) + { + /* send self the signal to trigger the handler */ + signal_handler_tested_g++; + HDraise(signum); + /* Should not reach here. Record error. */ + nfailures++; + }else{ + if (val==signum){ + /* return from signum handler. Record a sucess. */ + nsuccesses++; + }else{ + fprintf(stderr, "Unknown return value (%d) from H5SETJMP", + val); + nfailures++; + } + } + } + /* restore save handler, check results and report failures */ + HDsignal(signum, save_handler); + if (nfailures>0 || nsuccesses != ntries){ + fprintf(stderr, "verify_signal_handlers for signal %d did %d tries. " + "Found %d failures and %d successes\n", + signum, ntries, nfailures, nsuccesses); + return(-1); + }else{ + /* all succeeded */ + return(0); + } +} +#endif + + /*------------------------------------------------------------------------- * Function: main * @@ -1527,6 +1642,20 @@ main(void) #endif #endif +#if defined(H5SETJMP) && defined(H5_HAVE_SIGNAL) + /* verify the SIGBUS and SIGSEGV handlers work properly */ + if (verify_signal_handlers (SIGBUS, sigbus_handler) != 0){ + fprintf(stderr, "Signal handler %s for signal %d failed\n", + "sigbus_handler", SIGBUS); + } + if (verify_signal_handlers (SIGSEGV, sigsegv_handler) != 0){ + fprintf(stderr, "Signal handler %s for signal %d failed\n", + "sigsegv_handler", SIGSEGV); + } +#else + align_status_g |= STA_NoHandlerVerify; +#endif + print_header(); /* C89 integer types */ |