New condition and reccondition implementation
Should be working but not thoroughly tested still, docs not complete
This commit is contained in:
parent
4f29f302b2
commit
d91620a60f
6 changed files with 259 additions and 174 deletions
|
|
@ -2,7 +2,7 @@
|
|||
condition.c - condition variable
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
2008, 2009 Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -26,8 +26,6 @@
|
|||
* Condition variables
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed");
|
||||
|
||||
|
||||
LumieraCondition
|
||||
lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag)
|
||||
|
|
@ -35,7 +33,7 @@ lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug
|
|||
if (self)
|
||||
{
|
||||
pthread_cond_init (&self->cond, NULL);
|
||||
pthread_mutex_init (&self->mutex, NULL);
|
||||
pthread_mutex_init (&self->cndmutex, NULL);
|
||||
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
|
||||
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "cond_var", purpose, self, self->rh);
|
||||
}
|
||||
|
|
@ -50,15 +48,21 @@ lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag)
|
|||
{
|
||||
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
|
||||
|
||||
if (pthread_mutex_destroy (&self->mutex))
|
||||
LUMIERA_DIE (MUTEX_DESTROY);
|
||||
if (pthread_mutex_destroy (&self->cndmutex))
|
||||
LUMIERA_DIE (LOCK_DESTROY);
|
||||
|
||||
if (pthread_cond_destroy (&self->cond))
|
||||
LUMIERA_DIE (CONDITION_DESTROY);
|
||||
LUMIERA_DIE (LOCK_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int lumiera_condition_unlock_cb (void* cond)
|
||||
{
|
||||
return pthread_mutex_unlock (&((LumieraCondition)cond)->cndmutex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,58 +23,73 @@
|
|||
#define LUMIERA_CONDITION_H
|
||||
|
||||
#include "lib/error.h"
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/sectionlock.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <nobug.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Condition variables, header
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Condition section.
|
||||
* Locks the condition mutex, one can use LUMIERA_CONDITION_WAIT to wait for signals or
|
||||
* LUMIERA_CONDITION_SIGNAL or LUMIERA_CONDITION_BROADCAST to wake waiting threads
|
||||
* Condition variables must be at the end of locking chains, they can not be used at
|
||||
* intermediate position.
|
||||
* @param nobugflag NoBug flag used to log actions on the condition
|
||||
* @param cnd Condition variable to be locked
|
||||
*/
|
||||
#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \
|
||||
for (lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked) \
|
||||
lumiera_condition_section_ = {(LumieraCondition)1}; \
|
||||
lumiera_condition_section_.condition;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_condition_section_.condition = (cnd); \
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, lumiera_condition_section_.flag = &NOBUG_FLAG(nobugflag)); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_condition_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condition", &lumiera_condition_section_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, lumiera_condition_section_.rh); \
|
||||
if (pthread_mutex_lock (&(cnd)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
|
||||
}); \
|
||||
lumiera_condition_section_.condition; \
|
||||
({ \
|
||||
LUMIERA_CONDITION_UNLOCK \
|
||||
#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \
|
||||
for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
|
||||
lumiera_cond_section_ = { \
|
||||
(void*)1, lumiera_condition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_cond_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_cond_section_.lock = (cnd); \
|
||||
NOBUG_IF_ALPHA(lumiera_cond_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condmutex", &lumiera_cond_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_cond_section_.rh); \
|
||||
if (pthread_mutex_lock (&(cnd)->cndmutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \
|
||||
}); \
|
||||
lumiera_cond_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_CONDITION_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
/**
|
||||
* Explicit mutex unlock for a condition variable
|
||||
* One can early unlock the mutex of a condition variable prior leaving a CONDITION_SECTION.
|
||||
* The CONDITION_WAIT, CONDITION_SIGNAL and CONDITION_BROADCAST macros must not be used after the mutex
|
||||
* got unlocked.
|
||||
* @param nobugflag NoBug flag used to log actions on the condition
|
||||
*/
|
||||
#define LUMIERA_CONDITION_UNLOCK \
|
||||
if (lumiera_condition_section_.condition) \
|
||||
{ \
|
||||
pthread_mutex_unlock (&lumiera_condition_section_.condition->mutex); \
|
||||
lumiera_condition_section_.condition = NULL; \
|
||||
NOBUG_RESOURCE_LEAVE_RAW(lumiera_condition_section_.flag, lumiera_condition_section_.rh); \
|
||||
}
|
||||
#define LUMIERA_CONDITION_SECTION_CHAIN(nobugflag, cnd) \
|
||||
for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
|
||||
NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_cond_section_ = { \
|
||||
(void*)1, lumiera_condition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_cond_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
|
||||
lumiera_cond_section_.lock = cnd; \
|
||||
NOBUG_IF_ALPHA(lumiera_cond_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condmutex", &lumiera_cond_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_cond_section_.rh); \
|
||||
if (pthread_mutex_lock (&(cnd)->cndmutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \
|
||||
LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
|
||||
}); \
|
||||
lumiera_cond_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_CONDITION_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
|
||||
#define LUMIERA_CONDITION_SECTION_UNLOCK \
|
||||
LUMIERA_SECTION_UNLOCK_(&lumiera_cond_section_)
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -82,12 +97,13 @@ LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
|
|||
* Must be used inside a CONDITION_SECTION.
|
||||
* @param expr Conditon which must become true, else the condition variable goes back into sleep
|
||||
*/
|
||||
#define LUMIERA_CONDITION_WAIT(expr) \
|
||||
do { \
|
||||
ENSURE (lumiera_condition_section_.condition, "Condition mutex not locked"); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCE_WAITING); \
|
||||
pthread_cond_wait (&lumiera_condition_section_.condition->cond, &lumiera_condition_section_.condition->mutex); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCE_EXCLUSIVE);\
|
||||
#define LUMIERA_CONDITION_WAIT(expr) \
|
||||
do { \
|
||||
REQUIRE (lumiera_cond_section_.lock, "Condition mutex not locked"); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_cond_section_.flag, NOBUG_RESOURCE_WAITING, lumiera_cond_section_.rh); \
|
||||
pthread_cond_wait (&((LumieraCondition)lumiera_cond_section_.lock)->cond, \
|
||||
&((LumieraCondition)lumiera_cond_section_.lock)->cndmutex); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_cond_section_.flag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_cond_section_.rh); \
|
||||
} while (!(expr))
|
||||
|
||||
|
||||
|
|
@ -96,12 +112,12 @@ LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
|
|||
* Must be used inside a CONDITION_SECTION.
|
||||
* Wakes one thread waiting on the condition variable
|
||||
*/
|
||||
#define LUMIERA_CONDITION_SIGNAL \
|
||||
do { \
|
||||
ENSURE (lumiera_condition_section_.condition, "Condition mutex not locked"); \
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, TRACE(lumiera_condition_section_.flag, "Signaling")); \
|
||||
pthread_cond_signal (&lumiera_condition_section_.condition->cond); \
|
||||
} while (0)
|
||||
#define LUMIERA_CONDITION_SIGNAL \
|
||||
do { \
|
||||
REQUIRE (lumiera_cond_section_.lock, "Condition mutex not locked"); \
|
||||
TRACE(NOBUG_FLAG_RAW(lumiera_cond_section_.flag), "Signal %p", &lumiera_cond_section_); \
|
||||
pthread_cond_signal (&((LumieraCondition)lumiera_cond_section_.lock)->cond); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -109,13 +125,12 @@ do {
|
|||
* Must be used inside a CONDITION_SECTION.
|
||||
* Wakes all threads waiting on the condition variable
|
||||
*/
|
||||
#define LUMIERA_CONDITION_BROADCAST \
|
||||
do { \
|
||||
ENSURE (lumiera_condition_section_.condition, "Condition mutex not locked"); \
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, TRACE(lumiera_condition_section_.flag, "Broadcasting")); \
|
||||
pthread_cond_broadcast (&lumiera_condition_section_.condition->cond); \
|
||||
} while (0)
|
||||
|
||||
#define LUMIERA_CONDITION_BROADCAST \
|
||||
do { \
|
||||
REQUIRE (lumiera_cond_section_.lock, "Condition mutex not locked"); \
|
||||
TRACE(NOBUG_FLAG_RAW(lumiera_cond_section_.flag), "Broadcast %p", &lumiera_cond_section_); \
|
||||
pthread_cond_broadcast (&((LumieraCondition)lumiera_cond_section_.lock)->cond); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -125,7 +140,7 @@ do {
|
|||
struct lumiera_condition_struct
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_t cndmutex;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_condition_struct lumiera_condition;
|
||||
|
|
@ -149,26 +164,8 @@ lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug
|
|||
LumieraCondition
|
||||
lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag);
|
||||
|
||||
|
||||
/**
|
||||
* conditionacquirer used to manage the state of a condition variable.
|
||||
*/
|
||||
struct lumiera_conditionacquirer_struct
|
||||
{
|
||||
LumieraCondition condition;
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, struct nobug_flag* flag);
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_conditionacquirer_struct lumiera_conditionacquirer;
|
||||
typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer;
|
||||
|
||||
|
||||
/* helper function for nobug */
|
||||
static inline void
|
||||
lumiera_conditionacquirer_ensureunlocked (LumieraConditionacquirer self)
|
||||
{
|
||||
ENSURE (!self->condition, "forgot to unlock condition variable");
|
||||
}
|
||||
int
|
||||
lumiera_condition_unlock_cb (void* cond);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
reccondition.c - condition variable, w/ recursive mutex
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
2008, 2009, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -19,7 +19,6 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/condition.h"
|
||||
#include "lib/reccondition.h"
|
||||
|
||||
/**
|
||||
|
|
@ -48,7 +47,7 @@ lumiera_reccondition_init (LumieraReccondition self, const char* purpose, struct
|
|||
pthread_once (&recursive_mutexattr_once, recursive_mutexattr_init);
|
||||
|
||||
pthread_cond_init (&self->cond, NULL);
|
||||
pthread_mutex_init (&self->mutex, &recursive_mutexattr);
|
||||
pthread_mutex_init (&self->reccndmutex, &recursive_mutexattr);
|
||||
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
|
||||
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "reccond_var", purpose, self, self->rh);
|
||||
}
|
||||
|
|
@ -63,15 +62,19 @@ lumiera_reccondition_destroy (LumieraReccondition self, struct nobug_flag* flag)
|
|||
{
|
||||
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
|
||||
|
||||
if (pthread_mutex_destroy (&self->mutex))
|
||||
if (pthread_mutex_destroy (&self->reccndmutex))
|
||||
LUMIERA_DIE (LOCK_DESTROY);
|
||||
|
||||
if (pthread_cond_destroy (&self->cond))
|
||||
LUMIERA_DIE (CONDITION_DESTROY);
|
||||
LUMIERA_DIE (LOCK_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int lumiera_reccondition_unlock_cb (void* cond)
|
||||
{
|
||||
return pthread_mutex_unlock (&((LumieraReccondition)cond)->reccndmutex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
reccondition.h - condition variables, w/ recursive mutex
|
||||
reccondition.h - recursive locked condition variables
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
2008, 2009, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -23,106 +23,122 @@
|
|||
#define LUMIERA_RECCONDITION_H
|
||||
|
||||
#include "lib/error.h"
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/sectionlock.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <nobug.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Reccondition variables. Same as Conditon variables but using a recursive mutex for locking.
|
||||
* Condition variables, header
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Reccondition section.
|
||||
* Locks the reccondition mutex, one can then use LUMIERA_RECCONDITION_WAIT to wait for signals or
|
||||
* Recursive Condition section.
|
||||
* Locks the condition mutex, one can use LUMIERA_RECCONDITION_WAIT to wait for signals or
|
||||
* LUMIERA_RECCONDITION_SIGNAL or LUMIERA_RECCONDITION_BROADCAST to wake waiting threads
|
||||
* @param nobugflag NoBug flag used to log actions on the reccondition
|
||||
* @param rcnd Reccondition variable to be locked
|
||||
* @param nobugflag NoBug flag used to log actions on the condition
|
||||
* @param cnd Condition variable to be locked
|
||||
*/
|
||||
#define LUMIERA_RECCONDITION_SECTION(nobugflag, rcnd) \
|
||||
for (lumiera_recconditionacquirer NOBUG_CLEANUP(lumiera_recconditionacquirer_ensureunlocked) \
|
||||
lumiera_reccondition_section_ = {(LumieraReccondition)1}; \
|
||||
lumiera_reccondition_section_.reccondition;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_reccondition_section_.reccondition = (rcnd); \
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, lumiera_reccondition_section_.flag = &NOBUG_FLAG(nobugflag)); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_reccondition_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (rcnd)->rh, "acquire reccondition", &lumiera_reccondition_section_, \
|
||||
NOBUG_RESOURCE_RECURSIVE, lumiera_reccondition_section_.rh); \
|
||||
if (pthread_mutex_lock (&(rcnd)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
|
||||
}); \
|
||||
lumiera_reccondition_section_.reccondition; \
|
||||
({ \
|
||||
LUMIERA_RECCONDITION_UNLOCK(nobugflag) \
|
||||
#define LUMIERA_RECCONDITION_SECTION(nobugflag, cnd) \
|
||||
for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
|
||||
lumiera_reccond_section_ = { \
|
||||
(void*)1, lumiera_condition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_reccond_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_reccond_section_.lock = (cnd); \
|
||||
NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire reccondmutex", &lumiera_reccond_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_reccond_section_.rh); \
|
||||
if (pthread_mutex_lock (&(cnd)->reccndmutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \
|
||||
}); \
|
||||
lumiera_reccond_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_RECCONDITION_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
/**
|
||||
* Explicit mutex unlock for a reccondition variable
|
||||
* One can early unlock the mutex of a condition variable prior leaving a RECCONDITION_SECTION.
|
||||
* The RECCONDITION_WAIT, RECCONDITION_SIGNAL and RECCONDITION_BROADCAST macros must not be used after the mutex
|
||||
* got unlocked.
|
||||
* @param nobugflag NoBug flag used to log actions on the reccondition
|
||||
*/
|
||||
#define LUMIERA_RECCONDITION_UNLOCK \
|
||||
if (lumiera_reccondition_section_.reccondition) \
|
||||
{ \
|
||||
pthread_mutex_unlock (&lumiera_reccondition_section_.reccondition->mutex); \
|
||||
lumiera_reccondition_section_.reccondition = NULL; \
|
||||
RESOURCE_LEAVE(nobugflag, lumiera_reccondition_section_.rh); \
|
||||
}
|
||||
|
||||
#define LUMIERA_RECCONDITION_SECTION_CHAIN(nobugflag, cnd) \
|
||||
for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
|
||||
NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_reccond_section_ = { \
|
||||
(void*)1, lumiera_reccondition_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_reccond_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
|
||||
lumiera_reccond_section_.lock = (cnd); \
|
||||
NOBUG_IF_ALPHA(lumiera_reccond_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire reccondmutex", &lumiera_reccond_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_reccond_section_.rh); \
|
||||
if (pthread_mutex_lock (&(cnd)->reccndmutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \
|
||||
LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_) \
|
||||
}); \
|
||||
lumiera_reccond_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_RECCONDITION_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
#define LUMIERA_RECCONDITION_SECTION_UNLOCK \
|
||||
LUMIERA_SECTION_UNLOCK_(&lumiera_reccond_section_)
|
||||
|
||||
|
||||
/**
|
||||
* Wait for a reccondition.
|
||||
* Wait for a condition.
|
||||
* Must be used inside a RECCONDITION_SECTION.
|
||||
* @param expr Recconditon which must become true, else the reccondition variable goes back into sleep
|
||||
* @param expr Conditon which must become true, else the condition variable goes back into sleep
|
||||
*/
|
||||
#define LUMIERA_RECCONDITION_WAIT(expr) \
|
||||
do { \
|
||||
ENSURE (lumiera_reccondition_section_.reccondition, "Reccondition mutex not locked"); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_reccondition_section_.flag, lumiera_reccondition_section_.rh, NOBUG_RESOURCE_WAITING); \
|
||||
pthread_cond_wait (&lumiera_reccondition_section_.reccondition->cond, &lumiera_reccondition_section_.reccondition->mutex); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_reccondition_section_.flag, lumiera_reccondition_section_.rh, NOBUG_RESOURCE_RECURSIVE); \
|
||||
#define LUMIERA_RECCONDITION_WAIT(expr) \
|
||||
do { \
|
||||
REQUIRE (lumiera_reccond_section_.lock, "Condition recmutex not locked"); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_reccond_section_.flag, NOBUG_RESOURCE_WAITING, lumiera_reccond_section_.rh); \
|
||||
pthread_cond_wait (&((LumieraCondition)lumiera_reccond_section_.lock)->cond, \
|
||||
&((LumieraCondition)lumiera_reccond_section_.lock)->cndmutex); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_reccond_section_.flag, NOBUG_RESOURCE_RECURSIVE, lumiera_reccond_section_.rh); \
|
||||
} while (!(expr))
|
||||
|
||||
|
||||
/**
|
||||
* Signal a reccondition variable
|
||||
* Signal a condition variable
|
||||
* Must be used inside a RECCONDITION_SECTION.
|
||||
* Wakes one thread waiting on the condition variable
|
||||
*/
|
||||
#define LUMIERA_RECCONDITION_SIGNAL \
|
||||
do { \
|
||||
ENSURE (lumiera_reccondition_section_.reccondition, "Reccondition mutex not locked"); \
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, TRACE(lumiera_reccondition_section_.flag, "Signaling")); \
|
||||
pthread_cond_signal (&lumiera_reccondition_section_.reccondition->cond); \
|
||||
} while (0)
|
||||
#define LUMIERA_RECCONDITION_SIGNAL \
|
||||
do { \
|
||||
REQUIRE (lumiera_reccond_section_.lock, "Condition recmutex not locked"); \
|
||||
TRACE(NOBUG_FLAG_RAW(lumiera_reccond_section_.flag), "Signal %p", &lumiera_reccond_section_); \
|
||||
pthread_cond_signal (&((LumieraCondition)lumiera_reccond_section_.lock)->cond); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* Broadcast a reccondition variable
|
||||
* Broadcast a condition variable
|
||||
* Must be used inside a RECCONDITION_SECTION.
|
||||
* Wakes all threads waiting on the reccondition variable
|
||||
* Wakes all threads waiting on the condition variable
|
||||
*/
|
||||
#define LUMIERA_RECCONDITION_BROADCAST \
|
||||
do { \
|
||||
ENSURE (lumiera_reccondition_section_.reccondition, "Reccondition mutex not locked"); \
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, TRACE(lumiera_reccondition_section_.flag, "Broadcasting"));\
|
||||
pthread_cond_broadcast (&lumiera_reccondition_section_.reccondition->cond); \
|
||||
} while (0)
|
||||
|
||||
#define LUMIERA_RECCONDITION_BROADCAST \
|
||||
do { \
|
||||
REQUIRE (lumiera_reccond_section_.lock, "Condition recmutex not locked"); \
|
||||
TRACE(NOBUG_FLAG_RAW(lumiera_reccond_section_.flag), "Broadcast %p", &lumiera_reccond_section_); \
|
||||
pthread_cond_broadcast (&((LumieraCondition)lumiera_reccond_section_.lock)->cond); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* Reccondition variables.
|
||||
* Condition variables. Recursive mutex variant.
|
||||
*
|
||||
*/
|
||||
struct lumiera_reccondition_struct
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_t reccndmutex;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_reccondition_struct lumiera_reccondition;
|
||||
|
|
@ -130,8 +146,8 @@ typedef lumiera_reccondition* LumieraReccondition;
|
|||
|
||||
|
||||
/**
|
||||
* Initialize a reccondition variable
|
||||
* @param self is a pointer to the reccondition variable to be initialized
|
||||
* Initialize a condition variable
|
||||
* @param self is a pointer to the condition variable to be initialized
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraReccondition
|
||||
|
|
@ -139,34 +155,16 @@ lumiera_reccondition_init (LumieraReccondition self, const char* purpose, struct
|
|||
|
||||
|
||||
/**
|
||||
* Destroy a reccondition variable
|
||||
* @param self is a pointer to the reccondition variable to be destroyed
|
||||
* Destroy a condition variable
|
||||
* @param self is a pointer to the condition variable to be destroyed
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraReccondition
|
||||
lumiera_reccondition_destroy (LumieraReccondition self, struct nobug_flag* flag);
|
||||
|
||||
|
||||
/**
|
||||
* recconditionacquirer used to manage the state of a reccondition variable.
|
||||
*/
|
||||
struct lumiera_recconditionacquirer_struct
|
||||
{
|
||||
LumieraReccondition reccondition;
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, struct nobug_flag* flag);
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_recconditionacquirer_struct lumiera_recconditionacquirer;
|
||||
typedef struct lumiera_recconditionacquirer_struct* LumieraRecconditionacquirer;
|
||||
|
||||
|
||||
/* helper function for nobug */
|
||||
static inline void
|
||||
lumiera_recconditionacquirer_ensureunlocked (LumieraRecconditionacquirer self)
|
||||
{
|
||||
ENSURE (!self->reccondition, "forgot to unlock reccondition variable");
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_reccondition_unlock_cb (void* cond);
|
||||
|
||||
#endif
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -70,3 +70,19 @@ PLANNED "condition broadcasting" <<END
|
|||
END
|
||||
|
||||
|
||||
TEST "reccondition not unlocked asserts" recconditionforgotunlock <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
TEST "reccondition section" recconditionsection <<END
|
||||
out: reccondition locked section 1
|
||||
out: reccondition locked section 2
|
||||
END
|
||||
|
||||
PLANNED "reccondition signaling" <<END
|
||||
END
|
||||
|
||||
PLANNED "reccondition broadcasting" <<END
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,22 @@ TEST ("rwdeadlockrw")
|
|||
}
|
||||
|
||||
|
||||
TEST ("conditionops (compiletest only)")
|
||||
{
|
||||
lumiera_condition cond;
|
||||
lumiera_condition_init (&cond, "conditionsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
|
||||
{
|
||||
LUMIERA_CONDITION_WAIT(1);
|
||||
LUMIERA_CONDITION_SIGNAL;
|
||||
LUMIERA_CONDITION_BROADCAST;
|
||||
}
|
||||
|
||||
lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("conditionsection")
|
||||
{
|
||||
lumiera_condition cond;
|
||||
|
|
@ -251,4 +267,55 @@ TEST ("conditionforgotunlock")
|
|||
lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("recconditionops (compiletest only)")
|
||||
{
|
||||
lumiera_reccondition reccond;
|
||||
lumiera_reccondition_init (&reccond, "recconditionsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_RECCONDITION_SECTION (NOBUG_ON, &reccond)
|
||||
{
|
||||
LUMIERA_RECCONDITION_WAIT(1);
|
||||
LUMIERA_RECCONDITION_SIGNAL;
|
||||
LUMIERA_RECCONDITION_BROADCAST;
|
||||
}
|
||||
|
||||
lumiera_reccondition_destroy (&reccond, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("recconditionsection")
|
||||
{
|
||||
lumiera_reccondition reccond;
|
||||
lumiera_reccondition_init (&reccond, "recconditionsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_RECCONDITION_SECTION (NOBUG_ON, &reccond)
|
||||
{
|
||||
printf ("reccondition locked section 1\n");
|
||||
}
|
||||
|
||||
LUMIERA_RECCONDITION_SECTION (NOBUG_ON, &reccond)
|
||||
{
|
||||
printf ("reccondition locked section 2\n");
|
||||
}
|
||||
|
||||
lumiera_reccondition_destroy (&reccond, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("recconditionforgotunlock")
|
||||
{
|
||||
lumiera_reccondition reccond;
|
||||
lumiera_reccondition_init (&reccond, "recconditionforgotunlock", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_RECCONDITION_SECTION (NOBUG_ON, &reccond)
|
||||
{
|
||||
break; // RECCONDITION_SECTIONS must not be left by a jump
|
||||
}
|
||||
|
||||
lumiera_reccondition_destroy (&reccond, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TESTS_END
|
||||
|
|
|
|||
Loading…
Reference in a new issue