From c11915a4c4771949ce249c5df58ba08025f94d0c Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 13:44:34 +0200 Subject: [PATCH] new locking section macros for RWLocks, old acquirer bites the dust --- src/lib/rwlock.c | 112 ++++------------------------- src/lib/rwlock.h | 134 ++++++++++++++++------------------- tests/15locking.tests | 11 +++ tests/library/test-locking.c | 37 ++++++++++ 4 files changed, 125 insertions(+), 169 deletions(-) diff --git a/src/lib/rwlock.c b/src/lib/rwlock.c index a12642c01..9fad975b3 100644 --- a/src/lib/rwlock.c +++ b/src/lib/rwlock.c @@ -18,28 +18,30 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include + +#include "lib/error.h" #include "lib/rwlock.h" + LUMIERA_ERROR_DEFINE(RWLOCK_AGAIN, "maximum number of readlocks exceed"); LUMIERA_ERROR_DEFINE(RWLOCK_DEADLOCK, "deadlock detected"); -LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroy rwlock"); -LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock"); -LUMIERA_ERROR_DEFINE(RWLOCK_RLOCK, "rlock"); -LUMIERA_ERROR_DEFINE(RWLOCK_WLOCK, "wlock"); +LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroying rwlock"); +LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock rwlock failed"); +LUMIERA_ERROR_DEFINE(RWLOCK_RDLOCK, "locking rwlock for reading failed"); +LUMIERA_ERROR_DEFINE(RWLOCK_WRLOCK, "locking rwlock for writing failed"); /** * @file * Read/write locks. */ - LumieraRWLock lumiera_rwlock_init (LumieraRWLock self) { if (self) { pthread_rwlock_init (&self->rwlock, NULL); + NOBUG_RESOURCE_HANDLE_INIT (self->rh); } return self; } @@ -56,94 +58,10 @@ lumiera_rwlock_destroy (LumieraRWLock self) return self; } - - - - -LumieraRWLockacquirer -lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state) -{ - REQUIRE (self); - REQUIRE (rwlock); - REQUIRE (state != LUMIERA_LOCKED, "illegal state for rwlock"); - self->rwlock = rwlock; - self->state = state; - - if (state == LUMIERA_RDLOCKED) - switch (pthread_rwlock_rdlock (&rwlock->rwlock)) - { - case 0: - break; - case EAGAIN: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN); - return NULL; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_RLOCK); - } - else - switch (pthread_rwlock_wrlock (&rwlock->rwlock)) - { - case 0: - break; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_WLOCK); - } - - return self; -} - - - -LumieraRWLockacquirer -lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked"); - - switch (pthread_rwlock_rdlock (&self->rwlock->rwlock)) - { - case 0: - break; - case EAGAIN: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN); - return NULL; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_RLOCK); - } - - self->state = LUMIERA_RDLOCKED; - return self; -} - - - -LumieraRWLockacquirer -lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked"); - - switch (pthread_rwlock_wrlock (&self->rwlock->rwlock)) - { - case 0: - break; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_WLOCK); - } - - self->state = LUMIERA_WRLOCKED; - return self; -} - +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h index 3ac7f82ed..8d8f69e0c 100644 --- a/src/lib/rwlock.h +++ b/src/lib/rwlock.h @@ -27,41 +27,71 @@ #endif #include +//#include #include -#include "lib/locking.h" - LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN); LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK); LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY); LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK); -LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK); -LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK); +LUMIERA_ERROR_DECLARE(RWLOCK_RDLOCK); +LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK); /** * @file * Read/write locks, header. */ -#define LUMIERA_RDLOCK_SECTION(flag, handle, rwlock) \ -RESOURCE_HANDLE (rh_##__LINE__##_); \ -lumiera_rwlockacquirer lock_##__LINE__##_; \ -RESOURCE_ENTER (flag, handle, "acquire rwlock (read)", &lock_##__LINE__##_, \ - NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \ -for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_RDLOCKED); \ - lock_##__LINE__##_.state == LUMIERA_RDLOCKED; \ - lumiera_rwlockacquirer_unlock (&lock_##__LINE__##_), \ - ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);})) -#define LUMIERA_WRLOCK_SECTION(flag, handle, rwlock) \ -RESOURCE_HANDLE (rh_##__LINE__##_); \ -lumiera_rwlockacquirer lock_##__LINE__##_; \ -RESOURCE_ENTER (flag, handle, "acquire rwlock (write)", &lock_##__LINE__##_, \ - NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \ -for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_WRLOCKED); \ - lock_##__LINE__##_.state == LUMIERA_WRLOCKED; \ - lumiera_rwlockacquirer_unlock (&lock_##__LINE__##_), \ - ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);})) +/** + * Read locked section. + */ +#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \ + for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \ + lumiera_rwlock_section_.rwlock;) \ + for ( \ + ({ \ + lumiera_rwlock_section_.rwlock = (rwlck); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \ + RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \ + NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \ + if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_RDLOCK); \ + }); \ + lumiera_rwlock_section_.rwlock; \ + ({ \ + if (lumiera_rwlock_section_.rwlock) \ + { \ + pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \ + lumiera_rwlock_section_.rwlock = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \ + } \ + })) + + +/** + * Write locked section. + */ +#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \ + for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \ + lumiera_rwlock_section_.rwlock;) \ + for ( \ + ({ \ + lumiera_rwlock_section_.rwlock = (rwlck); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \ + RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \ + NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \ + if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_WRLOCK); \ + }); \ + lumiera_rwlock_section_.rwlock; \ + ({ \ + if (lumiera_rwlock_section_.rwlock) \ + { \ + pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \ + lumiera_rwlock_section_.rwlock = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \ + } \ + })) + /** * RWLock. @@ -70,6 +100,7 @@ for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_WRLOCKED) struct lumiera_rwlock_struct { pthread_rwlock_t rwlock; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_rwlock_struct lumiera_rwlock; typedef lumiera_rwlock* LumieraRWLock; @@ -99,7 +130,7 @@ lumiera_rwlock_destroy (LumieraRWLock self); struct lumiera_rwlockacquirer_struct { LumieraRWLock rwlock; - enum lumiera_lockstate state; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_rwlockacquirer_struct lumiera_rwlockacquirer; typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer; @@ -108,56 +139,15 @@ typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer; static inline void lumiera_rwlockacquirer_ensureunlocked (LumieraRWLockacquirer self) { - ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the rwlock"); -} - -/* override with a macro to use the cleanup checker */ -#define lumiera_rwlockacquirer \ -lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) - -/** - * initialize a rwlockacquirer state - * @param self rwlockacquirer to be initialized, must be an automatic variable - * @param rwlock associated rwlock - * @param state initial state of the mutex, either LUMIERA_RDLOCKED, LUMIERA_WRLOCKED or LUMIERA_UNLOCKED - * @return self as given or NULL on error - */ -LumieraRWLockacquirer -lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state); - -/** - * readlock the rwlock. - * must not already be locked - * @param self rwlockacquirer associated with a rwlock - * @return self as given or NULL on error - */ -LumieraRWLockacquirer -lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self); - -/** - * writelock the rwlock. - * must not already be locked - * @param self rwlockacquirer associated with a rwlock - * @return self as given or NULL on error - */ -LumieraRWLockacquirer -lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self); - - -/** - * release rwlock. - * a rwlockacquirer must be unlocked before leaving scope - * @param self rwlockacquirer associated with a rwlock variable - */ -static inline void -lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked"); - if (pthread_rwlock_unlock (&self->rwlock->rwlock)) - LUMIERA_DIE (RWLOCK_UNLOCK); - self->state = LUMIERA_UNLOCKED; + ENSURE (!self->rwlock, "forgot to unlock rwlock"); } #endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/tests/15locking.tests b/tests/15locking.tests index 80dda1a23..b994db1b2 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -24,3 +24,14 @@ TEST "nested mutex section" nestedmutexsection < #include @@ -105,5 +106,41 @@ TEST ("nestedmutexsection") +TEST ("rwlocksection") +{ + lumiera_rwlock rwlock; + lumiera_rwlock_init (&rwlock); + RESOURCE_ANNOUNCE (NOBUG_ON, "rwlock", "rwlocksection", &rwlock, rwlock.rh); + + LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock) + { + printf ("write locked section 1\n"); + } + + LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock) + { + printf ("read locked section 2\n"); + } + + RESOURCE_FORGET (NOBUG_ON, rwlock.rh); + lumiera_rwlock_destroy (&rwlock); +} + + +TEST ("rwlockforgotunlock") +{ + lumiera_rwlock rwlock; + lumiera_rwlock_init (&rwlock); + RESOURCE_ANNOUNCE (NOBUG_ON, "rwlock", "rwlockforgotunlock", &rwlock, rwlock.rh); + + LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock) + { + break; // LOCK_SECTIONS must not be left by a jump + } + + RESOURCE_FORGET (NOBUG_ON, rwlock.rh); + lumiera_rwlock_destroy (&rwlock); +} + TESTS_END