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.
This commit is contained in:
parent
9cdfd02e9b
commit
ed246ab222
4 changed files with 136 additions and 14 deletions
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@ out: inner but not outer mutex locked section
|
|||
END
|
||||
|
||||
|
||||
TEST "recursive mutex section" recursivemutexsection <<END
|
||||
out: mutex locked once
|
||||
out: mutex locked twice
|
||||
END
|
||||
|
||||
|
||||
TEST "rwlock section" rwlocksection <<END
|
||||
out: write locked section 1
|
||||
out: read locked section 2
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ TEST ("nestedmutexsection")
|
|||
}
|
||||
|
||||
lumiera_mutex_destroy (&n, &NOBUG_FLAG(NOBUG_ON));
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
TEST ("chainedmutexsection")
|
||||
|
|
@ -97,7 +97,7 @@ TEST ("chainedmutexsection")
|
|||
{
|
||||
printf ("outer mutex locked section\n");
|
||||
|
||||
LUMIERA_MUTEX_SECTION_CHAIN (NOBUG_ON, &m, &n)
|
||||
LUMIERA_MUTEX_SECTION_CHAIN (NOBUG_ON, &n)
|
||||
{
|
||||
printf ("inner but not outer mutex locked section\n");
|
||||
}
|
||||
|
|
@ -107,6 +107,25 @@ TEST ("chainedmutexsection")
|
|||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
TEST ("recursivemutexsection")
|
||||
{
|
||||
lumiera_mutex m;
|
||||
lumiera_recmutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
printf ("mutex locked once\n");
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
printf ("mutex locked twice\n");
|
||||
}
|
||||
}
|
||||
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
TEST ("rwlocksection")
|
||||
{
|
||||
lumiera_rwlock rwlock;
|
||||
|
|
|
|||
Loading…
Reference in a new issue