From 5bb6d7edbf4edbc135a4d9aeda19cd7994cb7077 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 2 Aug 2011 23:33:27 -0600 Subject: Wrap pthread API to reduce duplicated error tests. --- libdimension/error.c | 64 +++++++++++-------- libdimension/profile.c | 51 ++++----------- libdimension/progress.c | 123 +++++++++--------------------------- libdimension/prtree.c | 29 +++------ libdimension/tests/prtree.c | 2 +- libdimension/threads.c | 138 ++++++++++++++++++++++++++++++++++++++++ libdimension/threads.h | 151 +++++++++++++++++++++++++++++++++++++++++--- 7 files changed, 369 insertions(+), 189 deletions(-) diff --git a/libdimension/error.c b/libdimension/error.c index cfeed94..6276c5c 100644 --- a/libdimension/error.c +++ b/libdimension/error.c @@ -36,6 +36,29 @@ abort(); \ } while (0) +/** dmnsn_local_lock_mutex implementation. */ +static void +dmnsn_local_lock_mutex_impl(pthread_mutex_t *mutex) +{ + if (pthread_mutex_lock(mutex) != 0) { + DMNSN_LOCAL_ERROR("Couldn't lock mutex."); + } +} + +/** dmnsn_local_unlock_mutex implementation. */ +static void +dmnsn_local_unlock_mutex_impl(pthread_mutex_t *mutex) +{ + if (pthread_mutex_unlock(mutex) != 0) { + DMNSN_LOCAL_ERROR("Couldn't lock mutex."); + } +} + +/** Lock a mutex, bailing out without dmnsn_error() on error. */ +#define dmnsn_local_lock_mutex(mutex) dmnsn_local_lock_mutex_impl((mutex)); { +/** Unlock a mutex, bailing out without dmnsn_error() on error. */ +#define dmnsn_local_unlock_mutex(mutex) dmnsn_local_unlock_mutex_impl((mutex)); } + /** The default fatal error handler. */ static void dmnsn_default_fatal_error_fn(void); @@ -54,13 +77,10 @@ void dmnsn_report_error(bool die, const char *func, const char *file, unsigned int line, const char *str) { - if (pthread_mutex_lock(&dmnsn_always_die_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't lock mutex."); - } - bool always_die = dmnsn_always_die; - if (pthread_mutex_unlock(&dmnsn_always_die_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't unlock mutex."); - } + bool always_die; + dmnsn_local_lock_mutex(&dmnsn_always_die_mutex); + always_die = dmnsn_always_die; + dmnsn_local_unlock_mutex(&dmnsn_always_die_mutex); fprintf(stderr, "Dimension %s: %s, %s:%u: %s\n", die ? "ERROR" : "WARNING", func, file, line, str); @@ -87,39 +107,27 @@ dmnsn_report_error(bool die, const char *func, const char *file, void dmnsn_die_on_warnings(bool always_die) { - if (pthread_mutex_lock(&dmnsn_always_die_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't lock mutex."); - } - dmnsn_always_die = always_die; - if (pthread_mutex_unlock(&dmnsn_always_die_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't unlock mutex."); - } + dmnsn_local_lock_mutex(&dmnsn_always_die_mutex); + dmnsn_always_die = always_die; + dmnsn_local_unlock_mutex(&dmnsn_always_die_mutex); } dmnsn_fatal_error_fn * dmnsn_get_fatal_error_fn(void) { dmnsn_fatal_error_fn *fatal; - if (pthread_mutex_lock(&dmnsn_fatal_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't lock fatal error handler mutex."); - } - fatal = dmnsn_fatal; - if (pthread_mutex_unlock(&dmnsn_fatal_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't unlock fatal error handler mutex."); - } + dmnsn_local_lock_mutex(&dmnsn_fatal_mutex); + fatal = dmnsn_fatal; + dmnsn_local_unlock_mutex(&dmnsn_fatal_mutex); return fatal; } void dmnsn_set_fatal_error_fn(dmnsn_fatal_error_fn *fatal) { - if (pthread_mutex_lock(&dmnsn_fatal_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't lock fatal error handler mutex."); - } - dmnsn_fatal = fatal; - if (pthread_mutex_unlock(&dmnsn_fatal_mutex) != 0) { - DMNSN_LOCAL_ERROR("Couldn't unlock fatal error handler mutex."); - } + dmnsn_local_lock_mutex(&dmnsn_fatal_mutex); + dmnsn_fatal = fatal; + dmnsn_local_unlock_mutex(&dmnsn_fatal_mutex); } static void diff --git a/libdimension/profile.c b/libdimension/profile.c index 8fca36a..f7e8e41 100644 --- a/libdimension/profile.c +++ b/libdimension/profile.c @@ -65,13 +65,9 @@ dmnsn_delete_thread_profile(void *ptr) { dmnsn_dictionary *thread_profile = ptr; - if (pthread_mutex_lock(&dmnsn_profile_mutex) != 0) { - dmnsn_error("Couldn't lock mutex."); - } - dmnsn_dictionary_apply(thread_profile, dmnsn_profile_globalize); - if (pthread_mutex_unlock(&dmnsn_profile_mutex) != 0) { - dmnsn_error("Couldn't unlock mutex."); - } + dmnsn_lock_mutex(&dmnsn_profile_mutex); + dmnsn_dictionary_apply(thread_profile, dmnsn_profile_globalize); + dmnsn_unlock_mutex(&dmnsn_profile_mutex); dmnsn_delete_dictionary(thread_profile); } @@ -80,31 +76,18 @@ dmnsn_delete_thread_profile(void *ptr) static void dmnsn_initialize_thread_profile(void) { - if (pthread_key_create(&dmnsn_thread_profile, dmnsn_delete_thread_profile) - != 0) - { - dmnsn_error("pthread_key_create() failed."); - } + dmnsn_key_create(&dmnsn_thread_profile, dmnsn_delete_thread_profile); - if (pthread_mutex_lock(&dmnsn_profile_mutex) != 0) { - dmnsn_error("Couldn't lock mutex."); - } - dmnsn_profile = dmnsn_new_dictionary(sizeof(dmnsn_branch)); - if (pthread_mutex_unlock(&dmnsn_profile_mutex) != 0) { - dmnsn_error("Couldn't unlock mutex."); - } + dmnsn_lock_mutex(&dmnsn_profile_mutex); + dmnsn_profile = dmnsn_new_dictionary(sizeof(dmnsn_branch)); + dmnsn_unlock_mutex(&dmnsn_profile_mutex); } /** Get the thread-specific profile data. */ static dmnsn_dictionary * dmnsn_get_thread_profile(void) { - if (pthread_once(&dmnsn_thread_profile_once, dmnsn_initialize_thread_profile) - != 0) - { - dmnsn_error("pthread_once() failed."); - } - + dmnsn_once(&dmnsn_thread_profile_once, dmnsn_initialize_thread_profile); return pthread_getspecific(dmnsn_thread_profile); } @@ -112,9 +95,7 @@ dmnsn_get_thread_profile(void) static void dmnsn_set_thread_profile(dmnsn_dictionary *thread_profile) { - if (pthread_setspecific(dmnsn_thread_profile, thread_profile) != 0) { - dmnsn_error("pthread_setspecific() failed."); - } + dmnsn_setspecific(dmnsn_thread_profile, thread_profile); } bool @@ -178,13 +159,9 @@ dmnsn_print_bad_predictions(void) dmnsn_set_thread_profile(NULL); } - if (pthread_mutex_lock(&dmnsn_profile_mutex) != 0) { - dmnsn_error("Couldn't lock mutex."); - } - dmnsn_dictionary_apply(dmnsn_profile, dmnsn_print_bad_prediction); - dmnsn_delete_dictionary(dmnsn_profile); - dmnsn_profile = NULL; - if (pthread_mutex_unlock(&dmnsn_profile_mutex) != 0) { - dmnsn_error("Couldn't unlock mutex."); - } + dmnsn_lock_mutex(&dmnsn_profile_mutex); + dmnsn_dictionary_apply(dmnsn_profile, dmnsn_print_bad_prediction); + dmnsn_delete_dictionary(dmnsn_profile); + dmnsn_profile = NULL; + dmnsn_unlock_mutex(&dmnsn_profile_mutex); } diff --git a/libdimension/progress.c b/libdimension/progress.c index 22696cb..7344679 100644 --- a/libdimension/progress.c +++ b/libdimension/progress.c @@ -26,13 +26,6 @@ #include "dimension-impl.h" #include -/** Read-lock a progress object. */ -static void dmnsn_progress_rdlock(const dmnsn_progress *progress); -/** Write-lock a progress object. */ -static void dmnsn_progress_wrlock(dmnsn_progress *progress); -/** Unlock a progress object. */ -static void dmnsn_progress_unlock(const dmnsn_progress *progress); - /* Allocate a new dmnsn_progress* */ dmnsn_progress * dmnsn_new_progress(void) @@ -44,19 +37,13 @@ dmnsn_new_progress(void) /* Initialize the rwlock, condition variable, and mutex */ progress->rwlock = dmnsn_malloc(sizeof(pthread_rwlock_t)); - if (pthread_rwlock_init(progress->rwlock, NULL) != 0) { - dmnsn_error("Couldn't initialize read-write lock."); - } + dmnsn_initialize_rwlock(progress->rwlock); progress->cond = dmnsn_malloc(sizeof(pthread_cond_t)); - if (pthread_cond_init(progress->cond, NULL) != 0) { - dmnsn_error("Couldn't initialize condition variable."); - } + dmnsn_initialize_cond(progress->cond); progress->mutex = dmnsn_malloc(sizeof(pthread_mutex_t)); - if (pthread_mutex_init(progress->mutex, NULL) != 0) { - dmnsn_error("Couldn't initialize mutex."); - } + dmnsn_initialize_mutex(progress->mutex); progress->min_wait = 1.0; progress->min_waitp = &progress->min_wait; @@ -81,18 +68,16 @@ dmnsn_finish_progress(dmnsn_progress *progress) } /* Free the progress object */ - if (pthread_rwlock_destroy(progress->rwlock) != 0) { - dmnsn_warning("Leaking rwlock."); - } - if (pthread_mutex_destroy(progress->mutex) != 0) { - dmnsn_warning("Leaking mutex."); - } - if (pthread_cond_destroy(progress->cond) != 0) { - dmnsn_warning("Leaking condition variable."); - } - dmnsn_free(progress->rwlock); + + dmnsn_destroy_mutex(progress->mutex); dmnsn_free(progress->mutex); + + dmnsn_destroy_cond(progress->cond); dmnsn_free(progress->cond); + + dmnsn_destroy_rwlock(progress->rwlock); + dmnsn_free(progress->rwlock); + dmnsn_free(progress); } @@ -105,9 +90,9 @@ dmnsn_get_progress(const dmnsn_progress *progress) { double prog; - dmnsn_progress_rdlock(progress); + dmnsn_read_lock(progress->rwlock); prog = (double)progress->progress/progress->total; - dmnsn_progress_unlock(progress); + dmnsn_unlock_rwlock(progress->rwlock); return prog; } @@ -116,100 +101,52 @@ dmnsn_get_progress(const dmnsn_progress *progress) void dmnsn_wait_progress(const dmnsn_progress *progress, double prog) { - if (pthread_mutex_lock(progress->mutex) == 0) { + dmnsn_lock_mutex(progress->mutex); while (dmnsn_get_progress(progress) < prog) { /* Set the minimum waited-on value */ if (prog < progress->min_wait) *progress->min_waitp = prog; - if (pthread_cond_wait(progress->cond, progress->mutex) != 0) { - dmnsn_error("Couldn't wait on condition variable."); - } - } - - if (pthread_mutex_unlock(progress->mutex) != 0) { - dmnsn_error("Couldn't unlock condition mutex."); + dmnsn_cond_wait(progress->cond, progress->mutex); } - } else { - dmnsn_error("Couldn't lock condition mutex."); - } + dmnsn_unlock_mutex(progress->mutex); } /* Set the total number of loop iterations */ void dmnsn_set_progress_total(dmnsn_progress *progress, size_t total) { - dmnsn_progress_wrlock(progress); + dmnsn_write_lock(progress->rwlock); progress->total = total; - dmnsn_progress_unlock(progress); + dmnsn_unlock_rwlock(progress->rwlock); } /* Increment the number of completed loop iterations */ void dmnsn_increment_progress(dmnsn_progress *progress) { - dmnsn_progress_wrlock(progress); + dmnsn_write_lock(progress->rwlock); ++progress->progress; - dmnsn_progress_unlock(progress); - - if (pthread_mutex_lock(progress->mutex) != 0) { - dmnsn_error("Couldn't lock condition mutex."); - } + dmnsn_unlock_rwlock(progress->rwlock); - if (dmnsn_get_progress(progress) >= progress->min_wait) { - progress->min_wait = 1.0; + dmnsn_lock_mutex(progress->mutex); + if (dmnsn_get_progress(progress) >= progress->min_wait) { + progress->min_wait = 1.0; - if (pthread_cond_broadcast(progress->cond) != 0) { - dmnsn_error("Couldn't signal condition variable."); + dmnsn_cond_broadcast(progress->cond); } - } - - if (pthread_mutex_unlock(progress->mutex) != 0) { - dmnsn_error("Couldn't unlock condition mutex."); - } + dmnsn_unlock_mutex(progress->mutex); } /* Immediately set to 100% completion */ void dmnsn_done_progress(dmnsn_progress *progress) { - dmnsn_progress_wrlock(progress); + dmnsn_write_lock(progress->rwlock); progress->progress = progress->total; - dmnsn_progress_unlock(progress); - - if (pthread_mutex_lock(progress->mutex) != 0) { - dmnsn_error("Couldn't lock condition mutex."); - } - if (pthread_cond_broadcast(progress->cond) != 0) { - dmnsn_error("Couldn't signal condition variable."); - } - if (pthread_mutex_unlock(progress->mutex) != 0) { - dmnsn_error("Couldn't unlock condition mutex."); - } -} - -/* Thread synchronization */ - -static void -dmnsn_progress_rdlock(const dmnsn_progress *progress) -{ - if (pthread_rwlock_rdlock(progress->rwlock) != 0) { - dmnsn_error("Couldn't acquire read-lock."); - } -} + dmnsn_unlock_rwlock(progress->rwlock); -static void -dmnsn_progress_wrlock(dmnsn_progress *progress) -{ - if (pthread_rwlock_wrlock(progress->rwlock) != 0) { - dmnsn_error("Couldn't acquire write-lock."); - } -} - -static void -dmnsn_progress_unlock(const dmnsn_progress *progress) -{ - if (pthread_rwlock_unlock(progress->rwlock) != 0) { - dmnsn_error("Couldn't unlock read-write lock."); - } + dmnsn_lock_mutex(progress->mutex); + dmnsn_cond_broadcast(progress->cond); + dmnsn_unlock_mutex(progress->mutex); } diff --git a/libdimension/prtree.c b/libdimension/prtree.c index 4c7a2e5..0663acf 100644 --- a/libdimension/prtree.c +++ b/libdimension/prtree.c @@ -448,13 +448,9 @@ dmnsn_new_prtree(const dmnsn_array *objects) prtree->bounding_box = dmnsn_zero_bounding_box(); } - if (pthread_mutex_lock(&dmnsn_prtree_seq_mutex) != 0) { - dmnsn_error("Couldn't lock mutex."); - } - prtree->id = dmnsn_prtree_seq++; - if (pthread_mutex_unlock(&dmnsn_prtree_seq_mutex) != 0) { - dmnsn_error("Couldn't unlock mutex."); - } + dmnsn_lock_mutex(&dmnsn_prtree_seq_mutex); + prtree->id = dmnsn_prtree_seq++; + dmnsn_unlock_mutex(&dmnsn_prtree_seq_mutex); return prtree; } @@ -545,20 +541,13 @@ dmnsn_delete_prtree_caches(void *caches) static void dmnsn_initialize_prtree_caches(void) { - if (pthread_key_create(&dmnsn_prtree_caches, dmnsn_delete_prtree_caches) != 0) - { - dmnsn_error("pthread_key_create() failed."); - } + dmnsn_key_create(&dmnsn_prtree_caches, dmnsn_delete_prtree_caches); } static dmnsn_array * dmnsn_get_prtree_caches(void) { - if (pthread_once(&dmnsn_prtree_caches_once, dmnsn_initialize_prtree_caches) - != 0) - { - dmnsn_error("pthread_once() failed."); - } + dmnsn_once(&dmnsn_prtree_caches_once, dmnsn_initialize_prtree_caches); return pthread_getspecific(dmnsn_prtree_caches); } @@ -567,8 +556,8 @@ dmnsn_get_prtree_caches(void) DMNSN_DESTRUCTOR static void dmnsn_delete_main_prtree_caches(void) { - dmnsn_delete_array(dmnsn_get_prtree_caches()); - pthread_key_delete(dmnsn_prtree_caches); + dmnsn_delete_prtree_caches(dmnsn_get_prtree_caches()); + dmnsn_key_delete(dmnsn_prtree_caches); } static dmnsn_intersection_cache * @@ -577,9 +566,7 @@ dmnsn_get_intersection_cache(size_t id) dmnsn_array *caches = dmnsn_get_prtree_caches(); if (!caches) { caches = dmnsn_new_array(sizeof(dmnsn_intersection_cache)); - if (pthread_setspecific(dmnsn_prtree_caches, caches) != 0) { - dmnsn_error("pthread_setspecific() failed."); - } + dmnsn_setspecific(dmnsn_prtree_caches, caches); } while (dmnsn_array_size(caches) <= id) { diff --git a/libdimension/tests/prtree.c b/libdimension/tests/prtree.c index 5fb2f10..ddfa46a 100644 --- a/libdimension/tests/prtree.c +++ b/libdimension/tests/prtree.c @@ -22,7 +22,7 @@ */ #include "dimension-impl.h" -#include "../../libdimension/prtree.c" /* For DMNSN_PRTREE_B */ +#define DMNSN_PRTREE_B 8 #include #include diff --git a/libdimension/threads.c b/libdimension/threads.c index 04874de..11b01cf 100644 --- a/libdimension/threads.c +++ b/libdimension/threads.c @@ -124,3 +124,141 @@ dmnsn_execute_concurrently(dmnsn_ccthread_fn *ccthread_fn, return ret; } + +/* pthread wrappers */ + +void +dmnsn_initialize_mutex(pthread_mutex_t *mutex) +{ + if (pthread_mutex_init(mutex, NULL) != 0) { + dmnsn_error("Couldn't initialize mutex."); + } +} + +void +dmnsn_lock_mutex_impl(pthread_mutex_t *mutex) +{ + if (pthread_mutex_lock(mutex) != 0) { + dmnsn_error("Couldn't lock mutex."); + } +} + +void +dmnsn_unlock_mutex_impl(pthread_mutex_t *mutex) +{ + if (pthread_mutex_unlock(mutex) != 0) { + dmnsn_error("Couldn't unlock mutex."); + } +} + +void +dmnsn_destroy_mutex(pthread_mutex_t *mutex) +{ + if (pthread_mutex_destroy(mutex) != 0) { + dmnsn_warning("Couldn't destroy mutex."); + } +} + +void +dmnsn_initialize_rwlock(pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock_init(rwlock, NULL) != 0) { + dmnsn_error("Couldn't initialize read-write lock."); + } +} + +void +dmnsn_read_lock_impl(pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock_rdlock(rwlock) != 0) { + dmnsn_error("Couldn't acquire read lock."); + } +} + +void +dmnsn_write_lock_impl(pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock_wrlock(rwlock) != 0) { + dmnsn_error("Couldn't acquire write lock."); + } +} + +void +dmnsn_unlock_rwlock_impl(pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock_unlock(rwlock) != 0) { + dmnsn_error("Couldn't unlock read-write lock."); + } +} + +void +dmnsn_destroy_rwlock(pthread_rwlock_t *rwlock) +{ + if (pthread_rwlock_destroy(rwlock) != 0) { + dmnsn_warning("Couldn't destroy read-write lock."); + } +} + +void +dmnsn_initialize_cond(pthread_cond_t *cond) +{ + if (pthread_cond_init(cond, NULL) != 0) { + dmnsn_error("Couldn't initialize condition variable."); + } +} + +void +dmnsn_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + if (pthread_cond_wait(cond, mutex) != 0) { + dmnsn_error("Couldn't wait on condition variable."); + } +} + +void +dmnsn_cond_broadcast(pthread_cond_t *cond) +{ + if (pthread_cond_broadcast(cond) != 0) { + dmnsn_error("Couldn't signal condition variable."); + } +} + +void +dmnsn_destroy_cond(pthread_cond_t *cond) +{ + if (pthread_cond_destroy(cond) != 0) { + dmnsn_warning("Couldn't destroy condition variable."); + } +} + +void +dmnsn_once(pthread_once_t *once, dmnsn_once_fn *once_fn) +{ + if (pthread_once(once, once_fn) != 0) { + dmnsn_error("Couldn't call one-shot function."); + } +} + +void +dmnsn_key_create(pthread_key_t *key, dmnsn_callback_fn *destructor) +{ + if (pthread_key_create(key, destructor) != 0) { + dmnsn_error("Couldn't initialize thread-specific pointer."); + } +} + +void +dmnsn_setspecific(pthread_key_t key, const void *value) +{ + if (pthread_setspecific(key, value) != 0) { + dmnsn_error("Couldn't set thread-specific pointer."); + } +} + +void +dmnsn_key_delete(pthread_key_t key) +{ + if (pthread_key_delete(key) != 0) { + dmnsn_warning("Couldn't destroy thread-specific pointer."); + } +} diff --git a/libdimension/threads.h b/libdimension/threads.h index 8e88e7c..229acb9 100644 --- a/libdimension/threads.h +++ b/libdimension/threads.h @@ -23,6 +23,8 @@ * Background threading interface. */ +#include + /** * Thread callback type. * @param[in,out] ptr An arbitrary pointer. @@ -30,6 +32,15 @@ */ typedef int dmnsn_thread_fn(void *ptr); +/** + * Create a thread that cleans up after itself on errors. + * @param[in,out] progress The progress object to associate with the thread. + * @param[in] thread_fn The thread callback. + * @param[in,out] arg The pointer to pass to the thread callback. + */ +DMNSN_INTERNAL void dmnsn_new_thread(dmnsn_progress *progress, + dmnsn_thread_fn *thread_fn, void *arg); + /** * Thread callback type for parallel tasks. * @param[in,out] ptr An arbitrary pointer. @@ -40,15 +51,6 @@ typedef int dmnsn_thread_fn(void *ptr); typedef int dmnsn_ccthread_fn(void *ptr, unsigned int thread, unsigned int nthreads); -/** - * Create a thread that cleans up after itself on errors. - * @param[in,out] progress The progress object to associate with the thread. - * @param[in] thread_fn The thread callback. - * @param[in,out] arg The pointer to pass to the thread callback. - */ -DMNSN_INTERNAL void dmnsn_new_thread(dmnsn_progress *progress, - dmnsn_thread_fn *thread_fn, void *arg); - /** * Run \p nthreads threads in parallel. * @param[in] ccthread_fn The routine to run in each concurrent thread. @@ -58,3 +60,134 @@ DMNSN_INTERNAL void dmnsn_new_thread(dmnsn_progress *progress, */ DMNSN_INTERNAL int dmnsn_execute_concurrently(dmnsn_ccthread_fn *ccthread_fn, void *arg, unsigned int nthreads); + +/** + * Initialize a mutex, bailing out on failure. + * @param[out] mutex The mutex to initialize. + */ +DMNSN_INTERNAL void dmnsn_initialize_mutex(pthread_mutex_t *mutex); + +/** dmnsn_lock_mutex() implementation. */ +DMNSN_INTERNAL void dmnsn_lock_mutex_impl(pthread_mutex_t *mutex); +/** dmnsn_unlock_mutex() implementation. */ +DMNSN_INTERNAL void dmnsn_unlock_mutex_impl(pthread_mutex_t *mutex); + +/** + * Lock a mutex, bailing out on failure. + * Contains a {, so must be used in the same block as dmnsn_unlock_mutex(). + * @param[in,out] mutex The mutex to lock. + */ +#define dmnsn_lock_mutex(mutex) dmnsn_lock_mutex_impl((mutex)); { + +/** + * Lock a mutex, bailing out on failure. + * Contains a }, so must be used in the same block as dmnsn_lock_mutex(). + * @param[in,out] mutex The mutex to unlock. + */ +#define dmnsn_unlock_mutex(mutex) dmnsn_unlock_mutex_impl((mutex)); } + +/** + * Destroy a mutex, warning on failure. + * @param[in,out] mutex The mutex to destroy. + */ +DMNSN_INTERNAL void dmnsn_destroy_mutex(pthread_mutex_t *mutex); + +/** + * Initialize a read-write lock, bailing out on failure. + * @param[out] rwlock The read-write lock to initialize. + */ +DMNSN_INTERNAL void dmnsn_initialize_rwlock(pthread_rwlock_t *rwlock); + +/** dmnsn_read_lock() implementation. */ +DMNSN_INTERNAL void dmnsn_read_lock_impl(pthread_rwlock_t *rwlock); +/** dmnsn_write_lock() implementation. */ +DMNSN_INTERNAL void dmnsn_write_lock_impl(pthread_rwlock_t *rwlock); +/** dmnsn_unlock_rwlock() implementation. */ +DMNSN_INTERNAL void dmnsn_unlock_rwlock_impl(pthread_rwlock_t *rwlock); + +/** + * Lock a read-write lock, bailing out on failure. + * Contains a {, so must be used in the same block as dmnsn_unlock_rwlock(). + * @param[in,out] rwlock The read-write lock to lock. + */ +#define dmnsn_read_lock(rwlock) dmnsn_read_lock_impl((rwlock)); { + +/** + * Lock a read-write lock, bailing out on failure. + * Contains a {, so must be used in the same block as dmnsn_unlock_rwlock(). + * @param[in,out] rwlock The read-write lock to lock. + */ +#define dmnsn_write_lock(rwlock) dmnsn_write_lock_impl((rwlock)); { + +/** + * Lock a read-write lock, bailing out on failure. + * Contains a }, so must be used in the same block as dmnsn_read_lock() or + * dmnsn_write_lock(). + * @param[in,out] rwlock The read-write lock to lock. + */ +#define dmnsn_unlock_rwlock(rwlock) dmnsn_unlock_rwlock_impl((rwlock)); } + +/** + * Destroy a read-write lock, warning on failure. + * @param[in,out] rwlock The read-write lock to destroy. + */ +DMNSN_INTERNAL void dmnsn_destroy_rwlock(pthread_rwlock_t *rwlock); + +/** + * Initialize a condition variable, bailing out on failure. + * @param[out] cond The condition variable to initialize. + */ +DMNSN_INTERNAL void dmnsn_initialize_cond(pthread_cond_t *cond); + +/** + * Wait on a condition variable, bailing out on error. + * @param[in] cond The condition variable to wait on. + * @param[in] mutex The associated mutex. + */ +DMNSN_INTERNAL void dmnsn_cond_wait(pthread_cond_t *cond, + pthread_mutex_t *mutex); + +/** + * Signal a condition variable, bailing out on error. + * @param[in] cond The condition variable to signal. + */ +DMNSN_INTERNAL void dmnsn_cond_broadcast(pthread_cond_t *cond); + +/** + * Destroy a condition variable, warning on failure. + * @param[in,out] cond The condition variable to destroy. + */ +DMNSN_INTERNAL void dmnsn_destroy_cond(pthread_cond_t *cond); + +/** + * Once-called callback type. + */ +typedef void dmnsn_once_fn(void); + +/** + * Call a function exactly once, bailing out on failure. + * @param[in,out] once The once control. + * @param[in] once_fn The function to call. + */ +DMNSN_INTERNAL void dmnsn_once(pthread_once_t *once, dmnsn_once_fn *once_fn); + +/** + * Initialize a thread-local storage key, bailing out on failure. + * @param[out] key The key to initialize. + * @param[in] destructor An optional destructor callback. + */ +DMNSN_INTERNAL void dmnsn_key_create(pthread_key_t *key, + dmnsn_callback_fn *destructor); + +/** + * Set a thread-specific pointer, bailing out on failure. + * @param[in] key The thread-local storage key. + * @param[in] value The value to set. + */ +DMNSN_INTERNAL void dmnsn_setspecific(pthread_key_t key, const void *value); + +/** + * Destroy a thread-local storage key, warning out on failure. + * @param[out] key The key to destroy. + */ +DMNSN_INTERNAL void dmnsn_key_delete(pthread_key_t key); -- cgit v1.2.3