diff options
author | Albert Cheng <acheng@hdfgroup.org> | 2010-04-28 19:56:29 (GMT) |
---|---|---|
committer | Albert Cheng <acheng@hdfgroup.org> | 2010-04-28 19:56:29 (GMT) |
commit | 2bf52ee03ef0a1f8663d40b1ac0f8fe2d4934720 (patch) | |
tree | 9491fccce38c18b3f102485914e6516ab2fa5528 /src/H5detect.c | |
parent | fadbd8866f5741da77a369fd015c82db5b191294 (diff) | |
download | hdf5-2bf52ee03ef0a1f8663d40b1ac0f8fe2d4934720.zip hdf5-2bf52ee03ef0a1f8663d40b1ac0f8fe2d4934720.tar.gz hdf5-2bf52ee03ef0a1f8663d40b1ac0f8fe2d4934720.tar.bz2 |
[svn-r18659] Bug: 1764
Description:
longjmp do not necessary restore signal that is blocked during the signal
handling. This caused the Alignment test to fail quietly, resulting in wrong
alignment information which will cause failures later.
Solution:
One can use sigsetjmp/siglongjmp to restore signal handling but not all systems
such as Cray XT or VMS supports sigsetjmp. Backup solution is to use
sigprocmask to reset the signal. Again, some systems may not support it either.
Added code to try the first and then the second solution. Also added tests
to verify if the signal_handler routines are working properly. Finally, added
code to print results of the verification (in form of comments) to H5Tinit.c
for inspection in case of failure.
(Note that many platforms do not have alignment limits at all and ALIGNMNET
code never raise the SIGBUS or SIGSEGV errors. In those cases, it does not
matter whether the signal handlers work or not. Again, this can be deduced
from the results comments near the end of the H5Tinit.c. If the sum of signal
handlers called equals the total of verify, it means ALIGNMENT does not raise
any signals.)
For configure.in and configure:
Added the test for setjmp, sigsetjmp, sigprocmask which are used by the
H5detec.c.
Tested:
htcommittested, jam(serial).
Diffstat (limited to 'src/H5detect.c')
-rw-r--r-- | src/H5detect.c | 259 |
1 files changed, 194 insertions, 65 deletions
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 */ |