From 168d67dbd20923feef30fb76c6b569ef2e5add4a Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 7 Feb 2003 16:14:19 -0500 Subject: [svn-r6383] Purpose: New feature for developers. Description: Added "function stack" tracing to library. This allows developers (there is no public API) to call H5FS_print within the library and get a listing of the functions traversed to reach that point in the library. Eventually, I may add support for reporting the parameters to each function also... Mainly for debugging parallel I/O programs, but I think it will come in handy in other cases also. The function stack tracking is controlled with a configure switch: --enable-funcstack, which defaults to enabled currently. When we branch for 1.6, we should change the default setting on the branch to be disabled. Also, added a destructor to the thread-specific keys when thread-safety is turned on in the library. Otherwise, they were leaking memory and causing difficult to debug errors in threaded programs (like the test/ttsafe test). Platforms tested: Tested h5committest {arabica (fortran), eirene (fortran, C++) modi4 (parallel, fortran)} FreeBSD 4.7 (sleipnir) w/thread-safety enabled. Misc. update: Updated MANIFEST with new files added (src/H5FS.c & src/H5FDprivate.h) Update release_docs/RELEASE with thread-safety bug fix. --- MANIFEST | 2 + configure | 37 +++++++- configure.in | 25 ++++++ release_docs/RELEASE.txt | 2 + src/H5CS.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++ src/H5CSprivate.h | 40 +++++++++ src/H5FS.c | 223 ++++++++++++++++++++++++++++++++++++++++++++++ src/H5FSprivate.h | 40 +++++++++ src/H5TS.c | 73 ++++++++------- src/H5TSprivate.h | 1 + src/H5config.h.in | 9 +- src/H5private.h | 53 +++++++++-- src/Makefile.in | 17 ++-- test/bittests.c | 12 +++ test/hyperslab.c | 12 +++ test/ttsafe_cancel.c | 4 +- test/ttsafe_dcreate.c | 226 ++++++++++++++++++++++++----------------------- test/ttsafe_error.c | 3 + 18 files changed, 834 insertions(+), 168 deletions(-) create mode 100644 src/H5CS.c create mode 100644 src/H5CSprivate.h create mode 100644 src/H5FS.c create mode 100644 src/H5FSprivate.h diff --git a/MANIFEST b/MANIFEST index dd9f3c8..cd8ea04 100644 --- a/MANIFEST +++ b/MANIFEST @@ -840,6 +840,8 @@ ./src/H5FPprivate.h ./src/H5FPpublic.h ./src/H5FPserver.c +./src/H5FS.c +./src/H5FSprivate.h ./src/H5G.c ./src/H5Gent.c ./src/H5Gnode.c diff --git a/configure b/configure index 34ca1c4..c0a7674 100755 --- a/configure +++ b/configure @@ -1008,6 +1008,7 @@ Optional Features: --enable-linux-lfs Enable support for large (64-bit) files on Linux. [default=check] --enable-threadsafe Enable thread safe capability + --enable-funcstack Enable the function stack tracing [default=yes] --enable-hdf5v1_4 Compile the HDF5 v1.4 compatibility interface [default=no] --enable-stream-vfd Build the Stream Virtual File Driver [default=no] @@ -4107,7 +4108,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 4110 "configure"' > conftest.$ac_ext + echo '#line 4111 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -4648,7 +4649,7 @@ chmod -w . save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" compiler_c_o=no -if { (eval echo configure:4651: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then +if { (eval echo configure:4652: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s out/conftest.err; then @@ -6459,7 +6460,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5 +echo $ECHO_N "checking whether function stack tracking is enabled... $ECHO_C" >&6 +# Check whether --enable-funcstack or --disable-funcstack was given. +if test "${enable_funcstack+set}" = set; then + enableval="$enable_funcstack" + FUNCSTACK=$enableval +fi; + +case "X-$FUNCSTACK" in + X-|X-yes) + FUNCSTACK="yes" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_FUNCSTACK 1 +_ACEOF + + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; +esac + echo "$as_me:$LINENO: checking whether HDF5 v1.4 compatibility functions enabled" >&5 echo $ECHO_N "checking whether HDF5 v1.4 compatibility functions enabled... $ECHO_C" >&6 # Check whether --enable-hdf5v1_4 or --disable-hdf5v1_4 was given. @@ -32010,5 +32036,8 @@ IF_ENABLED_DISABLED "$STREAM_VFD" PRINT_N " Threadsafety" IF_ENABLED_DISABLED "$THREADSAFE" +PRINT_N " Function Stack Tracing" +IF_ENABLED_DISABLED "$FUNCSTACK" + PRINT_N " Zlib-compression" IF_YES_NO "$HAVE_ZLIB" diff --git a/configure.in b/configure.in index af929fe..8d689e0 100644 --- a/configure.in +++ b/configure.in @@ -1224,6 +1224,28 @@ if test "X$THREADSAFE" = "Xyes"; then fi dnl ---------------------------------------------------------------------- +dnl Check if they would like the function stack support compiled in +dnl +AC_MSG_CHECKING([whether function stack tracking is enabled]) +AC_ARG_ENABLE([funcstack], + [AC_HELP_STRING([--enable-funcstack], + [Enable the function stack + tracing [default=yes]])], + [FUNCSTACK=$enableval]) + +case "X-$FUNCSTACK" in + X-|X-yes) + FUNCSTACK="yes" + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_FUNCSTACK], [1], + [Define if the function stack tracing code is to be compiled in]) + ;; + *) + AC_MSG_RESULT([no]) + ;; +esac + +dnl ---------------------------------------------------------------------- dnl Check if they would like the HDF5 v1.4 compatibility functions dnl compiled in dnl @@ -2302,5 +2324,8 @@ IF_ENABLED_DISABLED "$STREAM_VFD" PRINT_N " Threadsafety" IF_ENABLED_DISABLED "$THREADSAFE" +PRINT_N " Function Stack Tracing" +IF_ENABLED_DISABLED "$FUNCSTACK" + PRINT_N " Zlib-compression" IF_YES_NO "$HAVE_ZLIB" diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 4c0115b..38a5a75 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -35,6 +35,8 @@ Bug Fixes since HDF5-1.4.0 Library ------- + * Corrected memory/resource leaks in per-thread key information when + thread-safe operation was enabled. QAK - 2003/02/07 * H5Fopen without the H5F_ACC_CREAT flag should not succeed in creating a new file with the 'core' VFL driver. QAK - 2003/01/24 * Allow opening objects with unknown object header messages. diff --git a/src/H5CS.c b/src/H5CS.c new file mode 100644 index 0000000..b523251 --- /dev/null +++ b/src/H5CS.c @@ -0,0 +1,223 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: Provides internal function tracing in the form of a stack. + * The FUNC_ENTER() macro adds the function name to the function + * stack whenever a function is entered. + * As the functions return with FUNC_LEAVE, + * entries are removed from the stack. + * + * A function stack has a fixed maximum size. If this size is + * exceeded then the stack will be truncated and only the + * first called functions will have entries on the stack. This is + * expected to be a rare condition. + * + * Each thread has its own function stack, but since + * multi-threading has not been added to the library yet, this + * package maintains a single function stack. The function stack + * is statically allocated to reduce the complexity of handling + * errors within the H5FS package. + * + */ +#include "H5private.h" /* Generic Functions */ +#include "H5FSprivate.h" /* Private function stack routines */ +#include "H5MMprivate.h" /* Memory management functions */ + +#ifdef H5_HAVE_FUNCSTACK + +#define PABLO_MASK H5FS_mask + +/* Interface initialization? */ +#define INTERFACE_INIT NULL + +#ifdef H5_HAVE_THREADSAFE +/* + * The per-thread function stack. pthread_once() initializes a special + * key that will be used by all threads to create a stack specific to + * each thread individually. The association of stacks to threads will + * be handled by the pthread library. + * + * In order for this macro to work, H5FS_get_my_stack() must be preceeded + * by "H5FS_t *fstack =". + */ +static H5FS_t *H5FS_get_stack(void); +#define H5FS_get_my_stack() H5FS_get_stack() +#else /* H5_HAVE_THREADSAFE */ +/* + * The function stack. Eventually we'll have some sort of global table so each + * thread has it's own stack. The stacks will be created on demand when the + * thread first calls H5FS_push(). */ +H5FS_t H5FS_stack_g[1]; +#define H5FS_get_my_stack() (H5FS_stack_g+0) +#endif /* H5_HAVE_THREADSAFE */ + + +#ifdef H5_HAVE_THREADSAFE +/*------------------------------------------------------------------------- + * Function: H5FS_get_stack + * + * Purpose: Support function for H5FS_get_my_stack() to initialize and + * acquire per-thread function stack. + * + * Return: Success: function stack (H5FS_t *) + * + * Failure: NULL + * + * Programmer: Quincey Koziol + * February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static H5FS_t * +H5FS_get_stack(void) +{ + H5FS_t *fstack; + + FUNC_ENTER_NOAPI_NOFS(H5FS_get_stack); + + fstack = pthread_getspecific(H5TS_funcstk_key_g); + if (!fstack) { + /* no associated value with current thread - create one */ + fstack = (H5FS_t *)H5MM_malloc(sizeof(H5FS_t)); + pthread_setspecific(H5TS_funcstk_key_g, (void *)fstack); + } + + FUNC_LEAVE_NOAPI_NOFS(fstack); +} /* end H5FS_get_stack() */ +#endif /* H5_HAVE_THREADSAFE */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_print + * + * Purpose: Prints the function stack in some default way. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * THursday, February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_print(FILE *stream) +{ + H5FS_t *fstack = H5FS_get_my_stack (); /* Get the correct function stack */ + const int indent = 2; /* Indention level */ + int i; /* Local index ariable */ + + /* Don't push this function on the function stack... :-) */ + FUNC_ENTER_NOAPI_NOFS(H5FS_print); + + /* Sanity check */ + assert(fstack); + + /* Default to outputting information to stderr */ + if (!stream) + stream = stderr; + + HDfprintf (stream, "HDF5-DIAG: Function stack from %s ", H5_lib_vers_info_g); + /* try show the process or thread id in multiple processes cases*/ +#ifdef H5_HAVE_THREADSAFE + HDfprintf (stream, "thread %d.", (int)pthread_self()); +#else /* H5_HAVE_THREADSAFE */ + HDfprintf (stream, "thread 0."); +#endif /* H5_HAVE_THREADSAFE */ + if (fstack && fstack->nused>0) + HDfprintf (stream, " Back trace follows."); + HDfputc ('\n', stream); + + for (i=fstack->nused-1; i>=0; --i) + HDfprintf(stream, "%*s#%03d: Routine: %s\n", indent, "", i, fstack->slot[i]); + + FUNC_LEAVE_NOAPI_NOFS(SUCCEED); +} /* end H5FS_print() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_push + * + * Purpose: Pushes a new record onto function stack for the current + * thread. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_push(const char *func_name) +{ + H5FS_t *fstack = H5FS_get_my_stack (); + + /* Don't push this function on the function stack... :-) */ + FUNC_ENTER_NOAPI_NOFS(H5FS_push); + + /* Sanity check */ + assert (fstack); + assert (func_name); + + /* + * Push the function if there's room. Otherwise just increment count + */ + if (fstack->nusedslot[fstack->nused] = func_name; + fstack->nused++; + + FUNC_LEAVE_NOAPI_NOFS(SUCCEED); +} /* end H5FS_push() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_pop + * + * Purpose: Pops a record off function stack for the current thread. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_pop(void) +{ + H5FS_t *fstack = H5FS_get_my_stack (); + + /* Don't push this function on the function stack... :-) */ + FUNC_ENTER_NOAPI_NOFS(H5FS_pop); + + /* Sanity check */ + assert (fstack); + assert (fstack->nused>0); + + /* Pop the function. */ + fstack->nused--; + + FUNC_LEAVE_NOAPI_NOFS(SUCCEED); +} /* end H5FS_pop() */ + +#endif /* H5_HAVE_FUNCSTACK */ diff --git a/src/H5CSprivate.h b/src/H5CSprivate.h new file mode 100644 index 0000000..6dba575 --- /dev/null +++ b/src/H5CSprivate.h @@ -0,0 +1,40 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Header file for function stacks, etc. + */ +#ifndef _H5FSprivate_H +#define _H5FSprivate_H + +#ifdef NOT_YET +#include "H5FSpublic.h" +#endif /* NOT_YET */ + +/* Private headers needed by this file */ +#include "H5private.h" + +#define H5FS_NSLOTS 32 /*number of slots in an function stack */ + +/* A function stack */ +typedef struct H5FS_t { + int nused; /*num slots currently used in stack */ + const char *slot[H5FS_NSLOTS]; /*array of function records */ +} H5FS_t; + +H5_DLL herr_t H5FS_push (const char *func_name); +H5_DLL herr_t H5FS_pop (void); +H5_DLL herr_t H5FS_print (FILE *stream); + +#endif /* _H5FSprivate_H */ diff --git a/src/H5FS.c b/src/H5FS.c new file mode 100644 index 0000000..b523251 --- /dev/null +++ b/src/H5FS.c @@ -0,0 +1,223 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: Provides internal function tracing in the form of a stack. + * The FUNC_ENTER() macro adds the function name to the function + * stack whenever a function is entered. + * As the functions return with FUNC_LEAVE, + * entries are removed from the stack. + * + * A function stack has a fixed maximum size. If this size is + * exceeded then the stack will be truncated and only the + * first called functions will have entries on the stack. This is + * expected to be a rare condition. + * + * Each thread has its own function stack, but since + * multi-threading has not been added to the library yet, this + * package maintains a single function stack. The function stack + * is statically allocated to reduce the complexity of handling + * errors within the H5FS package. + * + */ +#include "H5private.h" /* Generic Functions */ +#include "H5FSprivate.h" /* Private function stack routines */ +#include "H5MMprivate.h" /* Memory management functions */ + +#ifdef H5_HAVE_FUNCSTACK + +#define PABLO_MASK H5FS_mask + +/* Interface initialization? */ +#define INTERFACE_INIT NULL + +#ifdef H5_HAVE_THREADSAFE +/* + * The per-thread function stack. pthread_once() initializes a special + * key that will be used by all threads to create a stack specific to + * each thread individually. The association of stacks to threads will + * be handled by the pthread library. + * + * In order for this macro to work, H5FS_get_my_stack() must be preceeded + * by "H5FS_t *fstack =". + */ +static H5FS_t *H5FS_get_stack(void); +#define H5FS_get_my_stack() H5FS_get_stack() +#else /* H5_HAVE_THREADSAFE */ +/* + * The function stack. Eventually we'll have some sort of global table so each + * thread has it's own stack. The stacks will be created on demand when the + * thread first calls H5FS_push(). */ +H5FS_t H5FS_stack_g[1]; +#define H5FS_get_my_stack() (H5FS_stack_g+0) +#endif /* H5_HAVE_THREADSAFE */ + + +#ifdef H5_HAVE_THREADSAFE +/*------------------------------------------------------------------------- + * Function: H5FS_get_stack + * + * Purpose: Support function for H5FS_get_my_stack() to initialize and + * acquire per-thread function stack. + * + * Return: Success: function stack (H5FS_t *) + * + * Failure: NULL + * + * Programmer: Quincey Koziol + * February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static H5FS_t * +H5FS_get_stack(void) +{ + H5FS_t *fstack; + + FUNC_ENTER_NOAPI_NOFS(H5FS_get_stack); + + fstack = pthread_getspecific(H5TS_funcstk_key_g); + if (!fstack) { + /* no associated value with current thread - create one */ + fstack = (H5FS_t *)H5MM_malloc(sizeof(H5FS_t)); + pthread_setspecific(H5TS_funcstk_key_g, (void *)fstack); + } + + FUNC_LEAVE_NOAPI_NOFS(fstack); +} /* end H5FS_get_stack() */ +#endif /* H5_HAVE_THREADSAFE */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_print + * + * Purpose: Prints the function stack in some default way. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * THursday, February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_print(FILE *stream) +{ + H5FS_t *fstack = H5FS_get_my_stack (); /* Get the correct function stack */ + const int indent = 2; /* Indention level */ + int i; /* Local index ariable */ + + /* Don't push this function on the function stack... :-) */ + FUNC_ENTER_NOAPI_NOFS(H5FS_print); + + /* Sanity check */ + assert(fstack); + + /* Default to outputting information to stderr */ + if (!stream) + stream = stderr; + + HDfprintf (stream, "HDF5-DIAG: Function stack from %s ", H5_lib_vers_info_g); + /* try show the process or thread id in multiple processes cases*/ +#ifdef H5_HAVE_THREADSAFE + HDfprintf (stream, "thread %d.", (int)pthread_self()); +#else /* H5_HAVE_THREADSAFE */ + HDfprintf (stream, "thread 0."); +#endif /* H5_HAVE_THREADSAFE */ + if (fstack && fstack->nused>0) + HDfprintf (stream, " Back trace follows."); + HDfputc ('\n', stream); + + for (i=fstack->nused-1; i>=0; --i) + HDfprintf(stream, "%*s#%03d: Routine: %s\n", indent, "", i, fstack->slot[i]); + + FUNC_LEAVE_NOAPI_NOFS(SUCCEED); +} /* end H5FS_print() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_push + * + * Purpose: Pushes a new record onto function stack for the current + * thread. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_push(const char *func_name) +{ + H5FS_t *fstack = H5FS_get_my_stack (); + + /* Don't push this function on the function stack... :-) */ + FUNC_ENTER_NOAPI_NOFS(H5FS_push); + + /* Sanity check */ + assert (fstack); + assert (func_name); + + /* + * Push the function if there's room. Otherwise just increment count + */ + if (fstack->nusedslot[fstack->nused] = func_name; + fstack->nused++; + + FUNC_LEAVE_NOAPI_NOFS(SUCCEED); +} /* end H5FS_push() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS_pop + * + * Purpose: Pops a record off function stack for the current thread. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, February 6, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FS_pop(void) +{ + H5FS_t *fstack = H5FS_get_my_stack (); + + /* Don't push this function on the function stack... :-) */ + FUNC_ENTER_NOAPI_NOFS(H5FS_pop); + + /* Sanity check */ + assert (fstack); + assert (fstack->nused>0); + + /* Pop the function. */ + fstack->nused--; + + FUNC_LEAVE_NOAPI_NOFS(SUCCEED); +} /* end H5FS_pop() */ + +#endif /* H5_HAVE_FUNCSTACK */ diff --git a/src/H5FSprivate.h b/src/H5FSprivate.h new file mode 100644 index 0000000..6dba575 --- /dev/null +++ b/src/H5FSprivate.h @@ -0,0 +1,40 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Header file for function stacks, etc. + */ +#ifndef _H5FSprivate_H +#define _H5FSprivate_H + +#ifdef NOT_YET +#include "H5FSpublic.h" +#endif /* NOT_YET */ + +/* Private headers needed by this file */ +#include "H5private.h" + +#define H5FS_NSLOTS 32 /*number of slots in an function stack */ + +/* A function stack */ +typedef struct H5FS_t { + int nused; /*num slots currently used in stack */ + const char *slot[H5FS_NSLOTS]; /*array of function records */ +} H5FS_t; + +H5_DLL herr_t H5FS_push (const char *func_name); +H5_DLL herr_t H5FS_pop (void); +H5_DLL herr_t H5FS_print (FILE *stream); + +#endif /* _H5FSprivate_H */ diff --git a/src/H5TS.c b/src/H5TS.c index ce3d5ef..c577ebc 100644 --- a/src/H5TS.c +++ b/src/H5TS.c @@ -30,6 +30,7 @@ typedef struct H5TS_cancel_struct { /* Global variable definitions */ pthread_once_t H5TS_first_init_g = PTHREAD_ONCE_INIT; pthread_key_t H5TS_errstk_key_g; +pthread_key_t H5TS_funcstk_key_g; pthread_key_t H5TS_cancel_key_g; hbool_t H5TS_allow_concurrent_g = FALSE; /* concurrent APIs override this */ @@ -38,6 +39,36 @@ hbool_t H5TS_allow_concurrent_g = FALSE; /* concurrent APIs override this */ static void H5TS_mutex_init(H5TS_mutex_t *mutex); #endif /* NOT_USED */ + +/*-------------------------------------------------------------------------- + * NAME + * H5TS_key_destructor + * + * USAGE + * H5TS_key_destructor() + * + * RETURNS + * + * DESCRIPTION + * Frees the memory for a key. Called by each thread as it exits. + * Currently all the thread-specific information for all keys are simple + * structures allocated with malloc, so we can free them all uniformly. + * + * PROGRAMMER: Quincey Koziol + * February 7, 2003 + * + * MODIFICATIONS: + * + *-------------------------------------------------------------------------- + */ +static void +H5TS_key_destructor(void *key_val) +{ + /* Use HDfree here instead of H5MM_xfree(), to avoid calling the H5FS routines */ + if(key_val!=NULL) + HDfree(key_val); +} + /*-------------------------------------------------------------------------- * NAME * H5TS_first_thread_init @@ -73,46 +104,14 @@ H5TS_first_thread_init(void) H5_g.init_lock.lock_count = 0; /* initialize key for thread-specific error stacks */ - pthread_key_create(&H5TS_errstk_key_g, NULL); + pthread_key_create(&H5TS_errstk_key_g, H5TS_key_destructor); - /* initialize key for thread cancellability mechanism */ - pthread_key_create(&H5TS_cancel_key_g, NULL); -} + /* initialize key for thread-specific function stacks */ + pthread_key_create(&H5TS_funcstk_key_g, H5TS_key_destructor); -#ifdef NOT_USED -/*-------------------------------------------------------------------------- - * NAME - * H5TS_mutex_init - * - * USAGE - * H5TS_mutex_init(&mutex_var) - * - * RETURNS - * - * DESCRIPTION - * Recursive lock semantics for HDF5 (lock initialization) - - * Multiple acquisition of a lock by a thread is permitted with a - * corresponding unlock operation required. - * - * PROGRAMMER: Chee Wai LEE - * May 2, 2000 - * - * MODIFICATIONS: - * - * 19 May 2000, Bill Wendling - * Changed (*foo). form of accessing structure members to the -> form. - * - *-------------------------------------------------------------------------- - */ -static void -H5TS_mutex_init(H5TS_mutex_t *mutex) -{ - H5_g.init_lock.owner_thread = NULL; - pthread_mutex_init(&mutex->atomic_lock, NULL); - pthread_cond_init(&mutex->cond_var, NULL); - mutex->lock_count = 0; + /* initialize key for thread cancellability mechanism */ + pthread_key_create(&H5TS_cancel_key_g, H5TS_key_destructor); } -#endif /* NOT_USED */ /*-------------------------------------------------------------------------- * NAME diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index c9a8c20..4ece8d6 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -34,6 +34,7 @@ typedef struct H5TS_mutex_struct { /* Extern global variables */ extern pthread_once_t H5TS_first_init_g; extern pthread_key_t H5TS_errstk_key_g; +extern pthread_key_t H5TS_funcstk_key_g; #if defined c_plusplus || defined __cplusplus extern "C" diff --git a/src/H5config.h.in b/src/H5config.h.in index 1b7f58c..06928ff 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -21,15 +21,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_FEATURES_H +/* Define if support for Adler32 checksum is enabled */ +#undef HAVE_FILTER_ADLER32 + /* Define if support for deflate filter is enabled */ #undef HAVE_FILTER_DEFLATE /* Define if support for shuffle filter is enabled */ #undef HAVE_FILTER_SHUFFLE -/* Define if support for Adler32 checksum filter is enabled */ -#undef HAVE_FILTER_ADLER32 - /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK @@ -39,6 +39,9 @@ /* Define to 1 if you have the `fseek64' function. */ #undef HAVE_FSEEK64 +/* Define if the function stack tracing code is to be compiled in */ +#undef HAVE_FUNCSTACK + /* Define if the compiler understand the __FUNCTION__ keyword */ #undef HAVE_FUNCTION diff --git a/src/H5private.h b/src/H5private.h index baff347..09e0f02 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1091,6 +1091,18 @@ extern hbool_t H5_libinit_g; /* Has the library been initialized? */ #endif /* H5_HAVE_THREADSAFE */ +#ifdef H5_HAVE_FUNCSTACK + +/* Include required function stack header */ +#include "H5FSprivate.h" + +#define H5_PUSH_FUNC H5FS_push(FUNC) +#define H5_POP_FUNC H5FS_pop() +#else /* H5_HAVE_FUNCSTACK */ +#define H5_PUSH_FUNC /* void */ +#define H5_POP_FUNC /* void */ +#endif /* H5_HAVE_FUNCSTACK */ + #ifdef H5_HAVE_MPE extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ #endif @@ -1149,6 +1161,7 @@ extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ FUNC_ENTER_API_VARS \ FUNC_ENTER_COMMON(func_name,H5_IS_API(FUNC)); \ FUNC_ENTER_API_THREADSAFE; \ + H5_PUSH_FUNC; \ BEGIN_MPE_LOG(func_name); \ { @@ -1159,7 +1172,7 @@ extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ { /* - * Use this macro for non-API functions which fall into two categories: + * Use this macro for non-API functions which fall into these categories: * - static functions, since they must be called from a function in the * interface, the library and interface must already be * initialized. @@ -1168,16 +1181,25 @@ extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ */ #define FUNC_ENTER_NOINIT(func_name) { \ FUNC_ENTER_COMMON(func_name,!H5_IS_API(FUNC)); \ + H5_PUSH_FUNC; \ + { + +/* + * Use this macro for non-API functions which fall into these categories: + * - functions which shouldn't push their name on the function stack + * (so far, just the H5FS routines themselves) + */ +#define FUNC_ENTER_NOAPI_NOFS(func_name) { \ + FUNC_ENTER_COMMON(func_name,!H5_IS_API(FUNC)); \ { #define FUNC_ENTER_API_COMMON(func_name,interface_init_func,err) \ /* Initialize the library */ \ if (!(H5_INIT_GLOBAL)) { \ H5_INIT_GLOBAL = TRUE; \ - if (H5_init_library()<0) { \ + if (H5_init_library()<0) \ HGOTO_ERROR (H5E_FUNC, H5E_CANTINIT, err, \ "library initialization failed"); \ - } \ } \ \ /* Initialize this interface or bust */ \ @@ -1190,7 +1212,11 @@ extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ "interface initialization failed"); \ } \ } \ - BEGIN_MPE_LOG(func_name) + \ + /* Push the name of this function on the function stack */ \ + H5_PUSH_FUNC; \ + \ + BEGIN_MPE_LOG(func_name) #define FUNC_ENTER_NOAPI_INIT(func_name,interface_init_func,err) \ /* Initialize this interface or bust */ \ @@ -1202,7 +1228,10 @@ extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ HGOTO_ERROR (H5E_FUNC, H5E_CANTINIT, err, \ "interface initialization failed"); \ } \ - } + } \ + \ + /* Push the name of this function on the function stack */ \ + H5_PUSH_FUNC; /*------------------------------------------------------------------------- * Purpose: Register function exit for code profiling. This should be @@ -1223,6 +1252,7 @@ extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ FINISH_MPE_LOG; \ PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ H5TRACE_RETURN(ret_value); \ + H5_POP_FUNC; \ H5_API_UNLOCK \ H5_API_SET_CANCEL \ return (ret_value); \ @@ -1231,17 +1261,30 @@ extern hbool_t H5_MPEinit_g; /* Has the MPE Library been initialized? */ #define FUNC_LEAVE_NOAPI(ret_value) \ PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ + H5_POP_FUNC; \ return (ret_value); \ } /*end scope from end of FUNC_ENTER*/ \ } /*end scope from beginning of FUNC_ENTER*/ #define FUNC_LEAVE_NOAPI_VOID \ PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ + H5_POP_FUNC; \ return; \ } /*end scope from end of FUNC_ENTER*/ \ } /*end scope from beginning of FUNC_ENTER*/ /* + * Use this macro for non-API functions which fall into these categories: + * - functions which didn't push their name on the function stack + * (so far, just the H5FS routines themselves) + */ +#define FUNC_LEAVE_NOAPI_NOFS(ret_value) \ + PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \ + return (ret_value); \ + } /*end scope from end of FUNC_ENTER*/ \ +} /*end scope from beginning of FUNC_ENTER*/ + +/* * The FUNC_ENTER() and FUNC_LEAVE() macros make calls to Pablo functions * through one of these two sets of macros. */ diff --git a/src/Makefile.in b/src/Makefile.in index a783909..db8c717 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -32,8 +32,8 @@ LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5D.c H5E.c H5F.c H5Farray.c H5Fcontig.c \ H5Fcompact.c H5Fistore.c H5Fseq.c H5FD.c H5FDcore.c H5FDfamily.c \ H5FDfphdf5.c H5FDgass.c H5FDlog.c H5FDmpio.c H5FDmpiposix.c \ H5FDmulti.c H5FDsec2.c H5FDsrb.c H5FDstdio.c H5FDstream.c H5FL.c \ - H5FO.c H5FP.c H5FPclient.c H5FPserver.c H5G.c H5Gent.c H5Gnode.c \ - H5Gstab.c H5HG.c H5HL.c H5I.c H5MF.c H5MM.c H5O.c H5Oattr.c \ + H5FO.c H5FP.c H5FPclient.c H5FPserver.c H5FS.c H5G.c H5Gent.c \ + H5Gnode.c H5Gstab.c H5HG.c H5HL.c H5I.c H5MF.c H5MM.c H5O.c H5Oattr.c \ H5Obogus.c H5Ocont.c H5Odtype.c H5Oefl.c H5Ofill.c H5Ofphdf5.c \ H5Olayout.c H5Omtime.c H5Oname.c H5Onull.c H5Opline.c H5Oplist.c \ H5Osdspace.c H5Oshared.c H5Ostab.c H5P.c H5Pdcpl.c H5Pdxpl.c \ @@ -58,13 +58,12 @@ PUB_HDR=H5public.h H5Apublic.h H5ACpublic.h H5Bpublic.h H5Dpublic.h \ ## Other header files (not to be installed)... PRIVATE_HDR=H5private.h H5Aprivate.h H5Apkg.h H5ACprivate.h H5Bprivate.h \ - H5Dprivate.h H5Eprivate.h H5Fprivate.h H5FDprivate.h \ - H5FLprivate.h H5FOprivate.h H5FPprivate.h H5Gprivate.h H5Gpkg.h \ - H5HGprivate.h H5HLprivate.h H5Iprivate.h H5MFprivate.h \ - H5MMprivate.h H5Oprivate.h H5Pprivate.h H5Ppkg.h H5Rprivate.h \ - H5RSprivate.h H5Sprivate.h H5STprivate.h H5Tprivate.h \ - H5TBprivate.h H5Tpkg.h H5TSprivate.h H5Vprivate.h H5Zprivate.h \ - H5config.h + H5Dprivate.h H5Eprivate.h H5Fprivate.h H5FDprivate.h H5FLprivate.h \ + H5FOprivate.h H5FPprivate.h H5FSprivate.h H5Gprivate.h H5Gpkg.h \ + H5HGprivate.h H5HLprivate.h H5Iprivate.h H5MFprivate.h H5MMprivate.h \ + H5Oprivate.h H5Pprivate.h H5Ppkg.h H5Rprivate.h H5RSprivate.h \ + H5Sprivate.h H5STprivate.h H5Tprivate.h H5TBprivate.h H5Tpkg.h \ + H5TSprivate.h H5Vprivate.h H5Zprivate.h H5config.h ## Number format detection ## The LD_LIBRARY_PATH setting is a klutch. diff --git a/test/bittests.c b/test/bittests.c index a5af191..e1f01f9 100644 --- a/test/bittests.c +++ b/test/bittests.c @@ -513,6 +513,14 @@ main (void) { int nerrors=0; + /* + * Open the library explicitly for thread-safe builds, so per-thread + * things are initialized correctly. + */ +#ifdef H5_HAVE_THREADSAFE + H5open(); +#endif /* H5_HAVE_THREADSAFE */ + nerrors += test_find ()<0?1:0; nerrors += test_set ()<0?1:0; nerrors += test_clear()<0?1:0; @@ -524,5 +532,9 @@ main (void) exit(1); } printf("All bit tests passed.\n"); + +#ifdef H5_HAVE_THREADSAFE + H5close(); +#endif /* H5_HAVE_THREADSAFE */ return 0; } diff --git a/test/hyperslab.c b/test/hyperslab.c index 2844ec6..aa43d96 100644 --- a/test/hyperslab.c +++ b/test/hyperslab.c @@ -1114,6 +1114,14 @@ main(int argc, char *argv[]) printf("\n"); /* + * Open the library explicitly for thread-safe builds, so per-thread + * things are initialized correctly. + */ +#ifdef H5_HAVE_THREADSAFE + H5open(); +#endif /* H5_HAVE_THREADSAFE */ + + /* *------------------------------ * TEST HYPERSLAB FILL OPERATION *------------------------------ @@ -1259,5 +1267,9 @@ main(int argc, char *argv[]) exit(1); } printf("All hyperslab tests passed.\n"); + +#ifdef H5_HAVE_THREADSAFE + H5close(); +#endif /* H5_HAVE_THREADSAFE */ return 0; } diff --git a/test/ttsafe_cancel.c b/test/ttsafe_cancel.c index 2d2ce3f..8e47d09 100644 --- a/test/ttsafe_cancel.c +++ b/test/ttsafe_cancel.c @@ -86,6 +86,9 @@ void tts_cancel(void) H5Dclose(dataset); H5Fclose(cancel_file); + + /* Destroy the thread attribute */ + pthread_attr_destroy(&attribute); } void *tts_cancel_thread(void *arg) @@ -201,7 +204,6 @@ void tts_cancel_barrier(void) void cleanup_cancel(void) { - H5close(); HDunlink(FILENAME); } diff --git a/test/ttsafe_dcreate.c b/test/ttsafe_dcreate.c index ae4fdbc..d85dbe7 100644 --- a/test/ttsafe_dcreate.c +++ b/test/ttsafe_dcreate.c @@ -44,140 +44,148 @@ typedef struct thread_info { } thread_info; /* + * Set individual dataset names (rather than generated the names + * automatically) + */ +const char *dsetname[NUM_THREAD]={ + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "ten", + "eleven", + "twelve", + "thirteen", + "fourteen", + "fifteen" +}; + +thread_info thread_out[NUM_THREAD]; + +/* ********************************************************************** * Thread safe test - multiple dataset creation ********************************************************************** */ void tts_dcreate(void) { - /* Pthread definitions */ - pthread_t threads[NUM_THREAD]; - - /* HDF5 data definitions */ - hid_t file, dataset, datatype; - int datavalue, i; - thread_info *thread_out; - const char *dsetname[NUM_THREAD]; - pthread_attr_t attribute; - - /* set pthread attribute to perform global scheduling */ - pthread_attr_init(&attribute); - pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM); - - /* - * Set individual dataset names (rather than generated the names - * automatically) - */ - - for (i = 0; i < NUM_THREAD; i++) - dsetname[i] = malloc(sizeof(char) * DATASETNAME_LENGTH); - - dsetname[0] = "zero"; - dsetname[1] = "one"; - dsetname[2] = "two"; - dsetname[3] = "three"; - dsetname[4] = "four"; - dsetname[5] = "five"; - dsetname[6] = "six"; - dsetname[7] = "seven"; - dsetname[8] = "eight"; - dsetname[9] = "nine"; - dsetname[10] = "ten"; - dsetname[11] = "eleven"; - dsetname[12] = "twelve"; - dsetname[13] = "thirteen"; - dsetname[14] = "fourteen"; - dsetname[15] = "fifteen"; - - /* - * Create a hdf5 file using H5F_ACC_TRUNC access, default file - * creation plist and default file access plist - */ - file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); - - /* simultaneously create a large number of datasets within the file */ - for (i = 0; i < NUM_THREAD; i++) { - thread_out = malloc(sizeof(thread_info)); - thread_out->id = i; - thread_out->file = file; - thread_out->dsetname = dsetname[i]; - pthread_create(&threads[i], NULL, tts_dcreate_creator, thread_out); - } - - for (i = 0;i < NUM_THREAD; i++) - pthread_join(threads[i], NULL); - - /* compare data to see if it is written correctly */ - - /* define datatype for the data using native little endian integers */ - datatype = H5Tcopy(H5T_NATIVE_INT); - - for (i = 0; i < NUM_THREAD; i++) { - if ((dataset = H5Dopen(file,dsetname[i])) < 0) { - fprintf(stderr, "Dataset name not found - test failed\n"); - H5Fclose(file); - num_errs++; - return; - } else { - H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, &datavalue); - - if (datavalue != i) { - fprintf(stderr, - "Wrong value read %d for dataset name %s - test failed\n", - datavalue, dsetname[i]); - H5Dclose(dataset); - H5Fclose(file); - num_errs++; - return; - } - - H5Dclose(dataset); - } - } - - /* close remaining resources */ - H5Fclose(file); + /* Pthread definitions */ + pthread_t threads[NUM_THREAD]; + + /* HDF5 data definitions */ + hid_t file, dataset; + int datavalue, i; + pthread_attr_t attribute; + int ret; + + /* set pthread attribute to perform global scheduling */ + ret=pthread_attr_init(&attribute); + assert(ret==0); + ret=pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM); +/* Don't check return value on FreeBSD, since PTHREAD_SCOPE_SYSTEM is not + * currently supported in v4.7 + */ +#ifndef __FreeBSD__ + assert(ret==0); +#endif /* __FreeBSD__ */ + + /* + * Create a hdf5 file using H5F_ACC_TRUNC access, default file + * creation plist and default file access plist + */ + file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + assert(file>=0); + + /* simultaneously create a large number of datasets within the file */ + for (i = 0; i < NUM_THREAD; i++) { + thread_out[i].id = i; + thread_out[i].file = file; + thread_out[i].dsetname = dsetname[i]; + ret=pthread_create(&threads[i], NULL, tts_dcreate_creator, &thread_out[i]); + assert(ret==0); + } + + for (i = 0;i < NUM_THREAD; i++) { + ret=pthread_join(threads[i], NULL); + assert(ret==0); + } /* end for */ + + /* compare data to see if it is written correctly */ + + for (i = 0; i < NUM_THREAD; i++) { + if ((dataset = H5Dopen(file,dsetname[i])) < 0) { + fprintf(stderr, "Dataset name not found - test failed\n"); + H5Fclose(file); + num_errs++; + return; + } else { + ret=H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &datavalue); + assert(ret>=0); + + if (datavalue != i) { + fprintf(stderr, "Wrong value read %d for dataset name %s - test failed\n", + datavalue, dsetname[i]); + H5Dclose(dataset); + H5Fclose(file); + num_errs++; + return; + } + + ret=H5Dclose(dataset); + assert(ret>=0); + } + } + + /* close remaining resources */ + ret=H5Fclose(file); + assert(ret>=0); + + /* Destroy the thread attribute */ + ret=pthread_attr_destroy(&attribute); + assert(ret==0); } -void *tts_dcreate_creator(void *thread_data) +void *tts_dcreate_creator(void *_thread_data) { - hid_t dataspace, datatype, dataset; + hid_t dataspace, dataset; + herr_t ret; hsize_t dimsf[1]; /* dataset dimensions */ - struct thread_info { - int id; - hid_t file; - char *dsetname; - } thread_in; + struct thread_info thread_data; - thread_in.dsetname = malloc(sizeof(char) * DATASETNAME_LENGTH); - thread_in = *((struct thread_info *)thread_data); + memcpy(&thread_data,_thread_data,sizeof(struct thread_info)); /* define dataspace for dataset */ dimsf[0] = 1; dataspace = H5Screate_simple(1,dimsf,NULL); - - /* define datatype for the data using native little endian integers */ - datatype = H5Tcopy(H5T_NATIVE_INT); - H5Tset_order(datatype, H5T_ORDER_LE); + assert(dataspace>=0); /* create a new dataset within the file */ - dataset = H5Dcreate(thread_in.file, thread_in.dsetname, - datatype, dataspace, H5P_DEFAULT); + dataset = H5Dcreate(thread_data.file, thread_data.dsetname, + H5T_NATIVE_INT, dataspace, H5P_DEFAULT); + assert(dataset>=0); /* initialize data for dataset and write value to dataset */ - H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, - H5P_DEFAULT, &thread_in.id); + ret=H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, &thread_data.id); + assert(ret>=0); + + /* close dataset and dataspace resources */ + ret=H5Dclose(dataset); + assert(ret>=0); + ret=H5Sclose(dataspace); + assert(ret>=0); - /* close dataset, datatype and dataspace resources */ - H5Dclose(dataset); - H5Tclose(datatype); - H5Sclose(dataspace); return NULL; } void cleanup_dcreate(void) { - H5close(); HDunlink(FILENAME); } #endif /*H5_HAVE_THREADSAFE*/ diff --git a/test/ttsafe_error.c b/test/ttsafe_error.c index 54ffc4b..e911863 100644 --- a/test/ttsafe_error.c +++ b/test/ttsafe_error.c @@ -130,6 +130,9 @@ void tts_error(void) /* turn our error stack handler off */ H5Eset_auto(old_error_cb, old_error_client_data); + + /* Destroy the thread attribute */ + pthread_attr_destroy(&attribute); } static -- cgit v0.12