Skip to content

Commit

Permalink
Added support atomic_uint, updated "attempt lock count" to use it
Browse files Browse the repository at this point in the history
Signed-off-by: Quincey Koziol <[email protected]>
  • Loading branch information
qkoziol committed Mar 27, 2024
1 parent 8b94a31 commit 7f1a7a8
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 35 deletions.
14 changes: 1 addition & 13 deletions src/H5TS.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,11 @@ H5TSmutex_acquire(unsigned lock_count, bool *acquired)
herr_t
H5TSmutex_get_attempt_count(unsigned *count)
{
bool have_mutex = false;
herr_t ret_value = SUCCEED;

FUNC_ENTER_API_NAMECHECK_ONLY

/* Acquire the "attempt" lock, retrieve the attempt lock count, release the lock */
if (H5_UNLIKELY(H5TS_mutex_lock(&H5TS_api_info_p.attempt_mutex) < 0))
HGOTO_DONE(FAIL);
have_mutex = true;

*count = H5TS_api_info_p.attempt_lock_count;

done:
/* Release the lock */
if (H5_LIKELY(have_mutex))
if (H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.attempt_mutex) < 0))
ret_value = FAIL;
*count = H5TS_atomic_load_uint(&H5TS_api_info_p.attempt_lock_count);

FUNC_LEAVE_API_NAMECHECK_ONLY(ret_value)
} /* end H5TSmutex_get_attempt_count() */
Expand Down
185 changes: 177 additions & 8 deletions src/H5TSatomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
/*--------------------------------------------------------------------------
* Function: H5TS_atomic_init_int
*
* Purpose: Initializes an atomic variable object with a value.
* Purpose: Initializes an atomic 'int' variable object with a value.
*
* Note: Per the C11 standard, this function is not atomic and
* concurrent execution from multiple threads is a data race.
Expand All @@ -89,7 +89,7 @@ H5TS_atomic_init_int(H5TS_atomic_int_t *obj, int desired)
/*--------------------------------------------------------------------------
* Function: H5TS_atomic_load_int
*
* Purpose: Retrives the value of atomic variable object.
* Purpose: Retrieves the value of atomic 'int' variable object.
*
* Return: None
*
Expand All @@ -112,12 +112,12 @@ H5TS_atomic_load_int(H5TS_atomic_int_t *obj)
H5TS_mutex_unlock(&obj->mutex);

FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* end H5TS_atomic_init_int() */
} /* end H5TS_atomic_load_int() */

/*--------------------------------------------------------------------------
* Function: H5TS_atomic_store_int
*
* Purpose: Atomically replaces the value of the atomic variable
* Purpose: Atomically replaces the value of the atomic 'int' variable
*
* Return: None
*
Expand All @@ -143,7 +143,7 @@ H5TS_atomic_store_int(H5TS_atomic_int_t *obj, int desired)
/*--------------------------------------------------------------------------
* Function: H5TS_atomic_fetch_add_int
*
* Purpose: Atomically replaces the value of an atomic variable with the
* Purpose: Atomically replaces the value of an atomic 'int' variable with the
* result of addition of the 'arg' to the old value of the
* atomic variable.
*
Expand Down Expand Up @@ -176,7 +176,7 @@ H5TS_atomic_fetch_add_int(H5TS_atomic_int_t *obj, int arg)
/*--------------------------------------------------------------------------
* Function: H5TS_atomic_fetch_sub_int
*
* Purpose: Atomically replaces the value of an atomic variable with the
* Purpose: Atomically replaces the value of an atomic 'int' variable with the
* result of subtracting the 'arg' from the old value of the
* atomic variable.
*
Expand Down Expand Up @@ -209,7 +209,7 @@ H5TS_atomic_fetch_sub_int(H5TS_atomic_int_t *obj, int arg)
/*--------------------------------------------------------------------------
* Function: H5TS_atomic_destroy_int
*
* Purpose: Destroys / releases resources for an atomic variable
* Purpose: Destroys / releases resources for an atomic 'int' variable
*
* Note: No equivalent in the C11 atomics, but needed here, to destroy
* the mutex used to protect the atomic value.
Expand All @@ -229,6 +229,175 @@ H5TS_atomic_destroy_int(H5TS_atomic_int_t *obj)
FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
} /* end H5TS_atomic_destroy_int() */

