summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST1
-rw-r--r--release_docs/RELEASE.txt5
-rw-r--r--src/H5CS.c6
-rw-r--r--src/H5Dint.c2
-rw-r--r--src/H5Dlayout.c6
-rw-r--r--src/H5Eint.c8
-rw-r--r--src/H5TS.c119
-rw-r--r--src/H5TSprivate.h3
-rw-r--r--src/H5private.h5
-rw-r--r--src/H5win32defs.h4
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/CMakeTests.cmake124
-rw-r--r--test/Makefile.am23
-rw-r--r--test/dsets.c211
-rw-r--r--test/h5test.c4
-rw-r--r--test/thread_id.c163
16 files changed, 557 insertions, 128 deletions
diff --git a/MANIFEST b/MANIFEST
index 2d9749b..c70fe87 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -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:
------
diff --git a/src/H5CS.c b/src/H5CS.c
index 0a3dcce..3fccce4 100644
--- a/src/H5CS.c
+++ b/src/H5CS.c
@@ -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 */
diff --git a/src/H5TS.c b/src/H5TS.c
index 10e14d5..7a801e2 100644
--- a/src/H5TS.c
+++ b/src/H5TS.c
@@ -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*/
+