diff --git a/src/lib/mutex.c b/src/lib/mutex.c index 25b56679c..bdbc6662e 100644 --- a/src/lib/mutex.c +++ b/src/lib/mutex.c @@ -26,11 +26,6 @@ * Mutual exclusion locking. */ -LUMIERA_ERROR_DEFINE (LOCK_ACQUIRE, "locking failed"); -LUMIERA_ERROR_DEFINE (LOCK_RELEASE, "unlocking failed"); -LUMIERA_ERROR_DEFINE (LOCK_DESTROY, "lock destroy failed"); - - LumieraMutex lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag) { @@ -56,10 +51,7 @@ lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag) return self; } -int lumiera_mutex_unlock_cb (void* mutex) -{ - return pthread_mutex_unlock (&((LumieraMutex)mutex)->mutex); -} + /* // Local Variables: diff --git a/src/lib/mutex.h b/src/lib/mutex.h index c49265e6a..733fb06a6 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -24,8 +24,10 @@ #include "lib/error.h" #include "lib/sectionlock.h" +#include "lib/lockerror.h" #include +#include #include /** @@ -33,26 +35,22 @@ * Mutual exclusion locking, header. */ - /** * Mutual exclusive section. */ -#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \ - for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ - lumiera_lock_section_ = { \ - mtx, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ - ({ \ - if (lumiera_lock_section_.lock) \ - { \ - RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->mutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - } \ - lumiera_lock_section_.lock; \ - }); \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ +#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \ + for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \ + lumiera_lock_section_ = { \ + mtx, (lumiera_sectionlock_unlock_fn) lumiera_mutex_unlock \ + NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + lumiera_lock_section_.lock = \ + lumiera_mutex_lock (mtx, &NOBUG_FLAG(nobugflag), &lumiera_lock_section_.rh); \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ })) @@ -63,26 +61,26 @@ * This macro should only be used inside LUMIERA_MUTEX_SECTION and should be * called on the correct mutexes, period. */ -#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \ - for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ - NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ - mtx, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ - ({ \ - if (lumiera_lock_section_.lock) \ - { \ - REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ - RESOURCE_WAIT (nobugflag, (mtx)->rh, "acquire mutex", lumiera_lock_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->mutex)) \ - LUMIERA_DIE (LOCK_ACQUIRE); \ - RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \ - LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ - } \ - lumiera_lock_section_.lock; \ - }); \ - ({ \ - LUMIERA_MUTEX_SECTION_UNLOCK; \ +#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \ + for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \ + NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \ + mtx, (lumiera_sectionlock_unlock_fn) lumiera_mutex_unlock \ + NOBUG_ALPHA_COMMA(&NOBUG_FLAG(nobugflag)) NOBUG_ALPHA_COMMA_NULL}; \ + ({ \ + if (lumiera_lock_section_.lock) \ + { \ + REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \ + lumiera_lock_section_.lock = \ + lumiera_mutex_lock (mtx, &NOBUG_FLAG(nobugflag), &lumiera_lock_section_.rh); \ + LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \ + } \ + lumiera_lock_section_.lock; \ + }); \ + ({ \ + LUMIERA_MUTEX_SECTION_UNLOCK; \ })) + #define LUMIERA_MUTEX_SECTION_UNLOCK \ LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_) @@ -104,6 +102,8 @@ typedef lumiera_mutex* LumieraMutex; * Initialize a mutex variable * This initializes a 'fast' default mutex which must not be locked recursively from one thread. * @param self is a pointer to the mutex to be initialized + * @param purpose textual hint for the nobug resourcetracker + * @param flag nobug logging target * @return self as given */ LumieraMutex @@ -112,6 +112,7 @@ lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* f /** * Destroy a mutex variable * @param self is a pointer to the mutex to be destroyed + * @param flag nobug logging target * @return self as given */ LumieraMutex @@ -119,11 +120,125 @@ lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag); /** - * Callback for unlocking mutexes. - * @internal + * Lock a mutex variable + * Never fails + * @param self is a pointer to the mutex to be destroyed + * @param flag nobug logging target + * @param handle pointer to nobug user handle (NULL in beta and release builds) + * @return self as given */ -int -lumiera_mutex_unlock_cb (void* mutex); +static inline LumieraMutex +lumiera_mutex_lock (LumieraMutex self, struct nobug_flag* flag, struct nobug_resource_user** handle) +{ + if (self) + { + RESOURCE_WAIT (NOBUG_FLAG_RAW(flag), self->rh, "acquire mutex", *handle); + + if (pthread_mutex_lock (&self->mutex)) + LUMIERA_DIE (LOCK_ACQUIRE); /* never reached (in a correct program) */ + + RESOURCE_STATE (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle); + } + + return self; +} + + +/** + * Try to lock a mutex variable + * @param self is a pointer to the mutex to be destroyed + * @param flag nobug logging target + * @param handle pointer to nobug user handle (NULL in beta and release builds) + * @return self as given or NULL on error, lumiera_error gets set approbiately + */ +static inline LumieraMutex +lumiera_mutex_trylock (LumieraMutex self, struct nobug_flag* flag, struct nobug_resource_user** handle) +{ + if (self) + { + NOBUG_RESOURCE_TRY (NOBUG_FLAG_RAW(flag), self->rh, "try acquire mutex", *handle); + + int err = pthread_mutex_trylock (&self->mutex); + + if (!err) + { + RESOURCE_STATE (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle); + } + else + { + NOBUG_RESOURCE_LEAVE_RAW(flag, *handle) /*{}*/; + lumiera_lockerror_set (err, flag, __func__); + return NULL; + } + } + + return self; +} + + +#ifndef LUMIERA_RESTRICT +# ifdef __cplusplus /* C++ doesnt support restrict */ +# define LUMIERA_RESTRICT +# else +# define LUMIERA_RESTRICT restrict +# endif +#endif + + +/** + * Try to lock a mutex variable with a timeout + * @param self is a pointer to the mutex to be destroyed + * @param timeout timeout for waiting for the lock + * @param flag nobug logging target + * @param handle pointer to nobug user handle (NULL in beta and release builds) + * @return self as given or NULL on error, lumiera_error gets set approbiately + */ +static inline LumieraMutex +lumiera_mutex_timedlock (LumieraMutex self, + const struct timespec* LUMIERA_RESTRICT timeout, + struct nobug_flag* flag, + struct nobug_resource_user** handle) +{ + if (self) + { + NOBUG_RESOURCE_TRY (NOBUG_FLAG_RAW(flag), self->rh, "timed acquire mutex", *handle); + + int err = pthread_mutex_timedlock (&self->mutex, timeout); + + if (!err) + { + RESOURCE_STATE (NOBUG_FLAG_RAW(flag), NOBUG_RESOURCE_EXCLUSIVE, *handle); + } + else + { + NOBUG_RESOURCE_LEAVE_RAW(flag, *handle) /*{}*/; + lumiera_lockerror_set (err, flag, __func__); + return NULL; + } + } + + return self; +} + + +/** + * unlock a mutex variable + * Never fails + * @param self is a pointer to the mutex to be destroyed + * @param flag nobug logging target + * @param handle pointer to nobug user handle (NULL in beta and release builds) + */ +static inline void +lumiera_mutex_unlock (LumieraMutex self, struct nobug_flag* flag, struct nobug_resource_user** handle) +{ + REQUIRE(self); + + NOBUG_RESOURCE_LEAVE_RAW(flag, *handle) + { + if (pthread_mutex_unlock (&self->mutex)) + LUMIERA_DIE (LOCK_RELEASE); /* never reached (in a correct program) */ + } +} #endif diff --git a/src/lib/sectionlock.h b/src/lib/sectionlock.h index 808484007..a0a751ce7 100644 --- a/src/lib/sectionlock.h +++ b/src/lib/sectionlock.h @@ -26,7 +26,7 @@ #include -typedef int (*lumiera_sectionlock_unlock_fn)(void*); +typedef int (*lumiera_sectionlock_unlock_fn)(void*, struct nobug_flag* flag, struct nobug_resource_user** handle); /** * sectionlock used to manage the state of mutexes. @@ -49,22 +49,17 @@ lumiera_sectionlock_ensureunlocked (LumieraSectionlock self) } - /** * Unlock the lock hold in a SECTION * @internal * @param sectionname name used for the sectionlock instance * @param ... some extra code to execute */ -#define LUMIERA_SECTION_UNLOCK_(section) \ - do if ((section)->lock) \ - { \ - NOBUG_RESOURCE_LEAVE_RAW((section)->flag, (section)->rh) \ - { \ - if ((section)->unlock((section)->lock)) \ - LUMIERA_DIE (LOCK_RELEASE); \ - (section)->lock = NULL; \ - } \ +#define LUMIERA_SECTION_UNLOCK_(section) \ + do if ((section)->lock) \ + { \ + (section)->unlock((section)->lock, (section)->flag, &(section)->rh); \ + (section)->lock = NULL; \ } while (0)