#endif /* H5_HAVE_THREADS_H */
/*--------------------------------------------------------------------------
* Function: H5TS_atomic_init_uint
*
* Purpose: Initializes an atomic 'unsigned' variable object with a value.
*
* Note: Per the C11 standard, this function is not atomic and
* concurrent execution from multiple threads is a data race.
*
* Return: None
*
*--------------------------------------------------------------------------
*/
void
H5TS_atomic_init_uint(H5TS_atomic_uint_t *obj, unsigned desired)
{
FUNC_ENTER_NOAPI_NAMECHECK_ONLY

/* Initialize mutex that protects the "atomic" value */
(void) H5TS_mutex_init(&obj->mutex);

/* Set the value */
obj->value = desired;

FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
} /* end H5TS_atomic_init_uint() */

/*--------------------------------------------------------------------------
* Function: H5TS_atomic_load_uint
*
* Purpose: Retrieves the value of atomic 'unsigned' variable object.
*
* Return: None
*
*--------------------------------------------------------------------------
*/
unsigned
H5TS_atomic_load_uint(H5TS_atomic_uint_t *obj)
{
unsigned ret_value;

FUNC_ENTER_NOAPI_NAMECHECK_ONLY

/* Lock mutex that protects the "atomic" value */
(void) H5TS_mutex_lock(&obj->mutex);

/* Get the value */
ret_value = obj->value;

/* Release the object's mutex */
H5TS_mutex_unlock(&obj->mutex);

FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* end H5TS_atomic_load_uint() */

/*--------------------------------------------------------------------------
* Function: H5TS_atomic_store_uint
*
* Purpose: Atomically replaces the value of the atomic 'unsigned' variable
*
* Return: None
*
*--------------------------------------------------------------------------
*/
void
H5TS_atomic_store_uint(H5TS_atomic_uint_t *obj, unsigned desired)
{
FUNC_ENTER_NOAPI_NAMECHECK_ONLY

/* Lock mutex that protects the "atomic" value */
(void) H5TS_mutex_lock(&obj->mutex);

/* Set the value */
obj->value = desired;

/* Release the object's mutex */
H5TS_mutex_unlock(&obj->mutex);

FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
} /* end H5TS_atomic_store_uint() */

/*--------------------------------------------------------------------------
* Function: H5TS_atomic_fetch_add_uint
*
* Purpose: Atomically replaces the value of an atomic 'unsigned' variable with the
* result of addition of the 'arg' to the old value of the
* atomic variable.
*
* Return: Returns the value of the atomic variable held previously
*
*--------------------------------------------------------------------------
*/
unsigned
H5TS_atomic_fetch_add_uint(H5TS_atomic_uint_t *obj, unsigned arg)
{
unsigned ret_value;

FUNC_ENTER_NOAPI_NAMECHECK_ONLY

/* Lock mutex that protects the "atomic" value */
(void) H5TS_mutex_lock(&obj->mutex);

/* Get the current value */
ret_value = obj->value;

/* Increment the value */
obj->value += arg;

/* Release the object's mutex */
H5TS_mutex_unlock(&obj->mutex);

FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* end H5TS_atomic_fetch_add_uint() */

/*--------------------------------------------------------------------------
* Function: H5TS_atomic_fetch_sub_uint
*
* Purpose: Atomically replaces the value of an atomic 'unsigned' variable with the
* result of subtracting the 'arg' from the old value of the
* atomic variable.
*
* Return: Returns the value of the atomic variable held previously
*
*--------------------------------------------------------------------------
*/
unsigned
H5TS_atomic_fetch_sub_uint(H5TS_atomic_uint_t *obj, unsigned arg)
{
unsigned ret_value;

FUNC_ENTER_NOAPI_NAMECHECK_ONLY

/* Lock mutex that protects the "atomic" value */
(void) H5TS_mutex_lock(&obj->mutex);

/* Get the current value */
ret_value = obj->value;

/* Decrement the value */
obj->value -= arg;

/* Release the object's mutex */
H5TS_mutex_unlock(&obj->mutex);

FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value)
} /* end H5TS_atomic_fetch_sub_uint() */

/*--------------------------------------------------------------------------
* Function: H5TS_atomic_destroy_uint
*
* Purpose: Destroys / releases resources for an atomic 'unsigned' variable
*
* Note: No equivalent in the C11 atomics, but needed here, to destroy
* the mutex used to protect the atomic value.
*
* Return: None
*
*--------------------------------------------------------------------------
*/
void
H5TS_atomic_destroy_uint(H5TS_atomic_uint_t *obj)
{
FUNC_ENTER_NOAPI_NAMECHECK_ONLY

/* Destroy mutex that protects the "atomic" value */
(void) H5TS_mutex_destroy(&obj->mutex);

FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY
} /* end H5TS_atomic_destroy_uint() */

#endif /* H5_HAVE_STDATOMIC_H */

#endif /* H5_HAVE_THREADSAFE */
16 changes: 5 additions & 11 deletions src/H5TSint.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,9 @@ H5TS__init(void)
FUNC_ENTER_PACKAGE_NAMECHECK_ONLY

/* Initialize the global API lock */
memset(&H5TS_api_info_p, 0, sizeof(H5TS_api_info_p));
if (H5_UNLIKELY(H5TS__ex_lock_init(&H5TS_api_info_p.api_lock) < 0))
HGOTO_DONE(FAIL);
if (H5_UNLIKELY(H5TS_mutex_init(&H5TS_api_info_p.attempt_mutex) < 0))
HGOTO_DONE(FAIL);
H5TS_atomic_init_uint(&H5TS_api_info_p.attempt_lock_count, 0);

/* Initialize per-thread library info */
if (H5_UNLIKELY(H5TS__tinfo_init() < 0))
Expand Down Expand Up @@ -151,8 +149,8 @@ H5TS_term_package(void)
/* Destroy global API lock */
H5TS__ex_lock_destroy(&H5TS_api_info_p.api_lock);

/* Destroy the "lock acquisition attempt" mutex */
H5TS_mutex_destroy(&H5TS_api_info_p.attempt_mutex);
/* Destroy the "lock acquisition attempt" atomic */
H5TS_atomic_destroy_uint(&H5TS_api_info_p.attempt_lock_count);

/* Clean up per-process thread local storage */
H5TS__tinfo_term();
Expand Down Expand Up @@ -216,12 +214,8 @@ H5TS_api_lock(void)
if (H5_UNLIKELY(H5TS_once(&H5TS_first_init_s, H5TS_ONCE_INIT_FUNC) < 0))
HGOTO_DONE(FAIL);

/* Acquire the "attempt" mutex, increment the attempt lock count, release the lock */
if (H5_UNLIKELY(H5TS_mutex_lock(&H5TS_api_info_p.attempt_mutex) < 0))
HGOTO_DONE(FAIL);
H5TS_api_info_p.attempt_lock_count++;
if (H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.attempt_mutex) < 0))
HGOTO_DONE(FAIL);
/* Increment the attempt lock count */
H5TS_atomic_fetch_add_uint(&H5TS_api_info_p.attempt_lock_count, 1);

