mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-02-11 16:01:00 +08:00
Complete overhaul of the concurrency-related aspects of the library (threading, atomics, locking, etc.), adding private routines in the H5TS package to allow internal algorithms to use all of these capabilities. Adds many new features & components in the H5TS package that are equivalent to common concurrency data structures and capabilities: "regular" and recursive mutices, condition variables, semaphores, thread barriers, 'once' support, thread pools, atomic variables, thread-local keys, and spawning & joining internal threads. Now supports C11, pthreads, and Windows threading for all H5TS capabilities, except the recursive readers/writers lock, which is not supported on Windows (because Windows threads don't provide a callback on thread-local variable deletion). The "global" API lock is switched to use a recursive mutex from the H5TS package, instead of its own variant. API context code (H5CX package) and error stacks (H5E package) now use the common thread-local info, instead of their own variants. Subfiling code is switched from using Mercury threading features to the new internal H5TS features. Removes the mercury threading code. Adds a configure option (--enable-threads / HDF5_ENABLE_THREADS), enabled by default, to control whether threading is enabled within the library.
166 lines
5.7 KiB
C
166 lines
5.7 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* 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. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/********************************************************************
|
|
*
|
|
* Test the correctness of the threadsafety developer API routines
|
|
*
|
|
********************************************************************/
|
|
|
|
#include "ttsafe.h"
|
|
|
|
#ifdef H5_HAVE_THREADSAFE
|
|
|
|
typedef struct {
|
|
H5TS_barrier_t *barrier;
|
|
} tts_develop_api_udata_t;
|
|
|
|
/*
|
|
**********************************************************************
|
|
* tts_develop_api_thr_1
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
static H5TS_THREAD_RETURN_TYPE
|
|
tts_develop_api_thr_1(void *_udata)
|
|
{
|
|
tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata;
|
|
unsigned lock_count = UINT_MAX;
|
|
bool acquired = false;
|
|
herr_t result;
|
|
|
|
/* Acquire the API lock - should acquire it */
|
|
result = H5TSmutex_acquire(1, &acquired);
|
|
CHECK_I(result, "H5TSmutex_acquire");
|
|
VERIFY(acquired, true, "H5TSmutex_acquire");
|
|
|
|
result = H5TS_barrier_wait(udata->barrier);
|
|
CHECK_I(result, "H5TS_barrier_wait");
|
|
|
|
/* Thread #2 will attempt (unsuccessfully) to acquire the API lock */
|
|
|
|
result = H5TS_barrier_wait(udata->barrier);
|
|
CHECK_I(result, "H5TS_barrier_wait");
|
|
|
|
/* Release the API lock */
|
|
result = H5TSmutex_release(&lock_count);
|
|
CHECK_I(result, "H5TSmutex_release");
|
|
VERIFY(lock_count, 1, "H5TSmutex_release");
|
|
|
|
return (H5TS_thread_ret_t)0;
|
|
} /* end tts_develop_api_thr_1() */
|
|
|
|
/*
|
|
**********************************************************************
|
|
* tts_develop_api_thr_2
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
static H5TS_THREAD_RETURN_TYPE
|
|
tts_develop_api_thr_2(void *_udata)
|
|
{
|
|
tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata;
|
|
bool acquired = false;
|
|
herr_t result;
|
|
|
|
/* Thread #1 will acquire the API lock */
|
|
|
|
result = H5TS_barrier_wait(udata->barrier);
|
|
CHECK_I(result, "H5TS_barrier_wait");
|
|
|
|
/* Attempt to acquire the API lock - should not acquire it */
|
|
result = H5TSmutex_acquire(1, &acquired);
|
|
CHECK_I(result, "H5TSmutex_acquire");
|
|
VERIFY(acquired, false, "H5TSmutex_acquire");
|
|
|
|
result = H5TS_barrier_wait(udata->barrier);
|
|
CHECK_I(result, "H5TS_barrier_wait");
|
|
|
|
/* Thread #1 will release the API lock */
|
|
|
|
return (H5TS_thread_ret_t)0;
|
|
} /* end tts_develop_api_thr_2() */
|
|
|
|
/*
|
|
**********************************************************************
|
|
* tts_develop_api
|
|
*
|
|
**********************************************************************
|
|
*/
|
|
void
|
|
tts_develop_api(void)
|
|
{
|
|
H5TS_thread_t thread_1, thread_2;
|
|
H5TS_barrier_t barrier;
|
|
unsigned lock_count = UINT_MAX;
|
|
bool acquired = false;
|
|
tts_develop_api_udata_t udata;
|
|
unsigned api_count_1 = 0, api_count_2 = 0;
|
|
herr_t result;
|
|
|
|
/* Check that API count increases with each API call */
|
|
result = H5TSmutex_get_attempt_count(&api_count_1);
|
|
CHECK_I(result, "H5TSmutex_get_attempt_count");
|
|
|
|
/* No-op API call, to increment the API counter */
|
|
result = H5garbage_collect();
|
|
CHECK_I(result, "H5garbage_collect");
|
|
|
|
result = H5TSmutex_get_attempt_count(&api_count_2);
|
|
CHECK_I(result, "H5TSmutex_get_attempt_count");
|
|
|
|
VERIFY(api_count_2, (api_count_1 + 1), "H5TSmutex_get_attempt_count");
|
|
|
|
/* Check H5TSmutex_acquire & H5TSmutex_release in thread callbacks */
|
|
|
|
/* Create the thread barrier for the two threads */
|
|
result = H5TS_barrier_init(&barrier, 2);
|
|
CHECK_I(result, "H5TS_barrier_init");
|
|
|
|
/* Create the threads */
|
|
udata.barrier = &barrier;
|
|
result = H5TS_thread_create(&thread_1, tts_develop_api_thr_1, &udata);
|
|
CHECK_I(result, "H5TS_thread_create");
|
|
result = H5TS_thread_create(&thread_2, tts_develop_api_thr_2, &udata);
|
|
CHECK_I(result, "H5TS_thread_create");
|
|
|
|
/* Wait for threads to complete. */
|
|
result = H5TS_thread_join(thread_1, NULL);
|
|
CHECK_I(result, "H5TS_thread_join");
|
|
result = H5TS_thread_join(thread_2, NULL);
|
|
CHECK_I(result, "H5TS_thread_join");
|
|
|
|
result = H5TS_barrier_destroy(&barrier);
|
|
CHECK_I(result, "H5TS_barrier_destroy");
|
|
|
|
/* Test multiple / recursive acquisition of the API lock */
|
|
|
|
/* Acquire the API lock - should acquire it */
|
|
result = H5TSmutex_acquire(1, &acquired);
|
|
CHECK_I(result, "H5TSmutex_acquire");
|
|
VERIFY(acquired, true, "H5TSmutex_acquire");
|
|
|
|
/* Acquire the API lock again - should acquire it, since it's the same thread */
|
|
acquired = false;
|
|
result = H5TSmutex_acquire(1, &acquired);
|
|
CHECK_I(result, "H5TSmutex_acquire");
|
|
VERIFY(acquired, true, "H5TSmutex_acquire");
|
|
|
|
/* Release the API lock */
|
|
result = H5TSmutex_release(&lock_count);
|
|
CHECK_I(result, "H5TSmutex_release");
|
|
VERIFY(lock_count, 2, "H5TSmutex_release");
|
|
|
|
} /* end tts_develop_api() */
|
|
|
|
#endif /*H5_HAVE_THREADSAFE*/
|