diff options
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | release_docs/RELEASE.txt | 5 | ||||
-rw-r--r-- | src/H5CS.c | 6 | ||||
-rw-r--r-- | src/H5Dint.c | 2 | ||||
-rw-r--r-- | src/H5Dlayout.c | 6 | ||||
-rw-r--r-- | src/H5Eint.c | 8 | ||||
-rw-r--r-- | src/H5TS.c | 119 | ||||
-rw-r--r-- | src/H5TSprivate.h | 3 | ||||
-rw-r--r-- | src/H5private.h | 5 | ||||
-rw-r--r-- | src/H5win32defs.h | 4 | ||||
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/CMakeTests.cmake | 124 | ||||
-rw-r--r-- | test/Makefile.am | 23 | ||||
-rw-r--r-- | test/dsets.c | 211 | ||||
-rw-r--r-- | test/h5test.c | 4 | ||||
-rw-r--r-- | test/thread_id.c | 163 |
16 files changed, 557 insertions, 128 deletions
@@ -1235,6 +1235,7 @@ ./test/th5s.c ./test/th5s.h5 ./test/theap.c +./test/thread_id.c ./test/tid.c ./test/titerate.c ./test/tlayouto.h5 diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 8fafd0d..5ecb8b6 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -109,7 +109,10 @@ Bug Fixes since HDF5-1.12.0 release ================================== Library ------- - + - Don't allocate an empty (0-dimensioned) chunked dataset's chunk + index, until the dataset's dimensions are increased. + + (QAK - 2020/05/07) Tools: ------ @@ -145,11 +145,7 @@ H5CS_print_stack(const H5CS_t *fstack, FILE *stream) 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 %lu.", HDpthread_self_ulong()); -#else /* H5_HAVE_THREADSAFE */ - HDfprintf(stream, "thread 0."); -#endif /* H5_HAVE_THREADSAFE */ + HDfprintf(stream, "thread %" PRIu64 ".", H5TS_thread_id()); if(fstack && fstack->nused>0) HDfprintf(stream, " Back trace follows."); HDfputc('\n', stream); diff --git a/src/H5Dint.c b/src/H5Dint.c index 73dc526..4750ad6 100644 --- a/src/H5Dint.c +++ b/src/H5Dint.c @@ -2291,7 +2291,7 @@ H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, * We assume that external storage is already * allocated by the caller, or at least will be before I/O is performed. */ - if(!(H5S_NULL == H5S_GET_EXTENT_TYPE(dset->shared->space) || dset->shared->dcpl_cache.efl.nused > 0)) { + if(!(0 == H5S_GET_EXTENT_NPOINTS(dset->shared->space) || dset->shared->dcpl_cache.efl.nused > 0)) { /* Get a pointer to the dataset's layout information */ layout = &(dset->shared->layout); diff --git a/src/H5Dlayout.c b/src/H5Dlayout.c index c71cdc4..7ac274c 100644 --- a/src/H5Dlayout.c +++ b/src/H5Dlayout.c @@ -558,10 +558,12 @@ H5D__layout_oh_create(H5F_t *file, H5O_t *oh, H5D_t *dset, hid_t dapl_id) } /* end if */ /* Create layout message */ - /* (Don't make layout message constant unless allocation time is early and non-filtered, since space may not be allocated) */ + /* (Don't make layout message constant unless allocation time is early and + * non-filtered and has >0 elements, since space may not be allocated -QAK) */ /* (Note: this is relying on H5D__alloc_storage not calling H5O_msg_write during dataset creation) */ if(fill_prop->alloc_time == H5D_ALLOC_TIME_EARLY && H5D_COMPACT != layout->type - && !dset->shared->dcpl_cache.pline.nused) + && !dset->shared->dcpl_cache.pline.nused + && (0 != H5S_GET_EXTENT_NPOINTS(dset->shared->space))) layout_mesg_flags = H5O_MSG_FLAG_CONSTANT; else layout_mesg_flags = 0; diff --git a/src/H5Eint.c b/src/H5Eint.c index e76db82..7e144c8 100644 --- a/src/H5Eint.c +++ b/src/H5Eint.c @@ -259,10 +259,8 @@ H5E__walk1_cb(int n, H5E_error1_t *err_desc, void *client_data) else HDfprintf(stream, "thread 0"); } /* end block */ -#elif defined(H5_HAVE_THREADSAFE) - HDfprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong()); #else - HDfprintf(stream, "thread 0"); + HDfprintf(stream, "thread %" PRIu64, H5TS_thread_id()); #endif HDfprintf(stream, ":\n"); } /* end if */ @@ -391,10 +389,8 @@ H5E__walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data) else HDfprintf(stream, "thread 0"); } /* end block */ -#elif defined(H5_HAVE_THREADSAFE) - HDfprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong()); #else - HDfprintf(stream, "thread 0"); + HDfprintf(stream, "thread %" PRIu64, H5TS_thread_id()); #endif HDfprintf(stream, ":\n"); } /* end if */ @@ -37,6 +37,31 @@ H5TS_key_t H5TS_funcstk_key_g; H5TS_key_t H5TS_apictx_key_g; H5TS_key_t H5TS_cancel_key_g; +#ifndef H5_HAVE_WIN_THREADS + +/* An h5_tid_t is a record of a thread identifier that is + * available for reuse. + */ +struct _tid; +typedef struct _tid h5_tid_t; + +struct _tid { + h5_tid_t *next; + uint64_t id; +}; + +/* Pointer to first free thread ID record or NULL. */ +static h5_tid_t *tid_next_free = NULL; +static uint64_t tid_next_id = 0; + +/* Mutual exclusion for access to tid_next_free and tid_next_id. */ +static pthread_mutex_t tid_mtx; + +/* Key for thread-local storage of the thread ID. */ +static H5TS_key_t tid_key; + +#endif /* H5_HAVE_WIN_THREADS */ + /*-------------------------------------------------------------------------- * NAME @@ -68,6 +93,89 @@ H5TS_key_destructor(void *key_val) #ifndef H5_HAVE_WIN_THREADS +/* When a thread shuts down, put its ID record on the free list. */ +static void +tid_destructor(void *_v) +{ + h5_tid_t *tid = _v; + + if (tid == NULL) + return; + + /* XXX I can use mutexes in destructors, right? */ + /* TBD use an atomic CAS */ + pthread_mutex_lock(&tid_mtx); + tid->next = tid_next_free; + tid_next_free = tid; + pthread_mutex_unlock(&tid_mtx); +} + +/* Initialize for integer thread identifiers. */ +static void +tid_init(void) +{ + pthread_mutex_init(&tid_mtx, NULL); + pthread_key_create(&tid_key, tid_destructor); +} + +/* Return an integer identifier, ID, for the current thread satisfying the + * following properties: + * + * 1 1 <= ID <= UINT64_MAX + * 2 ID is constant over the thread's lifetime. + * 3 No two threads share an ID during their lifetimes. + * 4 A thread's ID is available for reuse as soon as it is joined. + * + * ID 0 is reserved. H5TS_thread_id() returns 0 if the library was not built + * with thread safety or if an error prevents it from assigning an ID. + */ +uint64_t +H5TS_thread_id(void) +{ + h5_tid_t *tid = pthread_getspecific(tid_key); + h5_tid_t proto_tid; + + /* An ID is already assigned. */ + if (tid != NULL) + return tid->id; + + /* An ID is *not* already assigned: reuse an ID that's on the + * free list, or else generate a new ID. + * + * Allocating memory while holding a mutex is bad form, so + * point `tid` at `proto_tid` if we need to allocate some + * memory. + */ + pthread_mutex_lock(&tid_mtx); + if ((tid = tid_next_free) != NULL) + tid_next_free = tid->next; + else if (tid_next_id != UINT64_MAX) { + tid = &proto_tid; + tid->id = ++tid_next_id; + } + pthread_mutex_unlock(&tid_mtx); + + /* If a prototype ID record was established, copy it to the heap. */ + if (tid == &proto_tid) { + if ((tid = HDmalloc(sizeof(*tid))) != NULL) + *tid = proto_tid; + } + + if (tid == NULL) + return 0; + + /* Finish initializing the ID record and set a thread-local pointer + * to it. + */ + tid->next = NULL; + if (pthread_setspecific(tid_key, tid) != 0) { + tid_destructor(tid); + return 0; + } + + return tid->id; +} + /*-------------------------------------------------------------------------- * NAME * H5TS_pthread_first_thread_init @@ -104,6 +212,9 @@ H5TS_pthread_first_thread_init(void) pthread_cond_init(&H5_g.init_lock.cond_var, NULL); H5_g.init_lock.lock_count = 0; + /* Initialize integer thread identifiers. */ + tid_init(); + /* initialize key for thread-specific error stacks */ pthread_key_create(&H5TS_errstk_key_g, H5TS_key_destructor); @@ -528,5 +639,13 @@ H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata) } /* H5TS_create_thread */ +#else /* H5_HAVE_THREADSAFE */ + +uint64_t +H5TS_thread_id(void) +{ + return 0; +} + #endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index 9e093a6..f22ed52 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -68,7 +68,7 @@ H5_DLL void H5TS_win32_process_exit(void); H5_DLL herr_t H5TS_win32_thread_enter(void); H5_DLL herr_t H5TS_win32_thread_exit(void); - +#define H5TS_thread_id() ((uint64_t)GetCurrentThreadId()) #else /* H5_HAVE_WIN_THREADS */ @@ -102,6 +102,7 @@ typedef pthread_once_t H5TS_once_t; #define H5TS_mutex_init(mutex) pthread_mutex_init(mutex, NULL) #define H5TS_mutex_lock_simple(mutex) pthread_mutex_lock(mutex) #define H5TS_mutex_unlock_simple(mutex) pthread_mutex_unlock(mutex) +H5_DLL uint64_t H5TS_thread_id(void); #endif /* H5_HAVE_WIN_THREADS */ diff --git a/src/H5private.h b/src/H5private.h index 7ff0c87..e7626ac 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1571,11 +1571,6 @@ extern char *strdup(const char *s); #define HDpthread_self() pthread_self() #endif /* HDpthread_self */ -/* Use this version of pthread_self for printing the thread ID */ -#ifndef HDpthread_self_ulong - #define HDpthread_self_ulong() ((unsigned long)pthread_self()) -#endif /* HDpthread_self_ulong */ - /* Macro for "stringizing" an integer in the C preprocessor (use H5_TOSTRING) */ /* (use H5_TOSTRING, H5_STRINGIZE is just part of the implementation) */ #define H5_STRINGIZE(x) #x diff --git a/src/H5win32defs.h b/src/H5win32defs.h index 0a0bd37..00df56d 100644 --- a/src/H5win32defs.h +++ b/src/H5win32defs.h @@ -163,10 +163,6 @@ extern "C" { /* Non-POSIX functions */ -/* Don't use actual pthread_self on Windows because the return - * type cannot be cast as a ulong like other systems. */ -#define HDpthread_self_ulong() ((unsigned long)GetCurrentThreadId()) - #ifndef H5_HAVE_MINGW #define HDftruncate(F,L) _chsize_s(F,L) #define HDfseek(F,O,W) _fseeki64(F,O,W) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 41d29f7..a02d1c2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -287,6 +287,7 @@ set (H5_TESTS cache_logging cork swmr + thread_id vol ) diff --git a/test/CMakeTests.cmake b/test/CMakeTests.cmake index b7eaa56..2371468 100644 --- a/test/CMakeTests.cmake +++ b/test/CMakeTests.cmake @@ -263,6 +263,9 @@ set (test_CLEANFILES bt2_hdr_fd.h5 storage_size.h5 dls_01_strings.h5 + power2up.h5 + version_bounds.h5 + alloc_0sized.h5 extend.h5 istore.h5 extlinks*.h5 @@ -285,60 +288,19 @@ set (test_CLEANFILES dt_arith2 links.h5 links*.h5 - extlinks16A00000.h5 - extlinks16A00001.h5 - extlinks16A00002.h5 - extlinks16B-b.h5 - extlinks16B-g.h5 - extlinks16B-l.h5 - extlinks16B-r.h5 - extlinks16B-s.h5 - extlinks19B00000.h5 - extlinks19B00001.h5 - extlinks19B00002.h5 - extlinks19B00003.h5 - extlinks19B00004.h5 - extlinks19B00005.h5 - extlinks19B00006.h5 - extlinks19B00007.h5 - extlinks19B00008.h5 - extlinks19B00009.h5 - extlinks19B00010.h5 - extlinks19B00011.h5 - extlinks19B00012.h5 - extlinks19B00013.h5 - extlinks19B00014.h5 - extlinks19B00015.h5 - extlinks19B00016.h5 - extlinks19B00017.h5 - extlinks19B00018.h5 - extlinks19B00019.h5 - extlinks19B00020.h5 - extlinks19B00021.h5 - extlinks19B00022.h5 - extlinks19B00023.h5 - extlinks19B00024.h5 - extlinks19B00025.h5 - extlinks19B00026.h5 - extlinks19B00027.h5 - extlinks19B00028.h5 + extlinks*.h5 + tmp + tmp_links + tmp2_links + tmp_links_env + tmp_vds/* + tmp_vds_env/* big.data big*.h5 stdio.h5 sec2.h5 - dtypes0.h5 - dtypes1.h5 - dtypes2.h5 - dtypes3.h5 - dtypes4.h5 - dtypes5.h5 - dtypes6.h5 - dtypes7.h5 - dtypes8.h5 - dtypes9.h5 - dtypes10.h5 - dt_arith1.h5 - dt_arith2.h5 + dtypes*.h5 + dt_arith*.h5 tattr.h5 tselect.h5 mtime.h5 @@ -350,40 +312,38 @@ set (test_CLEANFILES mount_*.h5 testmeta.h5 ttime.h5 - trefer1.h5 - trefer2.h5 - trefer3.h5 + trefer*.h5 + trefer_*.h5 tvltypes.h5 tvlstr.h5 tvlstr2.h5 twriteorder.dat + flush.h5 + flush-swmr.h5 + noflush.h5 + noflush-swmr.h5 + flush_extend.h5 + flush_extend-swmr.h5 + noflush_extend.h5 + noflush_extend-swmr.h5 enum1.h5 titerate.h5 ttsafe.h5 tarray1.h5 tgenprop.h5 tmisc*.h5 - set_extent1.h5 - set_extent2.h5 - set_extent3.h5 - set_extent4.h5 - set_extent5.h5 - ext1.bin - ext2.bin + set_extent*.h5 + ext*.bin getname.h5 - getname1.h5 - getname2.h5 - getname3.h5 + getname*.h5 sec2_file.h5 direct_file.h5 family_file000*.h5 new_family_v16_000*.h5 - multi_file-r.h5 - multi_file-s.h5 + multi_file-*.h5 core_file filter_plugin.h5 - new_move_a.h5 - new_move_b.h5 + new_move_*.h5 ntypes.h5 dangle.h5 error_test.h5 @@ -391,28 +351,22 @@ set (test_CLEANFILES dtransform.h5 test_filters.h5 get_file_name.h5 - tstint1.h5 - tstint2.h5 + tstint*.h5 unlink_chunked.h5 btree2.h5 btree2_tmp.h5 objcopy_src.h5 objcopy_dst.h5 objcopy_ext.dat - trefer1.h5 - trefer2.h5 app_ref.h5 farray.h5 farray_tmp.h5 earray.h5 earray_tmp.h5 - efc0.h5 - efc1.h5 - efc2.h5 - efc3.h5 - efc4.h5 - efc5.h5 + efc*.h5 log_vfd_out.log + log_ros3_out.log + log_s3comms_out.log new_multi_file_v16-r.h5 new_multi_file_v16-s.h5 split_get_file_image_test-m.h5 @@ -422,13 +376,11 @@ set (test_CLEANFILES unregister_filter_2.h5 vds_virt.h5 vds_dapl.h5 - vds_src_0.h5 - vds_src_1.h5 + vds_src_*.h5 swmr_data.h5 use_use_append_chunk.h5 use_append_mchunks.h5 use_disable_mdc_flushes.h5 - tbogus.h5.copy flushrefresh.h5 flushrefresh_VERIFICATION_START flushrefresh_VERIFICATION_CHECKPOINT1 @@ -444,9 +396,19 @@ set (test_CLEANFILES cache_logging.out vds_swmr.h5 vds_swmr_src_*.h5 - tmp_vds_env/vds_src_2.h5 + swmr*.h5 + swmr_writer.out + swmr_writer.log.* + swmr_reader.out.* + swmr_reader.log.* + tbogus.h5.copy + cache_image_test.h5 direct_chunk.h5 native_vol_test.h5 + splitter*.h5 + splitter.log + mirror_rw/* + mirror_wo/* ) # Remove any output file left over from previous test run diff --git a/test/Makefile.am b/test/Makefile.am index 57080aa..a60d0a8 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -63,7 +63,7 @@ TEST_PROG= testhdf5 \ flush1 flush2 app_ref enum set_extent ttsafe enc_dec_plist \ enc_dec_plist_cross_platform getname vfd ros3 s3comms hdfs ntypes \ dangle dtransform reserved cross_read freespace mf vds file_image \ - unregister cache_logging cork swmr vol + unregister cache_logging cork swmr thread_id vol # List programs to be built when testing here. # error_test and err_compat are built at the same time as the other tests, but executed by testerror.sh. @@ -179,14 +179,15 @@ CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offse chunk_fixed.h5 copy_dcpl_newfile.h5 partial_chunks.h5 layout_extend.h5 \ zero_chunk.h5 chunk_single.h5 swmr_non_latest.h5 \ earray_hdr_fd.h5 farray_hdr_fd.h5 bt2_hdr_fd.h5 \ - storage_size.h5 dls_01_strings.h5 \ + storage_size.h5 dls_01_strings.h5 power2up.h5 version_bounds.h5 \ + alloc_0sized.h5 \ extend.h5 istore.h5 extlinks*.h5 frspace.h5 links*.h5 \ sys_file1 tfile[1-7].h5 th5s[1-4].h5 lheap.h5 fheap.h5 ohdr.h5 \ stab.h5 extern_[1-5].h5 extern_[1-4][rw].raw gheap[0-4].h5 \ - ohdr_min_a.h5 ohdr_min_b.h5 min_dset_ohdr_testfile.h5\ + ohdr_min_a.h5 ohdr_min_b.h5 min_dset_ohdr_testfile.h5 \ dt_arith[1-2] links.h5 links[0-6]*.h5 extlinks[0-15].h5 \ - tmp tmp_links tmp2_links tmp_links_env tmp_vds_env \ - big.data big[0-9][0-9][0-9][0-9][0-9].h5 \ + tmp tmp_links tmp2_links tmp_links_env tmp_vds tmp_vds_env \ + big.data big[0-9][0-9][0-9][0-9][0-9].h5 \ stdio.h5 sec2.h5 dtypes[0-9].h5 dtypes1[0].h5 dt_arith[1-2].h5 tattr.h5 \ tselect.h5 mtime.h5 unlink.h5 unicode.h5 coord.h5 \ fillval_[0-9].h5 fillval.raw mount_[0-9].h5 testmeta.h5 ttime.h5 \ @@ -201,19 +202,21 @@ CHECK_CLEANFILES+=accum.h5 cmpd_dset.h5 compact_dataset.h5 dataset.h5 dset_offse new_move_[ab].h5 ntypes.h5 dangle.h5 error_test.h5 err_compat.h5 \ dtransform.h5 test_filters.h5 get_file_name.h5 tstint[1-2].h5 \ unlink_chunked.h5 btree2.h5 btree2_tmp.h5 objcopy_src.h5 objcopy_dst.h5 \ - objcopy_ext.dat trefer1.h5 trefer2.h5 app_ref.h5 farray.h5 farray_tmp.h5 \ + objcopy_ext.dat app_ref.h5 farray.h5 farray_tmp.h5 \ earray.h5 earray_tmp.h5 efc[0-5].h5 log_vfd_out.log log_ros3_out.log \ log_s3comms_out.log new_multi_file_v16-r.h5 new_multi_file_v16-s.h5 \ split_get_file_image_test-m.h5 split_get_file_image_test-r.h5 \ file_image_core_test.h5.copy unregister_filter_1.h5 unregister_filter_2.h5 \ vds_virt.h5 vds_dapl.h5 vds_src_[0-1].h5 \ - swmr_data.h5 use_use_append_chunk.h5 use_append_mchunks.h5 use_disable_mdc_flushes.h5 \ - flushrefresh.h5 flushrefresh_VERIFICATION_START \ + swmr_data.h5 use_use_append_chunk.h5 use_append_mchunks.h5 \ + use_disable_mdc_flushes.h5 flushrefresh.h5 flushrefresh_VERIFICATION_START \ flushrefresh_VERIFICATION_CHECKPOINT1 flushrefresh_VERIFICATION_CHECKPOINT2 \ - flushrefresh_VERIFICATION_DONE atomic_data accum_swmr_big.h5 ohdr_swmr.h5 \ + flushrefresh_VERIFICATION_DONE filenotclosed.h5 del_many_dense_attrs.h5 \ + atomic_data accum_swmr_big.h5 ohdr_swmr.h5 \ test_swmr*.h5 cache_logging.h5 cache_logging.out vds_swmr.h5 vds_swmr_src_*.h5 \ swmr[0-2].h5 swmr_writer.out swmr_writer.log.* swmr_reader.out.* swmr_reader.log.* \ - tbogus.h5.copy cache_image_test.h5 direct_chunk.h5 native_vol_test.h5 + tbogus.h5.copy cache_image_test.h5 direct_chunk.h5 native_vol_test.h5 \ + splitter*.h5 splitter.log mirror_rw mirror_ro # Sources for testhdf5 executable testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \ diff --git a/test/dsets.c b/test/dsets.c index 5eb8763..7f2eda5 100644 --- a/test/dsets.c +++ b/test/dsets.c @@ -83,6 +83,7 @@ const char *FILENAME[] = { "dls_01_strings", /* 23 */ "power2up", /* 24 */ "version_bounds", /* 25 */ + "alloc_0sized", /* 26 */ NULL }; @@ -3077,7 +3078,7 @@ test_nbit_float(hid_t file) */ for(i = 0; i < (size_t)size[0]; i++) { for(j = 0; j < (size_t)size[1]; j++) { - if(!(orig_data[i][j] == orig_data[i][j])) + if(HDisnan(orig_data[i][j])) continue; /* skip if value is NaN */ if(!H5_FLT_ABS_EQUAL(new_data[i][j], orig_data[i][j])) { H5_FAILED(); @@ -3209,7 +3210,7 @@ test_nbit_double(hid_t file) */ for(i = 0; i < (size_t)size[0]; i++) { for(j = 0; j < (size_t)size[1]; j++) { - if(!(orig_data[i][j] == orig_data[i][j])) + if(HDisnan(orig_data[i][j])) continue; /* skip if value is NaN */ if(!H5_DBL_ABS_EQUAL(new_data[i][j], orig_data[i][j])) { H5_FAILED(); @@ -3544,7 +3545,7 @@ test_nbit_compound(hid_t file) if(((unsigned)new_data[i][j].i & i_mask) != ((unsigned)orig_data[i][j].i & i_mask) || ((unsigned)new_data[i][j].c & c_mask) != ((unsigned)orig_data[i][j].c & c_mask) || ((unsigned)new_data[i][j].s & s_mask) != ((unsigned)orig_data[i][j].s & s_mask) || - (orig_data[i][j].f == orig_data[i][j].f && !H5_FLT_ABS_EQUAL(new_data[i][j].f, orig_data[i][j].f))) + (!HDisnan(orig_data[i][j].f) && !H5_FLT_ABS_EQUAL(new_data[i][j].f, orig_data[i][j].f))) { H5_FAILED(); HDprintf(" Read different values than written.\n"); @@ -3866,7 +3867,7 @@ test_nbit_compound_2(hid_t file) if(((unsigned)new_data[i][j].d[m][n].i & i_mask) != ((unsigned)orig_data[i][j].d[m][n].i & i_mask)|| ((unsigned)new_data[i][j].d[m][n].c & c_mask) != ((unsigned)orig_data[i][j].d[m][n].c & c_mask)|| ((unsigned)new_data[i][j].d[m][n].s & s_mask) != ((unsigned)orig_data[i][j].d[m][n].s & s_mask)|| - (new_data[i][j].d[m][n].f == new_data[i][j].d[m][n].f && !H5_FLT_ABS_EQUAL(new_data[i][j].d[m][n].f, new_data[i][j].d[m][n].f))) { + (!HDisnan(new_data[i][j].d[m][n].f) && !H5_FLT_ABS_EQUAL(new_data[i][j].d[m][n].f, new_data[i][j].d[m][n].f))) { d_failed = 1; goto out; } @@ -3875,7 +3876,7 @@ out: if(((unsigned)new_data[i][j].a.i & i_mask) != ((unsigned)orig_data[i][j].a.i & i_mask)|| ((unsigned)new_data[i][j].a.c & c_mask) != ((unsigned)orig_data[i][j].a.c & c_mask)|| ((unsigned)new_data[i][j].a.s & s_mask) != ((unsigned)orig_data[i][j].a.s & s_mask)|| - (new_data[i][j].a.f == new_data[i][j].a.f && !H5_FLT_ABS_EQUAL(new_data[i][j].a.f, new_data[i][j].a.f)) || + (!HDisnan(new_data[i][j].a.f) && !H5_FLT_ABS_EQUAL(new_data[i][j].a.f, new_data[i][j].a.f)) || new_data[i][j].v != orig_data[i][j].v || b_failed || d_failed) { H5_FAILED(); HDprintf(" Read different values than written.\n"); @@ -7034,12 +7035,12 @@ error: * * If either argument is zero, then the result is undefined. */ -static long -gcd(const long l0, const long r0) +static H5_ATTR_CONST long +gcd(long l0, long r0) { long magnitude, remainder; bool negative = ((l0 < 0) != (r0 < 0)); - long l = labs(l0), r = labs(r0); + long l = HDlabs(l0), r = HDlabs(r0); do { if (l < r) { @@ -13259,6 +13260,197 @@ error: } /* end test_object_header_minimization_dcpl() */ +/*----------------------------------------------------------------------------- + * Function: test_0sized_dset_metadata_alloc + * + * Purpose: Tests the metadata allocation for 0-sized datasets. + * + * Return: Success/pass: 0 + * Failure/error: -1 + * + * Programmer: Quincey Koziol + * 2020 April 30 + * + *----------------------------------------------------------------------------- + */ +static herr_t +test_0sized_dset_metadata_alloc(hid_t fapl_id) +{ + char filename[FILENAME_BUF_SIZE] = ""; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id_copy = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t dcpl_id_copy = H5I_INVALID_HID; + hid_t dset_space_id = H5I_INVALID_HID; + hid_t buf_space_id = H5I_INVALID_HID; + unsigned new_format; /* Whether to use latest file format */ + + TESTING("allocation of metadata for 0-sized datasets"); + + /*********/ + /* SETUP */ + /*********/ + + if(NULL == h5_fixname(FILENAME[26], fapl_id, filename, sizeof(filename))) + FAIL_STACK_ERROR + + /* Create DCPL for the dataset */ + if((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + FAIL_STACK_ERROR + + + /*************/ + /* RUN TESTS */ + /*************/ + + /* Iterate over file format versions */ + for(new_format = FALSE; new_format <= TRUE; new_format++) { + H5D_layout_t layout; /* Dataset layout type */ + H5D_alloc_time_t alloc_time; /* Storage allocation time */ + + /* Copy the file access property list */ + if((fapl_id_copy = H5Pcopy(fapl_id)) < 0) + FAIL_STACK_ERROR + + /* Set the "use the latest version of the format" bounds for creating objects in the file */ + if(new_format) + if(H5Pset_libver_bounds(fapl_id_copy, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) + FAIL_STACK_ERROR + + /* Create test file */ + if((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id_copy)) < 0) + FAIL_STACK_ERROR + + /* Close the copy of the FAPL */ + if(H5Pclose(fapl_id_copy) < 0) + FAIL_STACK_ERROR + + /* Iterate over combinations of testing parameters */ + for(layout = H5D_COMPACT; layout <= H5D_CHUNKED; layout++) { + for(alloc_time = H5D_ALLOC_TIME_EARLY; alloc_time <= H5D_ALLOC_TIME_INCR; alloc_time++) { + const hsize_t dims[1] = {0}; /* Dataset dimensions */ + const hsize_t max_dims[1] = {H5S_UNLIMITED}; /* Maximum dataset dimensions */ + const hsize_t chunk_dims[1] = {100}; /* Chunk dimensions */ + char dset_name[32]; /* Dataset name */ + H5O_native_info_t nat_info; /* Information about the dataset */ + + /* Compact storage must have early allocation */ + if(H5D_COMPACT == layout && H5D_ALLOC_TIME_EARLY != alloc_time) + continue; + + /* Compose dataset name */ + HDsnprintf(dset_name, sizeof(dset_name), "/Dataset-%u-%u", (unsigned)alloc_time, (unsigned)layout); + + /* Set up DCPL */ + if((dcpl_id_copy = H5Pcopy(dcpl_id)) < 0) + FAIL_STACK_ERROR + if(H5Pset_alloc_time(dcpl_id_copy, alloc_time) < 0) + FAIL_STACK_ERROR + if(H5Pset_layout(dcpl_id_copy, layout) < 0) + FAIL_STACK_ERROR + if(H5D_CHUNKED == layout) + if(H5Pset_chunk(dcpl_id_copy, 1, chunk_dims) < 0) + FAIL_STACK_ERROR + + /* Create the dataspace for the dataset */ + if((dset_space_id = H5Screate_simple(1, dims, (H5D_CHUNKED == layout ? max_dims : NULL))) < 0) + FAIL_STACK_ERROR + + /* Create the dataset with the appropriate parameters */ + if((dset_id = H5Dcreate2(file_id, dset_name, H5T_NATIVE_INT, dset_space_id, H5P_DEFAULT, dcpl_id_copy, H5P_DEFAULT)) < 0) + FAIL_STACK_ERROR + + /* Close objects used to create dataset */ + if(H5Pclose(dcpl_id_copy) < 0) + FAIL_STACK_ERROR + if(H5Sclose(dset_space_id) < 0) + FAIL_STACK_ERROR + + /* Retrieve & verify the dataset's index info */ + HDmemset(&nat_info, 0, sizeof(nat_info)); + if(H5Oget_native_info(dset_id, &nat_info, H5O_NATIVE_INFO_META_SIZE) < 0) + FAIL_STACK_ERROR + if(0 != nat_info.meta_size.obj.index_size) + FAIL_PUTS_ERROR("dataset index allocation size is non-zero") + + /* If chunked, try extending and verify that the index is allocated */ + if(H5D_CHUNKED == layout) { + const hsize_t new_dims[1] = {1500}; /* New dataset dimensions */ + const hsize_t mem_dims[1] = {1}; /* Memory buffer dataset dimensions */ + const hsize_t coord = 0; /* Dataset selection coordinate */ + int val = 0; /* Data value */ + + /* Extend dataset */ + if(H5Dset_extent(dset_id, new_dims) < 0) + FAIL_STACK_ERROR + + /* Get the dataspace for the dataset & set single point selection */ + if((dset_space_id = H5Dget_space(dset_id)) < 0) + FAIL_STACK_ERROR + if(H5Sselect_elements(dset_space_id, H5S_SELECT_SET, (size_t)1, (const hsize_t *)&coord) < 0) + FAIL_STACK_ERROR + + /* Create memory dataspace, with only one element */ + if((buf_space_id = H5Screate_simple(1, mem_dims, NULL)) < 0) + FAIL_STACK_ERROR + + /* Write the data to the dataset */ + if(H5Dwrite(dset_id, H5T_NATIVE_INT, buf_space_id, dset_space_id, H5P_DEFAULT, &val) < 0) + FAIL_STACK_ERROR + + /* Close objects used to perform I/O */ + if(H5Sclose(dset_space_id) < 0) + FAIL_STACK_ERROR + if(H5Sclose(buf_space_id) < 0) + FAIL_STACK_ERROR + + /* Retrieve & verify the dataset's index info */ + HDmemset(&nat_info, 0, sizeof(nat_info)); + if(H5Oget_native_info(dset_id, &nat_info, H5O_NATIVE_INFO_META_SIZE) < 0) + FAIL_STACK_ERROR + if(0 == nat_info.meta_size.obj.index_size) + FAIL_PUTS_ERROR("dataset index allocation size is zero") + } /* end if */ + + /* Close dataset */ + if(H5Dclose(dset_id) < 0) + FAIL_STACK_ERROR + } /* end for */ + } /* end for */ + + /* Close test file */ + if(H5Fclose(file_id) < 0) + FAIL_STACK_ERROR + } /* end for */ + + + /************/ + /* TEARDOWN */ + /************/ + + if(H5Pclose(dcpl_id) < 0) + FAIL_STACK_ERROR + + PASSED(); + + return SUCCEED; + +error: + H5E_BEGIN_TRY { + H5Pclose(dset_space_id); + H5Pclose(buf_space_id); + H5Pclose(fapl_id_copy); + H5Pclose(dcpl_id_copy); + H5Pclose(dcpl_id); + H5Dclose(dset_id); + H5Fclose(file_id); + } H5E_END_TRY; + + return FAIL; +} /* end test_0sized_dset_metadata_alloc() */ + + /*------------------------------------------------------------------------- * Function: main * @@ -13470,7 +13662,8 @@ main(void) nerrors += (test_object_header_minimization_dcpl() < 0 ? 1 : 0); /* Run misc tests */ - nerrors += dls_01_main(); + nerrors += (dls_01_main() < 0 ? 1 : 0); + nerrors += (test_0sized_dset_metadata_alloc(fapl) < 0 ? 1 : 0); /* Verify symbol table messages are cached */ nerrors += (h5_verify_cached_stabs(FILENAME, fapl) < 0 ? 1 : 0); diff --git a/test/h5test.c b/test/h5test.c index be974fe..ce573de 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -1164,10 +1164,8 @@ h5_show_hostname(void) else HDprintf("thread 0."); } -#elif defined(H5_HAVE_THREADSAFE) - HDprintf("thread %lu.", HDpthread_self_ulong()); #else - HDprintf("thread 0."); + HDprintf("thread %" PRIu64 ".", H5TS_thread_id()); #endif #ifdef H5_HAVE_WIN32_API diff --git a/test/thread_id.c b/test/thread_id.c new file mode 100644 index 0000000..75ffe17 --- /dev/null +++ b/test/thread_id.c @@ -0,0 +1,163 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * 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 COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Check that a thread ID returned by H5TS_thread_id() possesses the + * following properties: + * + * 1 ID >= 1. + * 2 The ID is constant over the thread's lifetime. + * 3 No two threads share an ID during their lifetimes. + * 4 A thread's ID is available for reuse as soon as it is joined. + */ +#include <err.h> + +/* + * Include required headers. This file tests internal library functions, + * so we include the private headers here. + */ +#include "testhdf5.h" + +#define threads_failure(_call, _result) do { \ + errx(EXIT_FAILURE, "%s.%d: " #_call ": %s", __func__, \ + __LINE__, strerror(_result)); \ +} while (false) + +#if defined(H5_HAVE_THREADSAFE) && !defined(H5_HAVE_WIN_THREADS) + +#define NTHREADS 5 + +static volatile bool failed = false; +static pthread_barrier_t barrier; +static bool used[NTHREADS]; +static pthread_mutex_t used_lock; + +static void +atomic_printf(const char *fmt, ...) +{ + char buf[80]; + va_list ap; + ssize_t nprinted, nwritten; + + va_start(ap, fmt); + nprinted = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + if (nprinted == -1) + err(EXIT_FAILURE, "%s.%d: vsnprintf", __func__, __LINE__); + else if (nprinted >= (ssize_t)sizeof(buf)) + errx(EXIT_FAILURE, "%s.%d: vsnprintf overflowed", __func__, __LINE__); + + nwritten = write(STDOUT_FILENO, buf, (size_t)nprinted); + if (nwritten < nprinted) { + errx(EXIT_FAILURE, "%s.%d: write error or short write", + __func__, __LINE__); + } +} + +/* Each thread runs this routine. The routine fetches the current + * thread's ID, makes sure that it is in the expected range, makes + * sure that in this round of testing, no two threads shared the + * same ID, + */ +static void * +thread_main(void H5_ATTR_UNUSED *arg) +{ + uint64_t ntid, tid; + + tid = H5TS_thread_id(); + + if (tid < 1 || NTHREADS < tid) { + atomic_printf("unexpected tid %" PRIu64 " FAIL\n", tid); + goto pre_barrier_error; + } + pthread_mutex_lock(&used_lock); + if (used[tid - 1]) { + atomic_printf("reused tid %" PRIu64 " FAIL\n", tid); + pthread_mutex_unlock(&used_lock); + goto pre_barrier_error; + } + used[tid - 1] = true; + pthread_mutex_unlock(&used_lock); + + atomic_printf("tid %" PRIu64 " in [1, %d] PASS\n", tid, NTHREADS); + pthread_barrier_wait(&barrier); + + ntid = H5TS_thread_id(); + if (ntid != tid) { + atomic_printf("tid changed from %" PRIu64 " to %" PRIu64 " FAIL\n", + tid, ntid); + failed = true; + } + return NULL; +pre_barrier_error: + pthread_barrier_wait(&barrier); + failed = true; + return NULL; +} + +int +main(void) +{ + int i, rc, times; + pthread_t threads[NTHREADS]; + + /* Run H5open() to initialize the library's thread-ID freelist, + * mutex, etc. + */ + if (H5open() != SUCCEED) + errx(EXIT_FAILURE, "%s.%d: H5open failed", __func__, __LINE__); + + if ((rc = pthread_mutex_init(&used_lock, NULL)) == -1) + threads_failure(pthread_mutex_init, rc); + + if ((rc = pthread_barrier_init(&barrier, NULL, NTHREADS)) != 0) + threads_failure(pthread_barrier_init, rc); + + /* Start the test threads and join them twice to make sure that + * the thread IDs are recycled in the second round. + */ + for (times = 0; times < 2; times++) { + + for (i = 0; i < NTHREADS; i++) + used[i] = false; // access synchronized by thread create/join + + for (i = 0; i < NTHREADS; i++) { + rc = pthread_create(&threads[i], NULL, thread_main, NULL); + if (rc != 0) + threads_failure(pthread_create, rc); + } + + for (i = 0; i < NTHREADS; i++) { + rc = pthread_join(threads[i], NULL); + if (rc != 0) + threads_failure(pthread_join, rc); + } + + for (i = 0; i < NTHREADS; i++) { + if (!used[i]) // access synchronized by thread create/join + errx(EXIT_FAILURE, "thread ID %d did not run.", i + 1); + } + } + if ((rc = pthread_barrier_destroy(&barrier)) != 0) + threads_failure(pthread_barrier_destroy, rc); + return failed ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#else /*H5_HAVE_THREADSAFE && !H5_HAVE_WIN_THREADS*/ +int +main(void) +{ + errx(EXIT_FAILURE, "not implemented in this configuration."); +} + +#endif /*H5_HAVE_THREADSAFE && !H5_HAVE_WIN_THREADS*/ + |