summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/H5config.h.in9
-rw-r--r--src/H5detect.c259
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 */