From ed246ab2224667db40faa8021da2bfa61063ac38 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 27 Sep 2008 04:19:43 +0200 Subject: [PATCH] Adding recursive mutexes, fix chained mutex to take only one parameter Recursive mutex can be locked multiple times by a single thread they are initialitzed by lumiera_recmutex_init() and used by LUMIERA_RECMUTEX_* macros. Chained mutex use the mutexacquirer from the outer scope now. Maybe its later needed to pass acquirers explicit, we will see. --- src/lib/mutex.c | 24 +++++++++ src/lib/mutex.h | 97 +++++++++++++++++++++++++++++++----- tests/15locking.tests | 6 +++ tests/library/test-locking.c | 23 ++++++++- 4 files changed, 136 insertions(+), 14 deletions(-) diff --git a/src/lib/mutex.c b/src/lib/mutex.c index 99ef8897f..b228de746 100644 --- a/src/lib/mutex.c +++ b/src/lib/mutex.c @@ -44,6 +44,30 @@ lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* f } +static pthread_once_t recursive_mutexattr_once = PTHREAD_ONCE_INIT; +static pthread_mutexattr_t recursive_mutexattr; + +static void recursive_mutexattr_init() +{ + pthread_mutexattr_init (&recursive_mutexattr); + pthread_mutexattr_settype (&recursive_mutexattr, PTHREAD_MUTEX_RECURSIVE); +} + + +LumieraMutex +lumiera_recmutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag) +{ + if (self) + { + pthread_once(&recursive_mutexattr_once, recursive_mutexattr_init); + pthread_mutex_init (&self->mutex, &recursive_mutexattr); + NOBUG_RESOURCE_HANDLE_INIT (self->rh); + NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "recmutex", purpose, self, self->rh); + } + return self; +} + + LumieraMutex lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag) { diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 0de69c2f7..9645cfd35 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -62,27 +62,28 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); /** * Mutual exclusion chainbuilder section. - * Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(a,b){run();}} + * Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(b){run();}} * calls lock(a); lock(b); unlock(a); run(); unlock(b); * 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, mtxa, mtxb) \ - for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ +#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \ + for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \ + NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ lumiera_mutex_section_.mutex;) \ for ( \ ({ \ - lumiera_mutex_section_.mutex = (mtxb); \ + lumiera_mutex_section_.mutex = (mtx); \ NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ - RESOURCE_ENTER (nobugflag, (mtxb)->rh, "acquire mutex", &lumiera_mutex_section_, \ + RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \ NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \ - if (pthread_mutex_lock (&(mtxb)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ - if (mtxa) \ - { \ - pthread_mutex_unlock (&mtxa->mutex); \ - mtxa = NULL; \ - RESOURCE_LEAVE(nobugflag, mtxa.rh); \ - } \ + if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ + if (lumiera_mutex_section_old_->mutex) \ + { \ + pthread_mutex_unlock (&lumiera_mutex_section_old_->mutex->mutex); \ + lumiera_mutex_section_old_->mutex = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_old_->rh); \ + } \ }); \ lumiera_mutex_section_.mutex; \ ({ \ @@ -94,6 +95,68 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); } \ })) + +/** + * Recursive Mutual exclusive section. + */ +#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \ + for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ + lumiera_mutex_section_.mutex;) \ + for ( \ + ({ \ + lumiera_mutex_section_.mutex = (mtx); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ + RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_mutex_section_, \ + NOBUG_RESOURCE_RECURSIVE, lumiera_mutex_section_.rh); \ + if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ + }); \ + lumiera_mutex_section_.mutex; \ + ({ \ + if (lumiera_mutex_section_.mutex) \ + { \ + pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \ + lumiera_mutex_section_.mutex = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \ + } \ + })) + + +/** + * Mutual exclusion chainbuilder section. + * Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_RECMUTEX_SECTION_CHAIN(b){run();}} + * calls lock(a); lock(b); unlock(a); run(); unlock(b); + * This macro should only be used inside LUMIERA_MUTEX_SECTION and should be + * called on the correct mutexes, period. + */ +#define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \ + for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \ + NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ + lumiera_mutex_section_.mutex;) \ + for ( \ + ({ \ + lumiera_mutex_section_.mutex = (mtx); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ + RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_mutex_section_, \ + NOBUG_RESOURCE_RECURSIVE, lumiera_mutex_section_.rh); \ + if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ + if (lumiera_mutex_section_old_->mutex) \ + { \ + pthread_mutex_unlock (&lumiera_mutex_section_old_->mutex->mutex); \ + lumiera_mutex_section_old_->mutex = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_old_->rh); \ + } \ + }); \ + lumiera_mutex_section_.mutex; \ + ({ \ + if (lumiera_mutex_section_.mutex) \ + { \ + pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \ + lumiera_mutex_section_.mutex = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \ + } \ + })) + + /** * Mutex. * @@ -109,12 +172,22 @@ 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 * @return self as given */ LumieraMutex lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag); +/** + * Initialize a mutex variable + * Initializes a 'recursive' mutex which might be locked by the same thread multiple times. + * @param self is a pointer to the mutex to be initialized + * @return self as given + */ +LumieraMutex +lumiera_recmutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag); + /** * Destroy a mutex variable diff --git a/tests/15locking.tests b/tests/15locking.tests index fab6431bf..3420f3fa1 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -24,6 +24,12 @@ out: inner but not outer mutex locked section END +TEST "recursive mutex section" recursivemutexsection <