summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDana Robinson <derobins@hdfgroup.org>2021-04-07 17:13:12 (GMT)
committerDana Robinson <derobins@hdfgroup.org>2021-04-07 17:13:12 (GMT)
commita96849027a93bd2b8011b763f9e4975676a14965 (patch)
tree9099788a4b3494dbc66137ee40b0b31aa3da9a3d /src
parent17c7cf94755aabd4885a3cbd287e65240ab04b49 (diff)
downloadhdf5-a96849027a93bd2b8011b763f9e4975676a14965.zip
hdf5-a96849027a93bd2b8011b763f9e4975676a14965.tar.gz
hdf5-a96849027a93bd2b8011b763f9e4975676a14965.tar.bz2
Brings thread-safety changes from develop
Diffstat (limited to 'src')
-rw-r--r--src/H5TS.c568
-rw-r--r--src/H5TSprivate.h53
-rw-r--r--src/H5private.h51
-rw-r--r--src/hdf5.h1
4 files changed, 533 insertions, 140 deletions
diff --git a/src/H5TS.c b/src/H5TS.c
index 9525843..258c9df 100644
--- a/src/H5TS.c
+++ b/src/H5TS.c
@@ -11,31 +11,104 @@
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-/* private headers */
-#include "H5private.h" /*library */
-#include "H5Eprivate.h" /*error handling */
-#include "H5MMprivate.h" /*memory management functions */
+/*
+ * Purpose: This file contains the framework for ensuring that the global
+ * library lock is held when an API routine is called. This
+ * framework works in concert with the FUNC_ENTER_API / FUNC_LEAVE_API
+ * macros defined in H5private.h.
+ *
+ * Note: Because this threadsafety framework operates outside the library,
+ * it does not use the error stack and only uses the "namecheck only"
+ * FUNC_ENTER_* / FUNC_LEAVE_* macros.
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5MMprivate.h" /* Memory management */
#ifdef H5_HAVE_THREADSAFE
-/* Module specific data structures */
+/****************/
+/* Local Macros */
+/****************/
-/* cancelability structure */
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* Cancelability structure */
typedef struct H5TS_cancel_struct {
int previous_state;
unsigned int cancel_count;
} H5TS_cancel_t;
+/* Function pointer typedef for thread callback function */
+typedef void *(*H5TS_thread_cb_t)(void *);
+
+/********************/
+/* Local Prototypes */
+/********************/
+static void H5TS__key_destructor(void *key_val);
+static herr_t H5TS__mutex_acquire(H5TS_mutex_t *mutex, unsigned int lock_count, hbool_t *acquired);
+static herr_t H5TS__mutex_unlock(H5TS_mutex_t *mutex, unsigned int *lock_count);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
/* Global variable definitions */
#ifdef H5_HAVE_WIN_THREADS
H5TS_once_t H5TS_first_init_g;
-#else /* H5_HAVE_WIN_THREADS */
-H5TS_once_t H5TS_first_init_g = PTHREAD_ONCE_INIT;
-#endif /* H5_HAVE_WIN_THREADS */
-H5TS_key_t H5TS_errstk_key_g;
+#else
+H5TS_once_t H5TS_first_init_g = PTHREAD_ONCE_INIT;
+#endif
+
+/* Thread-local keys, used by other interfaces */
+/* Error stack */
+#ifdef H5_HAVE_WIN_THREADS
+H5TS_key_t H5TS_errstk_key_g = TLS_OUT_OF_INDEXES;
+#else
+H5TS_key_t H5TS_errstk_key_g;
+#endif
+
+#ifdef H5_HAVE_CODESTACK
+/* Function stack */
+#ifdef H5_HAVE_WIN_THREADS
+H5TS_key_t H5TS_funcstk_key_g = TLS_OUT_OF_INDEXES;
+#else
H5TS_key_t H5TS_funcstk_key_g;
-H5TS_key_t H5TS_apictx_key_g;
-H5TS_key_t H5TS_cancel_key_g;
+#endif
+#endif /* H5_HAVE_CODESTACK */
+
+/* API context */
+#ifdef H5_HAVE_WIN_THREADS
+H5TS_key_t H5TS_apictx_key_g = TLS_OUT_OF_INDEXES;
+#else
+H5TS_key_t H5TS_apictx_key_g;
+#endif
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Thread-local keys, used in this module */
+/* Thread cancellation state */
+#ifdef H5_HAVE_WIN_THREADS
+static H5TS_key_t H5TS_cancel_key_s = TLS_OUT_OF_INDEXES;
+#else
+static H5TS_key_t H5TS_cancel_key_s;
+#endif
#ifndef H5_HAVE_WIN_THREADS
@@ -64,12 +137,13 @@ static H5TS_key_t H5TS_tid_key;
/*--------------------------------------------------------------------------
* NAME
- * H5TS_key_destructor
+ * H5TS__key_destructor
*
* USAGE
- * H5TS_key_destructor()
+ * H5TS__key_destructor()
*
* RETURNS
+ * None
*
* DESCRIPTION
* Frees the memory for a key. Called by each thread as it exits.
@@ -82,12 +156,16 @@ static H5TS_key_t H5TS_tid_key;
*--------------------------------------------------------------------------
*/
static void
-H5TS_key_destructor(void *key_val)
+H5TS__key_destructor(void *key_val)
{
+ FUNC_ENTER_STATIC_NAMECHECK_ONLY
+
/* Use HDfree here instead of H5MM_xfree(), to avoid calling the H5CS routines */
if (key_val != NULL)
HDfree(key_val);
-}
+
+ FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
+} /* end H5TS__key_destructor() */
#ifndef H5_HAVE_WIN_THREADS
@@ -114,10 +192,10 @@ H5TS_tid_destructor(void *_v)
return;
/* TBD use an atomic CAS */
- pthread_mutex_lock(&H5TS_tid_mtx);
+ HDpthread_mutex_lock(&H5TS_tid_mtx);
tid->next = H5TS_tid_next_free;
H5TS_tid_next_free = tid;
- pthread_mutex_unlock(&H5TS_tid_mtx);
+ HDpthread_mutex_unlock(&H5TS_tid_mtx);
}
/*--------------------------------------------------------------------------
@@ -137,8 +215,8 @@ H5TS_tid_destructor(void *_v)
static void
H5TS_tid_init(void)
{
- pthread_mutex_init(&H5TS_tid_mtx, NULL);
- pthread_key_create(&H5TS_tid_key, H5TS_tid_destructor);
+ HDpthread_mutex_init(&H5TS_tid_mtx, NULL);
+ HDpthread_key_create(&H5TS_tid_key, H5TS_tid_destructor);
}
/*--------------------------------------------------------------------------
@@ -168,7 +246,7 @@ H5TS_tid_init(void)
uint64_t
H5TS_thread_id(void)
{
- H5TS_tid_t *tid = pthread_getspecific(H5TS_tid_key);
+ H5TS_tid_t *tid = HDpthread_getspecific(H5TS_tid_key);
H5TS_tid_t proto_tid;
/* An ID is already assigned. */
@@ -182,20 +260,19 @@ H5TS_thread_id(void)
* point `tid` at `proto_tid` if we need to allocate some
* memory.
*/
- pthread_mutex_lock(&H5TS_tid_mtx);
+ HDpthread_mutex_lock(&H5TS_tid_mtx);
if ((tid = H5TS_tid_next_free) != NULL)
H5TS_tid_next_free = tid->next;
else if (H5TS_tid_next_id != UINT64_MAX) {
tid = &proto_tid;
tid->id = ++H5TS_tid_next_id;
}
- pthread_mutex_unlock(&H5TS_tid_mtx);
+ HDpthread_mutex_unlock(&H5TS_tid_mtx);
/* If a prototype ID record was established, copy it to the heap. */
- if (tid == &proto_tid) {
+ if (tid == &proto_tid)
if ((tid = HDmalloc(sizeof(*tid))) != NULL)
*tid = proto_tid;
- }
if (tid == NULL)
return 0;
@@ -204,7 +281,7 @@ H5TS_thread_id(void)
* to it.
*/
tid->next = NULL;
- if (pthread_setspecific(H5TS_tid_key, tid) != 0) {
+ if (HDpthread_setspecific(H5TS_tid_key, tid) != 0) {
H5TS_tid_destructor(tid);
return 0;
}
@@ -237,6 +314,8 @@ H5TS_pthread_first_thread_init(void)
H5_g.H5_libinit_g = FALSE; /* Library hasn't been initialized */
H5_g.H5_libterm_g = FALSE; /* Library isn't being shutdown */
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
#ifdef H5_HAVE_WIN32_API
#ifdef PTW32_STATIC_LIB
pthread_win32_process_attach_np();
@@ -244,27 +323,116 @@ H5TS_pthread_first_thread_init(void)
#endif
/* initialize global API mutex lock */
- pthread_mutex_init(&H5_g.init_lock.atomic_lock, NULL);
- pthread_cond_init(&H5_g.init_lock.cond_var, NULL);
+ HDpthread_mutex_init(&H5_g.init_lock.atomic_lock, NULL);
+ HDpthread_cond_init(&H5_g.init_lock.cond_var, NULL);
H5_g.init_lock.lock_count = 0;
+ HDpthread_mutex_init(&H5_g.init_lock.atomic_lock2, NULL);
+ H5_g.init_lock.attempt_lock_count = 0;
+
/* Initialize integer thread identifiers. */
H5TS_tid_init();
/* initialize key for thread-specific error stacks */
- pthread_key_create(&H5TS_errstk_key_g, H5TS_key_destructor);
+ HDpthread_key_create(&H5TS_errstk_key_g, H5TS__key_destructor);
+#ifdef H5_HAVE_CODESTACK
/* initialize key for thread-specific function stacks */
- pthread_key_create(&H5TS_funcstk_key_g, H5TS_key_destructor);
+ HDpthread_key_create(&H5TS_funcstk_key_g, H5TS__key_destructor);
+#endif /* H5_HAVE_CODESTACK */
/* initialize key for thread-specific API contexts */
- pthread_key_create(&H5TS_apictx_key_g, H5TS_key_destructor);
+ HDpthread_key_create(&H5TS_apictx_key_g, H5TS__key_destructor);
/* initialize key for thread cancellability mechanism */
- pthread_key_create(&H5TS_cancel_key_g, H5TS_key_destructor);
-}
+ HDpthread_key_create(&H5TS_cancel_key_s, H5TS__key_destructor);
+
+ FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
+} /* end H5TS_pthread_first_thread_init() */
+#endif /* H5_HAVE_WIN_THREADS */
+
+/*--------------------------------------------------------------------------
+ * Function: H5TS__mutex_acquire
+ *
+ * Purpose: Attempts to acquire a mutex lock, without blocking
+ *
+ * Note: On success, the 'acquired' flag indicates if the HDF5 library
+ * global lock was acquired.
+ *
+ * Note: The Windows threads code is very likely bogus.
+ *
+ * Return: Non-negative on success / Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Februrary 27, 2019
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5TS__mutex_acquire(H5TS_mutex_t *mutex, unsigned int lock_count, hbool_t *acquired)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_STATIC_NAMECHECK_ONLY
+
+#ifdef H5_HAVE_WIN_THREADS
+ EnterCriticalSection(&mutex->CriticalSection);
+ *acquired = TRUE;
+#else /* H5_HAVE_WIN_THREADS */
+ /* Attempt to acquire the mutex lock */
+ if (0 == HDpthread_mutex_lock(&mutex->atomic_lock)) {
+ pthread_t my_thread_id = HDpthread_self();
+
+ /* Check if locked already */
+ if (mutex->lock_count) {
+ /* Check for this thread already owning the lock */
+ if (HDpthread_equal(my_thread_id, mutex->owner_thread)) {
+ /* Already owned by self - increment count */
+ mutex->lock_count += lock_count;
+ *acquired = TRUE;
+ } /* end if */
+ else
+ *acquired = FALSE;
+ } /* end if */
+ else {
+ /* Take ownership of the mutex */
+ mutex->owner_thread = my_thread_id;
+ mutex->lock_count = lock_count;
+ *acquired = TRUE;
+ } /* end else */
+
+ if (0 != HDpthread_mutex_unlock(&mutex->atomic_lock))
+ ret_value = -1;
+ } /* end if */
+ else
+ ret_value = -1;
#endif /* H5_HAVE_WIN_THREADS */
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
+} /* end H5TS__mutex_acquire() */
+
+/*--------------------------------------------------------------------------
+ * Function: H5TSmutex_acquire
+ *
+ * Purpose: Attempts to acquire the HDF5 library global lock
+ *
+ * Note: On success, the 'acquired' flag indicates if the HDF5 library
+ * global lock was acquired.
+ *
+ * Return: Non-negative on success / Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Februrary 27, 2019
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TSmutex_acquire(unsigned int lock_count, hbool_t *acquired){
+ FUNC_ENTER_API_NAMECHECK_ONLY
+
+ FUNC_LEAVE_API_NAMECHECK_ONLY(H5TS__mutex_acquire(&H5_g.init_lock, lock_count, acquired))}
+/* end H5TSmutex_acquire() */
+
/*--------------------------------------------------------------------------
* NAME
* H5TS_mutex_lock
@@ -273,7 +441,7 @@ H5TS_pthread_first_thread_init(void)
* H5TS_mutex_lock(&mutex_var)
*
* RETURNS
- * 0 on success and non-zero on error.
+ * Non-negative on success / Negative on failure
*
* DESCRIPTION
* Recursive lock semantics for HDF5 (locking) -
@@ -285,35 +453,105 @@ H5TS_pthread_first_thread_init(void)
*
*--------------------------------------------------------------------------
*/
-herr_t
-H5TS_mutex_lock(H5TS_mutex_t *mutex)
+herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex)
{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
#ifdef H5_HAVE_WIN_THREADS
EnterCriticalSection(&mutex->CriticalSection);
- return 0;
#else /* H5_HAVE_WIN_THREADS */
- herr_t ret_value = pthread_mutex_lock(&mutex->atomic_lock);
+ /* Acquire the "attempt" lock, increment the attempt lock count, release the lock */
+ ret_value = HDpthread_mutex_lock(&mutex->atomic_lock2);
+ if (ret_value)
+ HGOTO_DONE(ret_value);
+ mutex->attempt_lock_count++;
+ ret_value = HDpthread_mutex_unlock(&mutex->atomic_lock2);
+ if (ret_value)
+ HGOTO_DONE(ret_value);
+ /* Acquire the library lock */
+ ret_value = HDpthread_mutex_lock(&mutex->atomic_lock);
if (ret_value)
- return ret_value;
+ HGOTO_DONE(ret_value);
- if (mutex->lock_count && pthread_equal(pthread_self(), mutex->owner_thread)) {
+ /* Check if this thread already owns the lock */
+ if (mutex->lock_count && HDpthread_equal(HDpthread_self(), mutex->owner_thread))
/* already owned by self - increment count */
mutex->lock_count++;
- }
else {
- /* if owned by other thread, wait for condition signal */
+ /* Wait until the lock is released by current owner thread */
while (mutex->lock_count)
- pthread_cond_wait(&mutex->cond_var, &mutex->atomic_lock);
+ HDpthread_cond_wait(&mutex->cond_var, &mutex->atomic_lock);
/* After we've received the signal, take ownership of the mutex */
- mutex->owner_thread = pthread_self();
+ mutex->owner_thread = HDpthread_self();
mutex->lock_count = 1;
- }
+ } /* end else */
- return pthread_mutex_unlock(&mutex->atomic_lock);
+ /* Release the library lock */
+ ret_value = HDpthread_mutex_unlock(&mutex->atomic_lock);
+
+done:
#endif /* H5_HAVE_WIN_THREADS */
-}
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
+} /* end H5TS_mutex_lock() */
+
+/*--------------------------------------------------------------------------
+ * NAME
+ * H5TS__mutex_unlock
+ *
+ * USAGE
+ * H5TS__mutex_unlock(&mutex_var, &lock_count)
+ *
+ * RETURNS
+ * Non-negative on success / Negative on failure
+ *
+ * DESCRIPTION
+ * Recursive lock semantics for HDF5 (unlocking) -
+ * Reset the lock and return the current lock count
+ *
+ * PROGRAMMER: Houjun Tang
+ * Nov 3, 2020
+ *
+ *--------------------------------------------------------------------------
+ */
+static herr_t
+H5TS__mutex_unlock(H5TS_mutex_t *mutex, unsigned int *lock_count)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
+#ifdef H5_HAVE_WIN_THREADS
+ /* Releases ownership of the specified critical section object. */
+ LeaveCriticalSection(&mutex->CriticalSection);
+#else /* H5_HAVE_WIN_THREADS */
+
+ /* Reset the lock count for this thread */
+ ret_value = HDpthread_mutex_lock(&mutex->atomic_lock);
+ if (ret_value)
+ HGOTO_DONE(ret_value);
+ *lock_count = mutex->lock_count;
+ mutex->lock_count = 0;
+ ret_value = HDpthread_mutex_unlock(&mutex->atomic_lock);
+
+ /* If the lock count drops to zero, signal the condition variable, to
+ * wake another thread.
+ */
+ if (mutex->lock_count == 0) {
+ int err;
+
+ err = HDpthread_cond_signal(&mutex->cond_var);
+ if (err != 0)
+ ret_value = err;
+ } /* end if */
+
+done:
+#endif /* H5_HAVE_WIN_THREADS */
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
+} /* H5TS__mutex_unlock */
/*--------------------------------------------------------------------------
* NAME
@@ -323,7 +561,7 @@ H5TS_mutex_lock(H5TS_mutex_t *mutex)
* H5TS_mutex_unlock(&mutex_var)
*
* RETURNS
- * 0 on success and non-zero on error.
+ * Non-negative on success / Negative on failure
*
* DESCRIPTION
* Recursive lock semantics for HDF5 (unlocking) -
@@ -338,33 +576,102 @@ H5TS_mutex_lock(H5TS_mutex_t *mutex)
herr_t
H5TS_mutex_unlock(H5TS_mutex_t *mutex)
{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
#ifdef H5_HAVE_WIN_THREADS
/* Releases ownership of the specified critical section object. */
LeaveCriticalSection(&mutex->CriticalSection);
- return 0;
#else /* H5_HAVE_WIN_THREADS */
- herr_t ret_value = pthread_mutex_lock(&mutex->atomic_lock);
+ /* Decrement the lock count for this thread */
+ ret_value = HDpthread_mutex_lock(&mutex->atomic_lock);
if (ret_value)
- return ret_value;
-
+ HGOTO_DONE(ret_value);
mutex->lock_count--;
+ ret_value = HDpthread_mutex_unlock(&mutex->atomic_lock);
- ret_value = pthread_mutex_unlock(&mutex->atomic_lock);
-
+ /* If the lock count drops to zero, signal the condition variable, to
+ * wake another thread.
+ */
if (mutex->lock_count == 0) {
int err;
- err = pthread_cond_signal(&mutex->cond_var);
+ err = HDpthread_cond_signal(&mutex->cond_var);
if (err != 0)
ret_value = err;
} /* end if */
- return ret_value;
+done:
#endif /* H5_HAVE_WIN_THREADS */
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* H5TS_mutex_unlock */
/*--------------------------------------------------------------------------
+ * Function: H5TSmutex_get_attempt_count
+ *
+ * Purpose: Get the current count of the global lock attempt
+ *
+ * Return: Non-negative on success / Negative on failure
+ *
+ * Programmer: Houjun Tang
+ * June 24, 2019
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TSmutex_get_attempt_count(unsigned int *count)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API_NAMECHECK_ONLY
+
+#ifdef H5_HAVE_WIN_THREADS
+ /* Add Win32 equivalent here when async is supported */
+#else /* H5_HAVE_WIN_THREADS */
+ ret_value = HDpthread_mutex_lock(&H5_g.init_lock.atomic_lock2);
+ if (ret_value)
+ HGOTO_DONE(ret_value);
+
+ *count = H5_g.init_lock.attempt_lock_count;
+
+ ret_value = HDpthread_mutex_unlock(&H5_g.init_lock.atomic_lock2);
+ if (ret_value)
+ HGOTO_DONE(ret_value);
+
+done:
+#endif /* H5_HAVE_WIN_THREADS */
+ FUNC_LEAVE_API_NAMECHECK_ONLY(ret_value)
+} /* end H5TSmutex_get_attempt_count() */
+
+/*--------------------------------------------------------------------------
+ * Function: H5TSmutex_release
+ *
+ * Purpose: Releases the HDF5 library global lock
+ *
+ * Return: Non-negative on success / Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Februrary 27, 2019
+ *
+ *--------------------------------------------------------------------------
+ */
+herr_t
+H5TSmutex_release(unsigned int *lock_count)
+{
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_API_NAMECHECK_ONLY
+
+ *lock_count = 0;
+ if (0 != H5TS__mutex_unlock(&H5_g.init_lock, lock_count))
+ ret_value = -1;
+
+ FUNC_LEAVE_API_NAMECHECK_ONLY(ret_value)
+} /* end H5TSmutex_release() */
+
+/*--------------------------------------------------------------------------
* NAME
* H5TS_cancel_count_inc
*
@@ -372,15 +679,15 @@ H5TS_mutex_unlock(H5TS_mutex_t *mutex)
* H5TS_cancel_count_inc()
*
* RETURNS
- * 0 on success non-zero error code on error.
+ * Non-negative on success / Negative on failure
*
* DESCRIPTION
- * Creates a cancelation counter for a thread if it is the first time
+ * Creates a cancellation counter for a thread if it is the first time
* the thread is entering the library.
*
* if counter value is zero, then set cancelability type of the thread
* to PTHREAD_CANCEL_DISABLE as thread is entering the library and store
- * the previous cancelability type into cancelation counter.
+ * the previous cancelability type into cancellation counter.
* Increase the counter value by 1.
*
* PROGRAMMER: Chee Wai LEE
@@ -391,15 +698,20 @@ H5TS_mutex_unlock(H5TS_mutex_t *mutex)
herr_t
H5TS_cancel_count_inc(void)
{
-#ifdef H5_HAVE_WIN_THREADS
- /* unsupported; just return 0 */
- return SUCCEED;
-#else /* H5_HAVE_WIN_THREADS */
+#ifndef H5_HAVE_WIN_THREADS
H5TS_cancel_t *cancel_counter;
- herr_t ret_value = SUCCEED;
+#endif /* H5_HAVE_WIN_THREADS */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
- cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_g);
+#ifdef H5_HAVE_WIN_THREADS
+ /* unsupported */
+#else /* H5_HAVE_WIN_THREADS */
+ /* Acquire the thread's cancellation counter */
+ cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_s);
+ /* Check if it's created yet */
if (!cancel_counter) {
/*
* First time thread calls library - create new counter and associate
@@ -409,24 +721,31 @@ H5TS_cancel_count_inc(void)
* order to avoid codestack calls.
*/
cancel_counter = (H5TS_cancel_t *)HDcalloc(1, sizeof(H5TS_cancel_t));
-
- if (!cancel_counter) {
- HERROR(H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed");
- return FAIL;
- }
-
- ret_value = pthread_setspecific(H5TS_cancel_key_g, (void *)cancel_counter);
- }
-
+ if (NULL == cancel_counter)
+ HGOTO_DONE(FAIL);
+
+ /* Set the thread's cancellation counter with the new object */
+ ret_value = HDpthread_setspecific(H5TS_cancel_key_s, (void *)cancel_counter);
+ if (ret_value) {
+ HDfree(cancel_counter);
+ HGOTO_DONE(FAIL);
+ } /* end if */
+ } /* end if */
+
+ /* Check if thread entering library */
if (cancel_counter->cancel_count == 0)
- /* thread entering library */
- ret_value = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_counter->previous_state);
+ /* Set cancellation state to 'disable', and remember previous state */
+ ret_value = HDpthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_counter->previous_state);
+ /* Increment # of times the library API was re-entered, to avoid resetting
+ * previous cancellation state until the final API routine is returning.
+ */
++cancel_counter->cancel_count;
- return ret_value;
+done:
#endif /* H5_HAVE_WIN_THREADS */
-}
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
+} /* end H5TS_cancel_count_inc() */
/*--------------------------------------------------------------------------
* NAME
@@ -440,7 +759,7 @@ H5TS_cancel_count_inc(void)
*
* DESCRIPTION
* If counter value is one, then set cancelability type of the thread
- * to the previous cancelability type stored in the cancelation counter.
+ * to the previous cancelability type stored in the cancellation counter.
* (the thread is leaving the library).
*
* Decrement the counter value by 1.
@@ -453,23 +772,30 @@ H5TS_cancel_count_inc(void)
herr_t
H5TS_cancel_count_dec(void)
{
+#ifndef H5_HAVE_WIN_THREADS
+ H5TS_cancel_t *cancel_counter;
+#endif /* H5_HAVE_WIN_THREADS */
+ herr_t ret_value = SUCCEED;
+
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
#ifdef H5_HAVE_WIN_THREADS
- /* unsupported; will just return 0 */
- return SUCCEED;
+ /* unsupported */
#else /* H5_HAVE_WIN_THREADS */
- register H5TS_cancel_t *cancel_counter;
- herr_t ret_value = SUCCEED;
-
- cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_g);
+ /* Acquire the thread's cancellation counter */
+ cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_s);
+ /* Check for leaving last API routine */
if (cancel_counter->cancel_count == 1)
- ret_value = pthread_setcancelstate(cancel_counter->previous_state, NULL);
+ /* Reset to previous thread cancellation state, if last API */
+ ret_value = HDpthread_setcancelstate(cancel_counter->previous_state, NULL);
+ /* Decrement cancellation counter */
--cancel_counter->cancel_count;
-
- return ret_value;
#endif /* H5_HAVE_WIN_THREADS */
-}
+
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
+} /* end H5TS_cancel_count_dec() */
#ifdef H5_HAVE_WIN_THREADS
/*--------------------------------------------------------------------------
@@ -489,6 +815,8 @@ H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex)
{
BOOL ret_value = TRUE;
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
/* Initialize the critical section (can't fail) */
InitializeCriticalSection(&H5_g.init_lock.CriticalSection);
@@ -504,11 +832,9 @@ H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex)
if (TLS_OUT_OF_INDEXES == (H5TS_apictx_key_g = TlsAlloc()))
ret_value = FALSE;
- return ret_value;
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* H5TS_win32_process_enter() */
-#endif /* H5_HAVE_WIN_THREADS */
-#ifdef H5_HAVE_WIN_THREADS
/*--------------------------------------------------------------------------
* NAME
* H5TS_win32_thread_enter
@@ -526,6 +852,8 @@ H5TS_win32_thread_enter(void)
{
herr_t ret_value = SUCCEED;
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
/* Currently a placeholder function. TLS setup is performed
* elsewhere in the library.
*
@@ -534,11 +862,9 @@ H5TS_win32_thread_enter(void)
* is used.
*/
- return ret_value;
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* H5TS_win32_thread_enter() */
-#endif /* H5_HAVE_WIN_THREADS */
-#ifdef H5_HAVE_WIN_THREADS
/*--------------------------------------------------------------------------
* NAME
* H5TS_win32_process_exit
@@ -554,6 +880,7 @@ H5TS_win32_thread_enter(void)
void
H5TS_win32_process_exit(void)
{
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
/* Windows uses a different thread local storage mechanism which does
* not support auto-freeing like pthreads' keys.
@@ -566,17 +893,18 @@ H5TS_win32_process_exit(void)
DeleteCriticalSection(&H5_g.init_lock.CriticalSection);
/* Clean up per-process thread local storage */
- TlsFree(H5TS_errstk_key_g);
+ if (H5TS_errstk_key_g != TLS_OUT_OF_INDEXES)
+ TlsFree(H5TS_errstk_key_g);
#ifdef H5_HAVE_CODESTACK
- TlsFree(H5TS_funcstk_key_g);
+ if (H5TS_funcstk_key_g != TLS_OUT_OF_INDEXES)
+ TlsFree(H5TS_funcstk_key_g);
#endif /* H5_HAVE_CODESTACK */
- TlsFree(H5TS_apictx_key_g);
+ if (H5TS_apictx_key_g != TLS_OUT_OF_INDEXES)
+ TlsFree(H5TS_apictx_key_g);
- return;
+ FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
} /* H5TS_win32_process_exit() */
-#endif /* H5_HAVE_WIN_THREADS */
-#ifdef H5_HAVE_WIN_THREADS
/*--------------------------------------------------------------------------
* NAME
* H5TS_win32_thread_exit
@@ -595,6 +923,8 @@ H5TS_win32_thread_exit(void)
LPVOID lpvData;
herr_t ret_value = SUCCEED;
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+
/* Windows uses a different thread local storage mechanism which does
* not support auto-freeing like pthreads' keys.
*
@@ -604,21 +934,27 @@ H5TS_win32_thread_exit(void)
*/
/* Clean up per-thread thread local storage */
- lpvData = TlsGetValue(H5TS_errstk_key_g);
- if (lpvData)
- LocalFree((HLOCAL)lpvData);
+ if (H5TS_errstk_key_g != TLS_OUT_OF_INDEXES) {
+ lpvData = TlsGetValue(H5TS_errstk_key_g);
+ if (lpvData)
+ LocalFree((HLOCAL)lpvData);
+ }
#ifdef H5_HAVE_CODESTACK
- lpvData = TlsGetValue(H5TS_funcstk_key_g);
- if (lpvData)
- LocalFree((HLOCAL)lpvData);
+ if (H5TS_funcstk_key_g != TLS_OUT_OF_INDEXES) {
+ lpvData = TlsGetValue(H5TS_funcstk_key_g);
+ if (lpvData)
+ LocalFree((HLOCAL)lpvData);
+ }
#endif /* H5_HAVE_CODESTACK */
- lpvData = TlsGetValue(H5TS_apictx_key_g);
- if (lpvData)
- LocalFree((HLOCAL)lpvData);
+ if (H5TS_apictx_key_g != TLS_OUT_OF_INDEXES) {
+ lpvData = TlsGetValue(H5TS_apictx_key_g);
+ if (lpvData)
+ LocalFree((HLOCAL)lpvData);
+ }
- return ret_value;
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* H5TS_win32_thread_exit() */
#endif /* H5_HAVE_WIN_THREADS */
@@ -638,12 +974,13 @@ H5TS_win32_thread_exit(void)
*--------------------------------------------------------------------------
*/
H5TS_thread_t
-H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata)
+H5TS_create_thread(H5TS_thread_cb_t func, H5TS_attr_t *attr, void *udata)
{
H5TS_thread_t ret_value;
-#ifdef H5_HAVE_WIN_THREADS
+ FUNC_ENTER_NOAPI_NAMECHECK_ONLY
+#ifdef H5_HAVE_WIN_THREADS
/* When calling C runtime functions, you should use _beginthread or
* _beginthreadex instead of CreateThread. Threads created with
* CreateThread risk being killed in low-memory situations. Since we
@@ -658,12 +995,11 @@ H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata)
#else /* H5_HAVE_WIN_THREADS */
- pthread_create(&ret_value, attr, (void *(*)(void *))func, udata);
+ HDpthread_create(&ret_value, attr, (void *(*)(void *))func, udata);
#endif /* H5_HAVE_WIN_THREADS */
- return ret_value;
-
+ FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* H5TS_create_thread */
#endif /* H5_HAVE_THREADSAFE */
diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h
index a0cb353..6f9f1c0 100644
--- a/src/H5TSprivate.h
+++ b/src/H5TSprivate.h
@@ -26,9 +26,7 @@
#ifdef H5_HAVE_THREADSAFE
/* Public headers needed by this file */
-#ifdef LATER
-#include "H5TSpublic.h" /*Public API prototypes */
-#endif /* LATER */
+#include "H5TSpublic.h" /* Public API prototypes */
#ifdef H5_HAVE_WIN_THREADS
@@ -38,6 +36,8 @@
typedef struct H5TS_mutex_struct {
CRITICAL_SECTION CriticalSection;
} H5TS_mutex_t;
+
+/* Portability wrappers around Windows Threads types */
typedef CRITICAL_SECTION H5TS_mutex_simple_t;
typedef HANDLE H5TS_thread_t;
typedef HANDLE H5TS_attr_t;
@@ -50,7 +50,7 @@ typedef INIT_ONCE H5TS_once_t;
#define H5TS_SCOPE_PROCESS 0
#define H5TS_CALL_CONV WINAPI
-/* Functions */
+/* Portability function aliases */
#define H5TS_get_thread_local_value(key) TlsGetValue(key)
#define H5TS_set_thread_local_value(key, value) TlsSetValue(key, value)
#define H5TS_attr_init(attr_ptr) 0
@@ -79,7 +79,12 @@ typedef struct H5TS_mutex_struct {
pthread_mutex_t atomic_lock; /* lock for atomicity of new mechanism */
pthread_cond_t cond_var; /* condition variable */
unsigned int lock_count;
+
+ pthread_mutex_t atomic_lock2; /* lock for attempt_lock_count */
+ unsigned int attempt_lock_count;
} H5TS_mutex_t;
+
+/* Portability wrappers around pthread types */
typedef pthread_t H5TS_thread_t;
typedef pthread_attr_t H5TS_attr_t;
typedef pthread_mutex_t H5TS_mutex_simple_t;
@@ -91,7 +96,7 @@ typedef pthread_once_t H5TS_once_t;
#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS
#define H5TS_CALL_CONV /* unused - Windows only */
-/* Functions */
+/* Portability function aliases */
#define H5TS_get_thread_local_value(key) pthread_getspecific(key)
#define H5TS_set_thread_local_value(key, value) pthread_setspecific(key, value)
#define H5TS_attr_init(attr_ptr) pthread_attr_init((attr_ptr))
@@ -101,31 +106,31 @@ 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)
+
+/* Pthread-only routines */
H5_DLL uint64_t H5TS_thread_id(void);
+H5_DLL void H5TS_pthread_first_thread_init(void);
#endif /* H5_HAVE_WIN_THREADS */
-/* External global variables */
-extern H5TS_once_t H5TS_first_init_g;
-extern H5TS_key_t H5TS_errstk_key_g;
-extern H5TS_key_t H5TS_funcstk_key_g;
-extern H5TS_key_t H5TS_apictx_key_g;
-
-#if defined c_plusplus || defined __cplusplus
-extern "C" {
-#endif /* c_plusplus || __cplusplus */
-
-H5_DLL void H5TS_pthread_first_thread_init(void);
-H5_DLL herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex);
-H5_DLL herr_t H5TS_mutex_unlock(H5TS_mutex_t *mutex);
-H5_DLL herr_t H5TS_cancel_count_inc(void);
-H5_DLL herr_t H5TS_cancel_count_dec(void);
+/* Library-scope global variables */
+extern H5TS_once_t H5TS_first_init_g; /* Library initialization */
+extern H5TS_key_t H5TS_errstk_key_g; /* Error stacks */
+#ifdef H5_HAVE_CODESTACK
+extern H5TS_key_t H5TS_funcstk_key_g; /* Function stacks */
+#endif /* H5_HAVE_CODESTACK */
+extern H5TS_key_t H5TS_apictx_key_g; /* API contexts */
+
+/* Library-scope routines */
+/* (Only used within H5private.h macros) */
+H5_DLL herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex);
+H5_DLL herr_t H5TS_mutex_unlock(H5TS_mutex_t *mutex);
+H5_DLL herr_t H5TS_cancel_count_inc(void);
+H5_DLL herr_t H5TS_cancel_count_dec(void);
+
+/* Testing routines */
H5_DLL H5TS_thread_t H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata);
-#if defined c_plusplus || defined __cplusplus
-}
-#endif /* c_plusplus || __cplusplus */
-
#else /* H5_HAVE_THREADSAFE */
#define H5TS_thread_id() ((uint64_t)0)
diff --git a/src/H5private.h b/src/H5private.h
index 4c77a98..3ccd14f 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -1258,6 +1258,57 @@ typedef off_t h5_stat_size_t;
#ifndef HDprintf
#define HDprintf(...) HDfprintf(stdout, __VA_ARGS__)
#endif /* HDprintf */
+#ifndef HDpthread_attr_destroy
+#define HDpthread_attr_destroy(A) pthread_attr_destroy(A)
+#endif /* HDpthread_attr_destroy */
+#ifndef HDpthread_attr_init
+#define HDpthread_attr_init(A) pthread_attr_init(A)
+#endif /* HDpthread_attr_init */
+#ifndef HDpthread_attr_setscope
+#define HDpthread_attr_setscope(A, S) pthread_attr_setscope(A, S)
+#endif /* HDpthread_attr_setscope */
+#ifndef HDpthread_cond_init
+#define HDpthread_cond_init(C, A) pthread_cond_init(C, A)
+#endif /* HDpthread_cond_init */
+#ifndef HDpthread_cond_signal
+#define HDpthread_cond_signal(C) pthread_cond_signal(C)
+#endif /* HDpthread_cond_signal */
+#ifndef HDpthread_cond_wait
+#define HDpthread_cond_wait(C, M) pthread_cond_wait(C, M)
+#endif /* HDpthread_cond_wait */
+#ifndef HDpthread_create
+#define HDpthread_create(R, A, F, U) pthread_create(R, A, F, U)
+#endif /* HDpthread_create */
+#ifndef HDpthread_equal
+#define HDpthread_equal(T1, T2) pthread_equal(T1, T2)
+#endif /* HDpthread_equal */
+#ifndef HDpthread_getspecific
+#define HDpthread_getspecific(K) pthread_getspecific(K)
+#endif /* HDpthread_getspecific */
+#ifndef HDpthread_join
+#define HDpthread_join(T, V) pthread_join(T, V)
+#endif /* HDpthread_join */
+#ifndef HDpthread_key_create
+#define HDpthread_key_create(K, D) pthread_key_create(K, D)
+#endif /* HDpthread_key_create */
+#ifndef HDpthread_mutex_init
+#define HDpthread_mutex_init(M, A) pthread_mutex_init(M, A)
+#endif /* HDpthread_mutex_init */
+#ifndef HDpthread_mutex_lock
+#define HDpthread_mutex_lock(M) pthread_mutex_lock(M)
+#endif /* HDpthread_mutex_lock */
+#ifndef HDpthread_mutex_unlock
+#define HDpthread_mutex_unlock(M) pthread_mutex_unlock(M)
+#endif /* HDpthread_mutex_unlock */
+#ifndef HDpthread_self
+#define HDpthread_self() pthread_self()
+#endif /* HDpthread_self */
+#ifndef HDpthread_setcancelstate
+#define HDpthread_setcancelstate(N, O) pthread_setcancelstate(N, O)
+#endif /* HDpthread_setcancelstate */
+#ifndef HDpthread_setspecific
+#define HDpthread_setspecific(K, V) pthread_setspecific(K, V)
+#endif /* HDpthread_setspecific */
#ifndef HDputc
#define HDputc(C, F) putc(C, F)
#endif /* HDputc*/
diff --git a/src/hdf5.h b/src/hdf5.h
index c19e8aa..2e7caf9 100644
--- a/src/hdf5.h
+++ b/src/hdf5.h
@@ -37,6 +37,7 @@
#include "H5Rpublic.h" /* References */
#include "H5Spublic.h" /* Dataspaces */
#include "H5Tpublic.h" /* Datatypes */
+#include "H5TSpublic.h" /* Thread-safety */
#include "H5VLpublic.h" /* Virtual Object Layer */
#include "H5Zpublic.h" /* Data filters */