/* Acquire the library's exclusive API lock */
if (H5_UNLIKELY(H5TS__ex_lock(&H5TS_api_info_p.api_lock) < 0))
Expand Down
3 changes: 1 addition & 2 deletions src/H5TSpkg.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ typedef struct H5TS_api_info_t {
H5TS_ex_lock_t api_lock;

/* Count of # of attempts to acquire API lock */
H5TS_mutex_t attempt_mutex; /* mutex for attempt_lock_count */
unsigned attempt_lock_count;
H5TS_atomic_uint_t attempt_lock_count;
} H5TS_api_info_t;

#if H5TS_ENABLE_REC_RW_LOCK_STATS
Expand Down
25 changes: 24 additions & 1 deletion src/H5TSprivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,22 @@

/* Atomics macros */
#ifdef H5_HAVE_STDATOMIC_H
/* atomic_int */
#define H5TS_atomic_init_int(obj, desired) atomic_init((obj), (desired))
#define H5TS_atomic_load_int(obj) atomic_load(obj)
#define H5TS_atomic_store_int(obj, desired) atomic_store((obj), (desired))
#define H5TS_atomic_fetch_add_int(obj, arg) atomic_fetch_add((obj), (arg))
#define H5TS_atomic_fetch_sub_int(obj, arg) atomic_fetch_sub((obj), (arg))
#define H5TS_atomic_destroy_int(obj) /* void */
#endif /* H5_HAVE_STDATOMIC_H */

