diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 681d29432..0de69c2f7 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -60,6 +60,39 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); } \ })) +/** + * Mutual exclusion chainbuilder section. + * Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(a,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}; \ + lumiera_mutex_section_.mutex;) \ + for ( \ + ({ \ + lumiera_mutex_section_.mutex = (mtxb); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ + RESOURCE_ENTER (nobugflag, (mtxb)->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); \ + } \ + }); \ + 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. diff --git a/tests/15locking.tests b/tests/15locking.tests index c7e8340e5..fab6431bf 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -18,6 +18,12 @@ out: inner mutex locked section END +TEST "chained mutex section" chainedmutexsection <