mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-12-21 07:51:46 +08:00
12ae6b9b1a
This caused H5TS.c functions to be mis-formatted
988 lines
28 KiB
C
988 lines
28 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://www.hdfgroup.org/licenses. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*
|
|
* 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
|
|
|
|
/****************/
|
|
/* Local Macros */
|
|
/****************/
|
|
|
|
/******************/
|
|
/* Local Typedefs */
|
|
/******************/
|
|
|
|
/* Cancellability 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, bool *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
|
|
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;
|
|
#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
|
|
|
|
/* An H5TS_tid_t is a record of a thread identifier that is
|
|
* available for reuse.
|
|
*/
|
|
struct _tid;
|
|
typedef struct _tid H5TS_tid_t;
|
|
|
|
struct _tid {
|
|
H5TS_tid_t *next;
|
|
uint64_t id;
|
|
};
|
|
|
|
/* Pointer to first free thread ID record or NULL. */
|
|
static H5TS_tid_t *H5TS_tid_next_free = NULL;
|
|
static uint64_t H5TS_tid_next_id = 0;
|
|
|
|
/* Mutual exclusion for access to H5TS_tid_next_free and H5TS_tid_next_id. */
|
|
static pthread_mutex_t H5TS_tid_mtx;
|
|
|
|
/* Key for thread-local storage of the thread ID. */
|
|
static H5TS_key_t H5TS_tid_key;
|
|
|
|
#endif /* H5_HAVE_WIN_THREADS */
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS__key_destructor
|
|
*
|
|
* USAGE
|
|
* H5TS__key_destructor()
|
|
*
|
|
* RETURNS
|
|
* None
|
|
*
|
|
* DESCRIPTION
|
|
* Frees the memory for a key. Called by each thread as it exits.
|
|
* Currently all the thread-specific information for all keys are simple
|
|
* structures allocated with malloc, so we can free them all uniformly.
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
H5TS__key_destructor(void *key_val)
|
|
{
|
|
FUNC_ENTER_PACKAGE_NAMECHECK_ONLY
|
|
|
|
/* Use free() here instead of H5MM_xfree(), to avoid calling the H5CS routines */
|
|
if (key_val != NULL)
|
|
free(key_val);
|
|
|
|
FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
|
|
} /* end H5TS__key_destructor() */
|
|
|
|
#ifndef H5_HAVE_WIN_THREADS
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_tid_destructor
|
|
*
|
|
* USAGE
|
|
* H5TS_tid_destructor()
|
|
*
|
|
* RETURNS
|
|
*
|
|
* DESCRIPTION
|
|
* When a thread shuts down, put its ID record on the free list.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
H5TS_tid_destructor(void *_v)
|
|
{
|
|
H5TS_tid_t *tid = _v;
|
|
|
|
if (tid == NULL)
|
|
return;
|
|
|
|
/* TBD use an atomic CAS */
|
|
pthread_mutex_lock(&H5TS_tid_mtx);
|
|
tid->next = H5TS_tid_next_free;
|
|
H5TS_tid_next_free = tid;
|
|
pthread_mutex_unlock(&H5TS_tid_mtx);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_tid_init
|
|
*
|
|
* USAGE
|
|
* H5TS_tid_init()
|
|
*
|
|
* RETURNS
|
|
*
|
|
* DESCRIPTION
|
|
* Initialize for integer thread identifiers.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
H5TS_tid_init(void)
|
|
{
|
|
pthread_mutex_init(&H5TS_tid_mtx, NULL);
|
|
pthread_key_create(&H5TS_tid_key, H5TS_tid_destructor);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_thread_id
|
|
*
|
|
* USAGE
|
|
* uint64_t id = H5TS_thread_id()
|
|
*
|
|
* RETURNS
|
|
* Return an integer identifier, ID, for the current thread.
|
|
*
|
|
* DESCRIPTION
|
|
* The ID satisfies 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)
|
|
{
|
|
H5TS_tid_t *tid = pthread_getspecific(H5TS_tid_key);
|
|
H5TS_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(&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);
|
|
|
|
/* If a prototype ID record was established, copy it to the heap. */
|
|
if (tid == &proto_tid)
|
|
if ((tid = malloc(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(H5TS_tid_key, tid) != 0) {
|
|
H5TS_tid_destructor(tid);
|
|
return 0;
|
|
}
|
|
|
|
return tid->id;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_pthread_first_thread_init
|
|
*
|
|
* USAGE
|
|
* H5TS_pthread_first_thread_init()
|
|
*
|
|
* RETURNS
|
|
*
|
|
* DESCRIPTION
|
|
* Initialization of global API lock, keys for per-thread error stacks and
|
|
* cancallability information. Called by the first thread that enters the
|
|
* library.
|
|
*
|
|
* PROGRAMMER: Chee Wai LEE
|
|
* May 2, 2000
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
void
|
|
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();
|
|
#endif
|
|
#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);
|
|
H5_g.init_lock.lock_count = 0;
|
|
|
|
pthread_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);
|
|
|
|
#ifdef H5_HAVE_CODESTACK
|
|
/* initialize key for thread-specific function stacks */
|
|
pthread_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);
|
|
|
|
/* initialize key for thread cancellability mechanism */
|
|
pthread_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
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5TS__mutex_acquire(H5TS_mutex_t *mutex, unsigned int lock_count, bool *acquired)
|
|
{
|
|
herr_t ret_value = SUCCEED;
|
|
|
|
FUNC_ENTER_PACKAGE_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 == pthread_mutex_lock(&mutex->atomic_lock)) {
|
|
pthread_t my_thread_id = pthread_self();
|
|
|
|
/* Check if locked already */
|
|
if (mutex->lock_count) {
|
|
/* Check for this thread already owning the lock */
|
|
if (pthread_equal(my_thread_id, mutex->owner_thread)) {
|
|
/* Already owned by self - increment count */
|
|
mutex->lock_count += lock_count;
|
|
*acquired = true;
|
|
}
|
|
else
|
|
*acquired = false;
|
|
}
|
|
else {
|
|
/* Take ownership of the mutex */
|
|
mutex->owner_thread = my_thread_id;
|
|
mutex->lock_count = lock_count;
|
|
*acquired = true;
|
|
}
|
|
|
|
if (0 != pthread_mutex_unlock(&mutex->atomic_lock))
|
|
ret_value = -1;
|
|
}
|
|
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
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5TSmutex_acquire(unsigned int lock_count, bool *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
|
|
*
|
|
* USAGE
|
|
* H5TS_mutex_lock(&mutex_var)
|
|
*
|
|
* RETURNS
|
|
* Non-negative on success / Negative on failure
|
|
*
|
|
* DESCRIPTION
|
|
* Recursive lock semantics for HDF5 (locking) -
|
|
* Multiple acquisition of a lock by a thread is permitted with a
|
|
* corresponding unlock operation required.
|
|
*
|
|
* PROGRAMMER: Chee Wai LEE
|
|
* May 2, 2000
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
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);
|
|
#else /* H5_HAVE_WIN_THREADS */
|
|
/* Acquire the "attempt" lock, increment the attempt lock count, release the lock */
|
|
ret_value = pthread_mutex_lock(&mutex->atomic_lock2);
|
|
if (ret_value)
|
|
HGOTO_DONE(ret_value);
|
|
mutex->attempt_lock_count++;
|
|
ret_value = pthread_mutex_unlock(&mutex->atomic_lock2);
|
|
if (ret_value)
|
|
HGOTO_DONE(ret_value);
|
|
|
|
/* Acquire the library lock */
|
|
ret_value = pthread_mutex_lock(&mutex->atomic_lock);
|
|
if (ret_value)
|
|
HGOTO_DONE(ret_value);
|
|
|
|
/* Check if this thread already owns the lock */
|
|
if (mutex->lock_count && pthread_equal(pthread_self(), mutex->owner_thread))
|
|
/* already owned by self - increment count */
|
|
mutex->lock_count++;
|
|
else {
|
|
/* Wait until the lock is released by current owner thread */
|
|
while (mutex->lock_count)
|
|
pthread_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->lock_count = 1;
|
|
}
|
|
|
|
/* Release the library lock */
|
|
ret_value = pthread_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 = pthread_mutex_lock(&mutex->atomic_lock);
|
|
if (ret_value)
|
|
HGOTO_DONE(ret_value);
|
|
*lock_count = mutex->lock_count;
|
|
mutex->lock_count = 0;
|
|
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);
|
|
if (err != 0)
|
|
ret_value = err;
|
|
}
|
|
|
|
done:
|
|
#endif /* H5_HAVE_WIN_THREADS */
|
|
FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
|
|
} /* H5TS__mutex_unlock */
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_mutex_unlock
|
|
*
|
|
* USAGE
|
|
* H5TS_mutex_unlock(&mutex_var)
|
|
*
|
|
* RETURNS
|
|
* Non-negative on success / Negative on failure
|
|
*
|
|
* DESCRIPTION
|
|
* Recursive lock semantics for HDF5 (unlocking) -
|
|
* Multiple acquisition of a lock by a thread is permitted with a
|
|
* corresponding unlock operation required.
|
|
*
|
|
* PROGRAMMER: Chee Wai LEE
|
|
* May 2, 2000
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
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);
|
|
#else /* H5_HAVE_WIN_THREADS */
|
|
|
|
/* Decrement the lock count for this thread */
|
|
ret_value = pthread_mutex_lock(&mutex->atomic_lock);
|
|
if (ret_value)
|
|
HGOTO_DONE(ret_value);
|
|
mutex->lock_count--;
|
|
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);
|
|
if (err != 0)
|
|
ret_value = err;
|
|
}
|
|
|
|
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
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
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 = pthread_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 = pthread_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
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
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
|
|
*
|
|
* USAGE
|
|
* H5TS_cancel_count_inc()
|
|
*
|
|
* RETURNS
|
|
* Non-negative on success / Negative on failure
|
|
*
|
|
* DESCRIPTION
|
|
* 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 cancellability type of the thread
|
|
* to PTHREAD_CANCEL_DISABLE as thread is entering the library and store
|
|
* the previous cancellability type into cancellation counter.
|
|
* Increase the counter value by 1.
|
|
*
|
|
* PROGRAMMER: Chee Wai LEE
|
|
* May 2, 2000
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5TS_cancel_count_inc(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 */
|
|
#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
|
|
* with key.
|
|
*
|
|
* Don't use H5MM calls here since the destructor has to use free in
|
|
* order to avoid codestack calls.
|
|
*/
|
|
cancel_counter = (H5TS_cancel_t *)calloc(1, sizeof(H5TS_cancel_t));
|
|
if (NULL == cancel_counter)
|
|
HGOTO_DONE(FAIL);
|
|
|
|
/* Set the thread's cancellation counter with the new object */
|
|
ret_value = pthread_setspecific(H5TS_cancel_key_s, (void *)cancel_counter);
|
|
if (ret_value) {
|
|
free(cancel_counter);
|
|
HGOTO_DONE(FAIL);
|
|
}
|
|
}
|
|
|
|
/* Check if thread entering library */
|
|
if (cancel_counter->cancel_count == 0)
|
|
/* Set cancellation state to 'disable', and remember previous state */
|
|
ret_value = pthread_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;
|
|
|
|
done:
|
|
#endif /* H5_HAVE_WIN_THREADS */
|
|
FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
|
|
} /* end H5TS_cancel_count_inc() */
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_cancel_count_dec
|
|
*
|
|
* USAGE
|
|
* H5TS_cancel_count_dec()
|
|
*
|
|
* RETURNS
|
|
* 0 on success and a non-zero error code on error.
|
|
*
|
|
* DESCRIPTION
|
|
* If counter value is one, then set cancellability type of the thread
|
|
* to the previous cancellability type stored in the cancellation counter.
|
|
* (the thread is leaving the library).
|
|
*
|
|
* Decrement the counter value by 1.
|
|
*
|
|
* PROGRAMMER: Chee Wai LEE
|
|
* May 2, 2000
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
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 */
|
|
#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 for leaving last API routine */
|
|
if (cancel_counter->cancel_count == 1)
|
|
/* Reset to previous thread cancellation state, if last API */
|
|
ret_value = pthread_setcancelstate(cancel_counter->previous_state, NULL);
|
|
|
|
/* Decrement cancellation counter */
|
|
--cancel_counter->cancel_count;
|
|
#endif /* H5_HAVE_WIN_THREADS */
|
|
|
|
FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
|
|
} /* end H5TS_cancel_count_dec() */
|
|
|
|
#ifdef H5_HAVE_WIN_THREADS
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_win32_process_enter
|
|
*
|
|
* RETURNS
|
|
* SUCCEED/FAIL
|
|
*
|
|
* DESCRIPTION
|
|
* Per-process setup on Windows when using Win32 threads.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
H5_DLL BOOL CALLBACK
|
|
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);
|
|
|
|
/* Set up thread local storage */
|
|
if (TLS_OUT_OF_INDEXES == (H5TS_errstk_key_g = TlsAlloc()))
|
|
ret_value = false;
|
|
|
|
#ifdef H5_HAVE_CODESTACK
|
|
if (TLS_OUT_OF_INDEXES == (H5TS_funcstk_key_g = TlsAlloc()))
|
|
ret_value = false;
|
|
#endif /* H5_HAVE_CODESTACK */
|
|
|
|
if (TLS_OUT_OF_INDEXES == (H5TS_apictx_key_g = TlsAlloc()))
|
|
ret_value = false;
|
|
|
|
FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
|
|
} /* H5TS_win32_process_enter() */
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_win32_thread_enter
|
|
*
|
|
* RETURNS
|
|
* SUCCEED/FAIL
|
|
*
|
|
* DESCRIPTION
|
|
* Per-thread setup on Windows when using Win32 threads.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
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.
|
|
*
|
|
* WARNING: Do NOT use C standard library functions here.
|
|
* CRT functions are not allowed in DllMain, which is where this code
|
|
* is used.
|
|
*/
|
|
|
|
FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
|
|
} /* H5TS_win32_thread_enter() */
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_win32_process_exit
|
|
*
|
|
* RETURNS
|
|
* SUCCEED/FAIL
|
|
*
|
|
* DESCRIPTION
|
|
* Per-process cleanup on Windows when using Win32 threads.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
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.
|
|
*
|
|
* This function is currently registered via atexit() and is called
|
|
* AFTER H5_term_library().
|
|
*/
|
|
|
|
/* Clean up critical section resources (can't fail) */
|
|
DeleteCriticalSection(&H5_g.init_lock.CriticalSection);
|
|
|
|
/* Clean up per-process thread local storage */
|
|
if (H5TS_errstk_key_g != TLS_OUT_OF_INDEXES)
|
|
TlsFree(H5TS_errstk_key_g);
|
|
#ifdef H5_HAVE_CODESTACK
|
|
if (H5TS_funcstk_key_g != TLS_OUT_OF_INDEXES)
|
|
TlsFree(H5TS_funcstk_key_g);
|
|
#endif /* H5_HAVE_CODESTACK */
|
|
if (H5TS_apictx_key_g != TLS_OUT_OF_INDEXES)
|
|
TlsFree(H5TS_apictx_key_g);
|
|
|
|
FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
|
|
} /* H5TS_win32_process_exit() */
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_win32_thread_exit
|
|
*
|
|
* RETURNS
|
|
* SUCCEED/FAIL
|
|
*
|
|
* DESCRIPTION
|
|
* Per-thread cleanup on Windows when using Win32 threads.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
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.
|
|
*
|
|
* WARNING: Do NOT use C standard library functions here.
|
|
* CRT functions are not allowed in DllMain, which is where this code
|
|
* is used.
|
|
*/
|
|
|
|
/* Clean up per-thread thread local storage */
|
|
if (H5TS_errstk_key_g != TLS_OUT_OF_INDEXES) {
|
|
lpvData = TlsGetValue(H5TS_errstk_key_g);
|
|
if (lpvData)
|
|
LocalFree((HLOCAL)lpvData);
|
|
}
|
|
|
|
#ifdef H5_HAVE_CODESTACK
|
|
if (H5TS_funcstk_key_g != TLS_OUT_OF_INDEXES) {
|
|
lpvData = TlsGetValue(H5TS_funcstk_key_g);
|
|
if (lpvData)
|
|
LocalFree((HLOCAL)lpvData);
|
|
}
|
|
#endif /* H5_HAVE_CODESTACK */
|
|
|
|
if (H5TS_apictx_key_g != TLS_OUT_OF_INDEXES) {
|
|
lpvData = TlsGetValue(H5TS_apictx_key_g);
|
|
if (lpvData)
|
|
LocalFree((HLOCAL)lpvData);
|
|
}
|
|
|
|
FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
|
|
} /* H5TS_win32_thread_exit() */
|
|
#endif /* H5_HAVE_WIN_THREADS */
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* NAME
|
|
* H5TS_create_thread
|
|
*
|
|
* RETURNS
|
|
* Thread identifier.
|
|
*
|
|
* DESCRIPTION
|
|
* Spawn off a new thread calling function 'func' with input 'udata'.
|
|
*
|
|
* PROGRAMMER: Mike McGreevy
|
|
* August 31, 2010
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
H5TS_thread_t
|
|
H5TS_create_thread(H5TS_thread_cb_t func, H5TS_attr_t *attr, void *udata)
|
|
{
|
|
H5TS_thread_t ret_value;
|
|
|
|
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
|
|
* only create threads in our test code, this is unlikely to be an issue
|
|
* and we'll use the easier-to-deal-with CreateThread for now.
|
|
*
|
|
* NOTE: _beginthread() auto-recycles its handle when execution completes
|
|
* so you can't wait on it, making it unsuitable for the existing
|
|
* test code.
|
|
*/
|
|
ret_value = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, udata, 0, NULL);
|
|
|
|
#else /* H5_HAVE_WIN_THREADS */
|
|
|
|
pthread_create(&ret_value, attr, (void *(*)(void *))func, udata);
|
|
|
|
#endif /* H5_HAVE_WIN_THREADS */
|
|
|
|
FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
|
|
} /* H5TS_create_thread */
|
|
|
|
#endif /* H5_HAVE_THREADSAFE */
|