/* atomic_uint */
#define H5TS_atomic_init_uint(obj, desired) atomic_init((obj), (desired))
#define H5TS_atomic_load_uint(obj) atomic_load(obj)
#define H5TS_atomic_store_uint(obj, desired) atomic_store((obj), (desired))
#define H5TS_atomic_fetch_add_uint(obj, arg) atomic_fetch_add((obj), (arg))
#define H5TS_atomic_fetch_sub_uint(obj, arg) atomic_fetch_sub((obj), (arg))
#define H5TS_atomic_destroy_uint(obj) /* void */
#endif /* H5_HAVE_STDATOMIC_H */

/****************************/
/* Library Private Typedefs */
Expand Down Expand Up @@ -124,11 +133,16 @@ typedef void (*H5TS_once_init_func_t)(void);
/* Atomics */
#ifdef H5_HAVE_STDATOMIC_H
typedef atomic_int H5TS_atomic_int_t;
typedef atomic_uint H5TS_atomic_uint_t;
#else
typedef struct {
H5TS_mutex_t mutex;
int value;
} H5TS_atomic_int_t;
typedef struct {
H5TS_mutex_t mutex;
unsigned value;
} H5TS_atomic_uint_t;
#endif

/*****************************/
Expand Down Expand Up @@ -187,12 +201,21 @@ H5_DLL herr_t H5TS_pool_destroy(H5TS_pool_t *pool);

/* Emulated C11 atomics */
#ifndef H5_HAVE_STDATOMIC_H
/* atomic_int */
H5_DLL void H5TS_atomic_init_int(H5TS_atomic_int_t *obj, int desired);
H5_DLL int H5TS_atomic_load_int(H5TS_atomic_int_t *obj);
H5_DLL void H5TS_atomic_store_int(H5TS_atomic_int_t *obj, int desired);
H5_DLL int H5TS_atomic_fetch_add_int(H5TS_atomic_int_t *obj, int arg);
H5_DLL int H5TS_atomic_fetch_sub_int(H5TS_atomic_int_t *obj, int arg);
H5_DLL void H5TS_atomic_destroy_int(H5TS_atomic_int_t *obj);

/* atomic_uint */
H5_DLL void H5TS_atomic_init_uint(H5TS_atomic_uint_t *obj, unsigned desired);
H5_DLL unsigned H5TS_atomic_load_uint(H5TS_atomic_uint_t *obj);
H5_DLL void H5TS_atomic_store_uint(H5TS_atomic_uint_t *obj, unsigned desired);
H5_DLL unsigned H5TS_atomic_fetch_add_uint(H5TS_atomic_uint_t *obj, unsigned arg);
H5_DLL unsigned H5TS_atomic_fetch_sub_uint(H5TS_atomic_uint_t *obj, unsigned arg);
H5_DLL void H5TS_atomic_destroy_uint(H5TS_atomic_uint_t *obj);
#endif /* H5_HAVE_STDATOMIC_H */

#else /* H5_HAVE_THREADSAFE */
Expand Down

0 comments on commit 7f1a7a8

Please sign in to comment.