mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-02-11 16:01:00 +08:00
Update Description: Updated copyright statement in files which hadn't been updated yet. Platforms tested: Linux (Only comment change) Misc. update:
352 lines
9.8 KiB
C
352 lines
9.8 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* Copyright by the Board of Trustees of the University of Illinois. *
|
||
* 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 files COPYING and Copyright.html. COPYING can be found at the root *
|
||
* of the source code distribution tree; Copyright.html can be found at the *
|
||
* root level of an installed copy of the electronic HDF5 document set and *
|
||
* is linked from the top-level documents page. It can also be found at *
|
||
* http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
||
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
/* $Id$ */
|
||
|
||
/* private headers */
|
||
#include "H5private.h" /*library */
|
||
#include "H5Eprivate.h" /*error handling */
|
||
#include "H5MMprivate.h" /*memory management functions */
|
||
|
||
#ifdef H5_HAVE_THREADSAFE
|
||
|
||
/* Module specific data structures */
|
||
|
||
/* cancelability structure */
|
||
typedef struct H5TS_cancel_struct {
|
||
int previous_state;
|
||
unsigned int cancel_count;
|
||
} H5TS_cancel_t;
|
||
|
||
/* Global variable definitions */
|
||
pthread_once_t H5TS_first_init_g = PTHREAD_ONCE_INIT;
|
||
pthread_key_t H5TS_errstk_key_g;
|
||
pthread_key_t H5TS_funcstk_key_g;
|
||
pthread_key_t H5TS_cancel_key_g;
|
||
hbool_t H5TS_allow_concurrent_g = FALSE; /* concurrent APIs override this */
|
||
|
||
/* Local function definitions */
|
||
#ifdef NOT_USED
|
||
static void H5TS_mutex_init(H5TS_mutex_t *mutex);
|
||
#endif /* NOT_USED */
|
||
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* NAME
|
||
* H5TS_key_destructor
|
||
*
|
||
* USAGE
|
||
* H5TS_key_destructor()
|
||
*
|
||
* RETURNS
|
||
*
|
||
* 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.
|
||
*
|
||
* PROGRAMMER: Quincey Koziol
|
||
* February 7, 2003
|
||
*
|
||
* MODIFICATIONS:
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
static void
|
||
H5TS_key_destructor(void *key_val)
|
||
{
|
||
/* Use HDfree here instead of H5MM_xfree(), to avoid calling the H5FS routines */
|
||
if(key_val!=NULL)
|
||
HDfree(key_val);
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* NAME
|
||
* H5TS_first_thread_init
|
||
*
|
||
* USAGE
|
||
* H5TS_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
|
||
*
|
||
* MODIFICATIONS:
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
void
|
||
H5TS_first_thread_init(void)
|
||
{
|
||
H5_g.H5_libinit_g = FALSE;
|
||
|
||
/* set the two pthread_t objects to ``null'' */
|
||
H5_g.init_lock.owner_thread = NULL;
|
||
|
||
/* 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;
|
||
|
||
/* initialize key for thread-specific error stacks */
|
||
pthread_key_create(&H5TS_errstk_key_g, H5TS_key_destructor);
|
||
|
||
/* initialize key for thread-specific function stacks */
|
||
pthread_key_create(&H5TS_funcstk_key_g, H5TS_key_destructor);
|
||
|
||
/* initialize key for thread cancellability mechanism */
|
||
pthread_key_create(&H5TS_cancel_key_g, H5TS_key_destructor);
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* NAME
|
||
* H5TS_mutex_lock
|
||
*
|
||
* USAGE
|
||
* H5TS_mutex_lock(&mutex_var)
|
||
*
|
||
* RETURNS
|
||
* 0 on success and non-zero on error.
|
||
*
|
||
* 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
|
||
*
|
||
* MODIFICATIONS:
|
||
*
|
||
* 19 May 2000, Bill Wendling
|
||
* Changed (*foo). form of accessing structure members to the -> form.
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5TS_mutex_lock(H5TS_mutex_t *mutex)
|
||
{
|
||
herr_t ret_value;
|
||
|
||
ret_value = pthread_mutex_lock(&mutex->atomic_lock);
|
||
|
||
if (ret_value)
|
||
return ret_value;
|
||
|
||
if (mutex->owner_thread && pthread_equal(pthread_self(), *mutex->owner_thread)) {
|
||
/* already owned by self - increment count */
|
||
mutex->lock_count++;
|
||
} else if (!mutex->owner_thread) {
|
||
/* no one else has locked it - set owner and grab lock */
|
||
mutex->owner_thread = H5MM_malloc(sizeof(pthread_t));
|
||
|
||
if (!mutex->owner_thread) {
|
||
H5E_push(H5E_RESOURCE, H5E_NOSPACE, "H5TS_mutex_lock",
|
||
__FILE__, __LINE__, "memory allocation failed");
|
||
return FAIL;
|
||
}
|
||
|
||
*mutex->owner_thread = pthread_self();
|
||
mutex->lock_count = 1;
|
||
} else {
|
||
/* if already locked by someone else */
|
||
for (;;) {
|
||
pthread_cond_wait(&mutex->cond_var, &mutex->atomic_lock);
|
||
|
||
if (!mutex->owner_thread) {
|
||
mutex->owner_thread = H5MM_malloc(sizeof(pthread_t));
|
||
|
||
if (!mutex->owner_thread) {
|
||
H5E_push(H5E_RESOURCE, H5E_NOSPACE, "H5TS_mutex_lock",
|
||
__FILE__, __LINE__, "memory allocation failed");
|
||
return FAIL;
|
||
}
|
||
|
||
*mutex->owner_thread = pthread_self();
|
||
mutex->lock_count = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return pthread_mutex_unlock(&mutex->atomic_lock);
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* NAME
|
||
* H5TS_mutex_unlock
|
||
*
|
||
* USAGE
|
||
* H5TS_mutex_unlock(&mutex_var)
|
||
*
|
||
* RETURNS
|
||
* 0 on success and non-zero on error.
|
||
*
|
||
* 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
|
||
*
|
||
* MODIFICATIONS:
|
||
*
|
||
* 19 May 2000, Bill Wendling
|
||
* Changed (*foo). form of accessing structure members to the -> form.
|
||
* Also gave the function a return value.
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5TS_mutex_unlock(H5TS_mutex_t *mutex)
|
||
{
|
||
herr_t ret_value;
|
||
|
||
ret_value = pthread_mutex_lock(&mutex->atomic_lock);
|
||
|
||
if (ret_value)
|
||
return ret_value;
|
||
|
||
mutex->lock_count--;
|
||
|
||
if (mutex->lock_count == 0) {
|
||
H5MM_xfree(mutex->owner_thread);
|
||
mutex->owner_thread = NULL;
|
||
ret_value = pthread_cond_signal(&mutex->cond_var);
|
||
|
||
if (ret_value) {
|
||
pthread_mutex_unlock(&mutex->atomic_lock);
|
||
return ret_value;
|
||
}
|
||
}
|
||
|
||
return pthread_mutex_unlock(&mutex->atomic_lock);
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* NAME
|
||
* H5TS_cancel_count_inc
|
||
*
|
||
* USAGE
|
||
* H5TS_cancel_count_inc()
|
||
*
|
||
* RETURNS
|
||
* 0 on success non-zero error code on error.
|
||
*
|
||
* DESCRIPTION
|
||
* Creates a cancelation 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.
|
||
* Increase the counter value by 1.
|
||
*
|
||
* PROGRAMMER: Chee Wai LEE
|
||
* May 2, 2000
|
||
*
|
||
* MODIFICATIONS:
|
||
*
|
||
* 19 May 2000, Bill Wendling
|
||
* Changed function to return a value. Also changed the malloc() call to
|
||
* the H5MM_malloc() call and checked the returned pointer.
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5TS_cancel_count_inc(void)
|
||
{
|
||
H5TS_cancel_t *cancel_counter;
|
||
herr_t ret_value = 0;
|
||
|
||
cancel_counter = pthread_getspecific(H5TS_cancel_key_g);
|
||
|
||
if (!cancel_counter) {
|
||
/*
|
||
* First time thread calls library - create new counter and associate
|
||
* with key
|
||
*/
|
||
cancel_counter = H5MM_malloc(sizeof(H5TS_cancel_t));
|
||
|
||
if (!cancel_counter) {
|
||
H5E_push(H5E_RESOURCE, H5E_NOSPACE, "H5TS_cancel_count_inc",
|
||
__FILE__, __LINE__, "memory allocation failed");
|
||
return FAIL;
|
||
}
|
||
|
||
cancel_counter->cancel_count = 0;
|
||
ret_value = pthread_setspecific(H5TS_cancel_key_g,
|
||
(void *)cancel_counter);
|
||
}
|
||
|
||
if (cancel_counter->cancel_count == 0)
|
||
/* thread entering library */
|
||
ret_value = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
|
||
&cancel_counter->previous_state);
|
||
|
||
++cancel_counter->cancel_count;
|
||
return ret_value;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------
|
||
* 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 cancelability type of the thread
|
||
* to the previous cancelability type stored in the cancelation counter.
|
||
* (the thread is leaving the library).
|
||
*
|
||
* Decrement the counter value by 1.
|
||
*
|
||
* PROGRAMMER: Chee Wai LEE
|
||
* May 2, 2000
|
||
*
|
||
* MODIFICATIONS:
|
||
*
|
||
* 19 May 2000, Bill Wendling
|
||
* Changed so that function returns a value. May be of limited usefulness.
|
||
*
|
||
*--------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5TS_cancel_count_dec(void)
|
||
{
|
||
herr_t ret_value = 0;
|
||
register H5TS_cancel_t *cancel_counter;
|
||
|
||
cancel_counter = pthread_getspecific(H5TS_cancel_key_g);
|
||
|
||
if (cancel_counter->cancel_count == 1)
|
||
ret_value = pthread_setcancelstate(cancel_counter->previous_state, NULL);
|
||
|
||
--cancel_counter->cancel_count;
|
||
return ret_value;
|
||
}
|
||
|
||
#endif /* H5_HAVE_THREADSAFE */
|