Merge commit '99b5f8'
* commit '99b5f8': adapt the Sync template Add reccondition to threads, make its functionality complete fix some includes for new mutex/recmutex headers weed out reccondition bugs/typos New condition and reccondition implementation split mutex.h again into mutex.h and recmutex.h typo fix in mutex.h rename casing of RecMutex to Recmutex to be consistent store lumiera_rwlock in sectionlock store a lumiera_mutex in a sectionlock, looks cleaner add check to chained locking validating that the parent lock is held rwlock makeover, locksections etc... error code changed to LOCK_DESTROY fix: forgotten backcasts in mutex.h new mutex and recmutex implementation (breaks sync.hpp for now)
This commit is contained in:
commit
062dbfe82f
24 changed files with 1032 additions and 470 deletions
|
|
@ -19,7 +19,7 @@ liblumierabackend_la_srcdir = $(top_srcdir)/src/backend
|
|||
lib_LTLIBRARIES += liblumierabackend.la
|
||||
|
||||
liblumierabackend_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
liblumierabackend_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wextra -Wall -Werror
|
||||
liblumierabackend_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wextra -Wall -Werror
|
||||
liblumierabackend_la_LIBADD = liblumiera.la
|
||||
|
||||
liblumierabackend_la_SOURCES = \
|
||||
|
|
@ -29,10 +29,10 @@ liblumierabackend_la_SOURCES = \
|
|||
$(liblumierabackend_la_srcdir)/file.c \
|
||||
$(liblumierabackend_la_srcdir)/filehandle.c \
|
||||
$(liblumierabackend_la_srcdir)/filedescriptor.c \
|
||||
$(liblumierabackend_la_srcdir)/filehandlecache.c \
|
||||
$(liblumierabackend_la_srcdir)/mmap.c \
|
||||
$(liblumierabackend_la_srcdir)/mmapings.c \
|
||||
$(liblumierabackend_la_srcdir)/mmapcache.c \
|
||||
$(liblumierabackend_la_srcdir)/filehandlecache.c \
|
||||
$(liblumierabackend_la_srcdir)/enginefacade.cpp \
|
||||
$(liblumierabackend_la_srcdir)/scriptrunnerfacade.cpp \
|
||||
$(liblumierabackend_la_srcdir)/netnodefacade.cpp
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
//TODO: Support library includes//
|
||||
|
||||
#include "include/logging.h"
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "threads.h"
|
||||
|
|
@ -41,8 +42,29 @@
|
|||
|
||||
//code goes here//
|
||||
|
||||
/* really dumb mutex, to make the mockup little less brittle */
|
||||
static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
struct lumiera_thread_mockup
|
||||
{
|
||||
void (*fn)(void*);
|
||||
void* arg;
|
||||
LumieraReccondition finished;
|
||||
};
|
||||
|
||||
|
||||
static void* pthread_runner (void* thread)
|
||||
{
|
||||
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
|
||||
|
||||
struct lumiera_thread_mockup* starter = (struct lumiera_thread_mockup*) thread;
|
||||
|
||||
starter->fn (starter->arg);
|
||||
|
||||
LUMIERA_RECCONDITION_SECTION(cond_sync, starter->finished)
|
||||
LUMIERA_RECCONDITION_BROADCAST;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static pthread_once_t attr_once = PTHREAD_ONCE_INIT;
|
||||
static pthread_attr_t attrs;
|
||||
|
|
@ -51,42 +73,22 @@ static void thread_attr_init (void)
|
|||
{
|
||||
pthread_attr_init (&attrs);
|
||||
pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_DETACHED);
|
||||
//cancel ...
|
||||
}
|
||||
|
||||
struct lumiera_thread_mockup
|
||||
{
|
||||
void (*fn)(void*);
|
||||
void* arg;
|
||||
};
|
||||
|
||||
|
||||
static void* pthread_runner (void* thread)
|
||||
{
|
||||
struct lumiera_thread_mockup* starter = (struct lumiera_thread_mockup*) thread;
|
||||
(void) starter;
|
||||
pthread_mutex_lock (&threads_mutex);
|
||||
pthread_mutex_unlock (&threads_mutex);
|
||||
starter->fn (starter->arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LumieraThread
|
||||
lumiera_thread_run (enum lumiera_thread_class kind,
|
||||
void (*start_routine)(void *),
|
||||
void * arg,
|
||||
LumieraCondition finished,
|
||||
LumieraReccondition finished,
|
||||
const char* purpose,
|
||||
struct nobug_flag* flag)
|
||||
{
|
||||
(void) kind;
|
||||
(void) finished;
|
||||
(void) purpose;
|
||||
(void) flag;
|
||||
|
||||
REQUIRE (!finished, "Condition variable for finish notification not yet implemented");
|
||||
|
||||
if (attr_once == PTHREAD_ONCE_INIT)
|
||||
pthread_once (&attr_once, thread_attr_init);
|
||||
|
||||
|
|
@ -94,14 +96,11 @@ lumiera_thread_run (enum lumiera_thread_class kind,
|
|||
|
||||
thread.fn = start_routine;
|
||||
thread.arg = arg;
|
||||
|
||||
pthread_mutex_lock (&threads_mutex);
|
||||
thread.finished = finished;
|
||||
|
||||
pthread_t dummy;
|
||||
int error = pthread_create (&dummy, &attrs, pthread_runner, &thread);
|
||||
|
||||
pthread_mutex_unlock (&threads_mutex);
|
||||
|
||||
if (error) return 0; /////TODO temporary addition by Ichthyo; probably we'll set lumiera_error?
|
||||
return (LumieraThread) 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#define LUMIERA_THREADS_H
|
||||
|
||||
//TODO: Support library includes//
|
||||
#include "lib/condition.h"
|
||||
#include "lib/reccondition.h"
|
||||
|
||||
|
||||
//TODO: Forward declarations//
|
||||
|
|
@ -96,7 +96,7 @@ LumieraThread
|
|||
lumiera_thread_run (enum lumiera_thread_class kind,
|
||||
void (*start_routine)(void *),
|
||||
void * arg,
|
||||
LumieraCondition finished,
|
||||
LumieraReccondition finished,
|
||||
const char* purpose,
|
||||
struct nobug_flag* flag);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "include/logging.h"
|
||||
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/recmutex.h"
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
#include "common/plugin.h"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
*/
|
||||
|
||||
#include "include/logging.h"
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/error.h"
|
||||
#include "lib/psplay.h"
|
||||
#include "lib/safeclib.h"
|
||||
|
|
@ -47,7 +46,7 @@
|
|||
|
||||
PSplay lumiera_interfaceregistry;
|
||||
PSplay lumiera_pluginregistry;
|
||||
lumiera_mutex lumiera_interface_mutex;
|
||||
lumiera_recmutex lumiera_interface_mutex;
|
||||
|
||||
static int
|
||||
lumiera_interface_cmp_fn (const void* keya, const void* keyb);
|
||||
|
|
@ -126,7 +125,7 @@ lumiera_interfaceregistry_destroy (void)
|
|||
psplay_delete (lumiera_pluginregistry);
|
||||
lumiera_pluginregistry = NULL;
|
||||
|
||||
lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(mutex_dbg));
|
||||
lumiera_recmutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(mutex_dbg));
|
||||
|
||||
REQUIRE (!psplay_nelements (lumiera_interfaceregistry), "some interfaces still registered at shutdown");
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#define LUMIERA_INTERFACEREGISTRY_H
|
||||
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/recmutex.h"
|
||||
#include "lib/psplay.h"
|
||||
|
||||
#include "common/interface.h"
|
||||
|
|
@ -42,7 +43,7 @@
|
|||
//NOBUG_DECLARE_FLAG (interface);
|
||||
|
||||
extern PSplay lumiera_interfaceregistry;
|
||||
extern lumiera_mutex lumiera_interface_mutex;
|
||||
extern lumiera_recmutex lumiera_interface_mutex;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -75,8 +76,6 @@ struct lumiera_interfacenode_struct
|
|||
LumieraInterfacenode* deps;
|
||||
};
|
||||
|
||||
extern lumiera_mutex lumiera_interface_mutex;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the interface registry
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "include/logging.h"
|
||||
#include "lib/safeclib.h"
|
||||
#include "lib/psplay.h"
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/recmutex.h"
|
||||
#include "lib/error.h"
|
||||
|
||||
#include "common/interfaceregistry.h"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Copyright (C) Lumiera.org
|
||||
# 2007, Christian Thaeter <ct@pipapo.org>
|
||||
# 2007, 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
|
||||
|
|
@ -25,6 +25,7 @@ liblumiera_la_SOURCES = \
|
|||
$(liblumiera_la_srcdir)/error.c \
|
||||
$(liblumiera_la_srcdir)/exception.cpp \
|
||||
$(liblumiera_la_srcdir)/mutex.c \
|
||||
$(liblumiera_la_srcdir)/recmutex.c \
|
||||
$(liblumiera_la_srcdir)/rwlock.c \
|
||||
$(liblumiera_la_srcdir)/condition.c \
|
||||
$(liblumiera_la_srcdir)/reccondition.c \
|
||||
|
|
@ -51,6 +52,7 @@ noinst_HEADERS += \
|
|||
$(liblumiera_la_srcdir)/error.h \
|
||||
$(liblumiera_la_srcdir)/error.hpp \
|
||||
$(liblumiera_la_srcdir)/mutex.h \
|
||||
$(liblumiera_la_srcdir)/recmutex.h \
|
||||
$(liblumiera_la_srcdir)/rwlock.h \
|
||||
$(liblumiera_la_srcdir)/condition.h \
|
||||
$(liblumiera_la_srcdir)/reccondition.h \
|
||||
|
|
|
|||
|
|
@ -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 @@
|
|||
mutex.c - 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
|
||||
|
|
@ -26,9 +26,9 @@
|
|||
* Mutual exclusion locking.
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DEFINE (MUTEX_LOCK, "Mutex locking failed");
|
||||
LUMIERA_ERROR_DEFINE (MUTEX_UNLOCK, "Mutex unlocking failed");
|
||||
LUMIERA_ERROR_DEFINE (MUTEX_DESTROY, "Mutex destroy failed");
|
||||
LUMIERA_ERROR_DEFINE (LOCK_ACQUIRE, "locking failed");
|
||||
LUMIERA_ERROR_DEFINE (LOCK_RELEASE, "unlocking failed");
|
||||
LUMIERA_ERROR_DEFINE (LOCK_DESTROY, "lock destroy failed");
|
||||
|
||||
|
||||
LumieraMutex
|
||||
|
|
@ -44,32 +44,6 @@ 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)
|
||||
{
|
||||
if (recursive_mutexattr_once == PTHREAD_ONCE_INIT)
|
||||
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)
|
||||
{
|
||||
|
|
@ -77,11 +51,16 @@ lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag)
|
|||
{
|
||||
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
|
||||
if (pthread_mutex_destroy (&self->mutex))
|
||||
LUMIERA_DIE (MUTEX_DESTROY);
|
||||
LUMIERA_DIE (LOCK_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
int lumiera_mutex_unlock_cb (void* mutex)
|
||||
{
|
||||
return pthread_mutex_unlock (&((LumieraMutex)mutex)->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
|
|
|
|||
184
src/lib/mutex.h
184
src/lib/mutex.h
|
|
@ -2,7 +2,7 @@
|
|||
mutex.h - mutal exclusion locking
|
||||
|
||||
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,6 +23,7 @@
|
|||
#define LUMIERA_MUTEX_H
|
||||
|
||||
#include "lib/error.h"
|
||||
#include "lib/sectionlock.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <nobug.h>
|
||||
|
|
@ -32,35 +33,31 @@
|
|||
* Mutual exclusion locking, header.
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
|
||||
|
||||
/**
|
||||
* Mutual exclusive section.
|
||||
*/
|
||||
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
|
||||
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ \
|
||||
= {(LumieraMutex)1 NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_mutex_section_.mutex;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_mutex_section_.mutex = (mtx); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, 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); \
|
||||
} \
|
||||
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
|
||||
for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
|
||||
lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_lock_section_.lock = (mtx); \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_lock_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \
|
||||
if (pthread_mutex_lock (&(mtx)->mutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_MUTEX_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
/**
|
||||
* Mutual exclusion chainbuilder section.
|
||||
* Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(b){run();}}
|
||||
|
|
@ -68,97 +65,32 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
|
|||
* 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, mtx) \
|
||||
for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \
|
||||
NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1 \
|
||||
NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_mutex_section_.mutex;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_mutex_section_.mutex = (mtx); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, 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); \
|
||||
} \
|
||||
|
||||
#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \
|
||||
for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
|
||||
NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
|
||||
lumiera_lock_section_.lock = mtx; \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_lock_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \
|
||||
if (pthread_mutex_lock (&(mtx)->mutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \
|
||||
LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_MUTEX_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
/**
|
||||
* Recursive Mutual exclusive section.
|
||||
*/
|
||||
#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \
|
||||
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ \
|
||||
= {(LumieraMutex)1 NOBUG_ALPHA_COMMA_NULL}; \
|
||||
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 \
|
||||
NOBUG_ALPHA_COMMA_NULL}; \
|
||||
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); \
|
||||
} \
|
||||
}))
|
||||
#define LUMIERA_MUTEX_SECTION_UNLOCK \
|
||||
LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_)
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -183,16 +115,6 @@ typedef lumiera_mutex* LumieraMutex;
|
|||
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
|
||||
* @param self is a pointer to the mutex to be destroyed
|
||||
|
|
@ -203,22 +125,12 @@ lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag);
|
|||
|
||||
|
||||
/**
|
||||
* mutexacquirer used to manage the state of a mutex.
|
||||
* Callback for unlocking mutexes.
|
||||
* @internal
|
||||
*/
|
||||
struct lumiera_mutexacquirer_struct
|
||||
{
|
||||
LumieraMutex mutex;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_mutexacquirer_struct lumiera_mutexacquirer;
|
||||
typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer;
|
||||
int
|
||||
lumiera_mutex_unlock_cb (void* mutex);
|
||||
|
||||
/* helper function for nobug */
|
||||
static inline void
|
||||
lumiera_mutexacquirer_ensureunlocked (LumieraMutexacquirer self)
|
||||
{
|
||||
ENSURE (!self->mutex, "forgot to unlock mutex");
|
||||
}
|
||||
|
||||
#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))
|
||||
LUMIERA_DIE (MUTEX_DESTROY);
|
||||
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_reccondition_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 (&((LumieraReccondition)lumiera_reccond_section_.lock)->cond, \
|
||||
&((LumieraReccondition)lumiera_reccond_section_.lock)->reccndmutex); \
|
||||
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 (&((LumieraReccondition)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 (&((LumieraReccondition)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
|
||||
/*
|
||||
|
|
|
|||
74
src/lib/recmutex.c
Normal file
74
src/lib/recmutex.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
recmutex.c - recursive mutex
|
||||
|
||||
Copyright (C) Lumiera.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
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/recmutex.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Recursive Mutexes.
|
||||
*/
|
||||
|
||||
|
||||
static pthread_once_t recmutexattr_once = PTHREAD_ONCE_INIT;
|
||||
static pthread_mutexattr_t recmutexattr;
|
||||
|
||||
static void recmutexattr_init()
|
||||
{
|
||||
pthread_mutexattr_init (&recmutexattr);
|
||||
pthread_mutexattr_settype (&recmutexattr, PTHREAD_MUTEX_RECURSIVE);
|
||||
}
|
||||
|
||||
|
||||
LumieraRecmutex
|
||||
lumiera_recmutex_init (LumieraRecmutex self, const char* purpose, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
if (recmutexattr_once == PTHREAD_ONCE_INIT)
|
||||
pthread_once (&recmutexattr_once, recmutexattr_init);
|
||||
|
||||
pthread_mutex_init (&self->recmutex, &recmutexattr);
|
||||
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
|
||||
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "recmutex", purpose, self, self->rh);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
LumieraRecmutex
|
||||
lumiera_recmutex_destroy (LumieraRecmutex self, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
|
||||
if (pthread_mutex_destroy (&self->recmutex))
|
||||
LUMIERA_DIE (LOCK_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
132
src/lib/recmutex.h
Normal file
132
src/lib/recmutex.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
recmutex.h - recursive mutal exclusion locking
|
||||
|
||||
Copyright (C) Lumiera.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
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_RECMUTEX_H
|
||||
#define LUMIERA_RECMUTEX_H
|
||||
|
||||
#include "lib/error.h"
|
||||
#include "lib/sectionlock.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <nobug.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Mutual exclusion locking, header.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Recursive Mutual exclusive section.
|
||||
*/
|
||||
#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \
|
||||
for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
|
||||
lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_lock_section_.lock = (mtx); \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_lock_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \
|
||||
if (pthread_mutex_lock (&(mtx)->recmutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_lock_section_.rh); \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_MUTEX_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
#define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \
|
||||
for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
|
||||
NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_mutex_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
|
||||
lumiera_lock_section_.lock = (mtx); \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_lock_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \
|
||||
if (pthread_mutex_lock (&(mtx)->recmutex)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_RECURSIVE, lumiera_lock_section_.rh); \
|
||||
LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_) \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_MUTEX_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
#define LUMIERA_RECMUTEX_SECTION_UNLOCK \
|
||||
LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Mutex.
|
||||
*
|
||||
*/
|
||||
struct lumiera_recmutex_struct
|
||||
{
|
||||
pthread_mutex_t recmutex;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_recmutex_struct lumiera_recmutex;
|
||||
typedef lumiera_recmutex* LumieraRecmutex;
|
||||
|
||||
/**
|
||||
* Initialize a recursive 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
|
||||
*/
|
||||
LumieraRecmutex
|
||||
lumiera_recmutex_init (LumieraRecmutex self, const char* purpose, struct nobug_flag* flag);
|
||||
|
||||
/**
|
||||
* Destroy a recursive mutex variable
|
||||
* @param self is a pointer to the mutex to be destroyed
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraRecmutex
|
||||
lumiera_recmutex_destroy (LumieraRecmutex self, struct nobug_flag* flag);
|
||||
|
||||
/**
|
||||
* Callback for unlocking mutexes.
|
||||
* @internal
|
||||
*/
|
||||
int
|
||||
lumiera_mutex_unlock_cb (void* mutex);
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -60,6 +60,12 @@ lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag)
|
|||
return self;
|
||||
}
|
||||
|
||||
|
||||
int lumiera_rwlock_unlock_cb (void* rwlock)
|
||||
{
|
||||
return pthread_rwlock_unlock (&((LumieraRWLock)rwlock)->rwlock);
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
|
|
|
|||
151
src/lib/rwlock.h
151
src/lib/rwlock.h
|
|
@ -45,53 +45,106 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK);
|
|||
/**
|
||||
* 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); \
|
||||
} \
|
||||
#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \
|
||||
for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
|
||||
lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_lock_section_.lock = (rwlck); \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire readlock", \
|
||||
&lumiera_lock_section_, NOBUG_RESOURCE_WAITING, \
|
||||
lumiera_lock_section_.rh); \
|
||||
if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
TODO ("implement NOBUG_RESOURCE_SHARED"); \
|
||||
/*RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); */ \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_RWLOCK_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
#define LUMIERA_RDLOCK_SECTION_CHAIN(nobugflag, rwlck) \
|
||||
for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
|
||||
NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
|
||||
lumiera_lock_section_.lock = (rwlck); \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire readlock", &lumiera_lock_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \
|
||||
if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
/*RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_SHARED, lumiera_lock_section_.rh); */ \
|
||||
LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_MUTEX_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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); \
|
||||
} \
|
||||
#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \
|
||||
for (lumiera_sectionlock NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) \
|
||||
lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_lock_section_.lock = (rwlck); \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire writelock", \
|
||||
&lumiera_lock_section_, NOBUG_RESOURCE_WAITING, \
|
||||
lumiera_lock_section_.rh); \
|
||||
if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_RWLOCK_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
#define LUMIERA_WRLOCK_SECTION_CHAIN(nobugflag, rwlck) \
|
||||
for (lumiera_sectionlock *lumiera_lock_section_old_ = &lumiera_lock_section_, \
|
||||
NOBUG_CLEANUP(lumiera_sectionlock_ensureunlocked) lumiera_lock_section_ = { \
|
||||
(void*)1, lumiera_rwlock_unlock_cb NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA_NULL}; \
|
||||
lumiera_lock_section_.lock;) \
|
||||
for ( \
|
||||
({ \
|
||||
REQUIRE (lumiera_lock_section_old_->lock, "section prematurely unlocked"); \
|
||||
lumiera_lock_section_.lock = (rwlck); \
|
||||
NOBUG_IF_ALPHA(lumiera_lock_section_.flag = &NOBUG_FLAG(nobugflag);) \
|
||||
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire writelock", &lumiera_lock_section_, \
|
||||
NOBUG_RESOURCE_WAITING, lumiera_lock_section_.rh); \
|
||||
if (pthread_rwlock_wrlock (&(twlck)->rwlock)) \
|
||||
LUMIERA_DIE (LOCK_ACQUIRE); \
|
||||
RESOURCE_STATE (nobugflag, NOBUG_RESOURCE_EXCLUSIVE, lumiera_lock_section_.rh); \
|
||||
LUMIERA_SECTION_UNLOCK_(lumiera_lock_section_old_); \
|
||||
}); \
|
||||
lumiera_lock_section_.lock; \
|
||||
({ \
|
||||
LUMIERA_MUTEX_SECTION_UNLOCK; \
|
||||
}))
|
||||
|
||||
|
||||
#define LUMIERA_RWLOCK_SECTION_UNLOCK \
|
||||
LUMIERA_SECTION_UNLOCK_(&lumiera_lock_section_)
|
||||
|
||||
|
||||
/**
|
||||
* RWLock.
|
||||
*
|
||||
|
|
@ -121,26 +174,8 @@ LumieraRWLock
|
|||
lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* rwlockacquirer used to manage the state of a rwlock variable.
|
||||
*/
|
||||
struct lumiera_rwlockacquirer_struct
|
||||
{
|
||||
LumieraRWLock rwlock;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_rwlockacquirer_struct lumiera_rwlockacquirer;
|
||||
typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer;
|
||||
|
||||
/* helper function for nobug */
|
||||
static inline void
|
||||
lumiera_rwlockacquirer_ensureunlocked (LumieraRWLockacquirer self)
|
||||
{
|
||||
ENSURE (!self->rwlock, "forgot to unlock rwlock");
|
||||
}
|
||||
int
|
||||
lumiera_rwlock_unlock_cb (void* rwlock);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
82
src/lib/sectionlock.h
Normal file
82
src/lib/sectionlock.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
sectionlock.h - mutex state handle
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_SECTIONLOCK_H
|
||||
#define LUMIERA_SECTIONLOCK_H
|
||||
|
||||
#include "lib/error.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <nobug.h>
|
||||
|
||||
LUMIERA_ERROR_DECLARE (LOCK_ACQUIRE);
|
||||
LUMIERA_ERROR_DECLARE (LOCK_RELEASE);
|
||||
LUMIERA_ERROR_DECLARE (LOCK_DESTROY);
|
||||
|
||||
|
||||
typedef int (*lumiera_sectionlock_unlock_fn)(void*);
|
||||
|
||||
/**
|
||||
* sectionlock used to manage the state of mutexes.
|
||||
*/
|
||||
struct lumiera_sectionlock_struct
|
||||
{
|
||||
void* lock;
|
||||
lumiera_sectionlock_unlock_fn unlock;
|
||||
NOBUG_IF_ALPHA(struct nobug_flag* flag);
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_sectionlock_struct lumiera_sectionlock;
|
||||
typedef struct lumiera_sectionlock_struct* LumieraSectionlock;
|
||||
|
||||
/* helper function for nobug */
|
||||
static inline void
|
||||
lumiera_sectionlock_ensureunlocked (LumieraSectionlock self)
|
||||
{
|
||||
ENSURE (!self->lock, "forgot to unlock");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Unlock the lock hold in a SECTION
|
||||
* @internal
|
||||
* @param sectionname name used for the sectionlock instance
|
||||
* @param ... some extra code to execute
|
||||
*/
|
||||
#define LUMIERA_SECTION_UNLOCK_(section) \
|
||||
do if ((section)->lock) \
|
||||
{ \
|
||||
if ((section)->unlock((section)->lock)) \
|
||||
LUMIERA_DIE (LOCK_RELEASE); \
|
||||
(section)->lock = NULL; \
|
||||
NOBUG_RESOURCE_LEAVE_RAW((section)->flag, (section)->rh); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -73,6 +73,7 @@
|
|||
|
||||
extern "C" {
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/recmutex.h"
|
||||
#include "lib/condition.h"
|
||||
#include "lib/reccondition.h"
|
||||
}
|
||||
|
|
@ -98,25 +99,29 @@ namespace lib {
|
|||
protected:
|
||||
Wrapped_LumieraExcMutex() { lumiera_mutex_init (this, "Obj.Monitor ExclMutex", &NOBUG_FLAG(sync)); }
|
||||
~Wrapped_LumieraExcMutex() { lumiera_mutex_destroy (this, &NOBUG_FLAG(sync)); }
|
||||
|
||||
|
||||
pthread_mutex_t* mutex() { return &(lumiera_mutex::mutex); }
|
||||
|
||||
//------------------Resource-Tracking------
|
||||
void __may_block() { TODO ("Record we may block on mutex"); }
|
||||
void __enter() { TODO ("Record we successfully acquired the mutex"); }
|
||||
void __leave() { TODO ("Record we are releasing the mutex"); }
|
||||
void __left() { TODO ("Record we released the mutex"); }
|
||||
};
|
||||
|
||||
|
||||
struct Wrapped_LumieraRecMutex
|
||||
: public lumiera_mutex
|
||||
: public lumiera_recmutex
|
||||
{
|
||||
protected:
|
||||
Wrapped_LumieraRecMutex() { lumiera_recmutex_init (this, "Obj.Monitor RecMutex", &NOBUG_FLAG(sync)); }
|
||||
~Wrapped_LumieraRecMutex() { lumiera_mutex_destroy (this, &NOBUG_FLAG(sync)); }
|
||||
|
||||
~Wrapped_LumieraRecMutex() { lumiera_recmutex_destroy (this, &NOBUG_FLAG(sync)); }
|
||||
|
||||
pthread_mutex_t* mutex() { return &recmutex; }
|
||||
|
||||
//------------------Resource-Tracking------
|
||||
void __may_block() { TODO ("Record we may block on mutex"); }
|
||||
void __enter() { TODO ("Record we successfully acquired the mutex"); }
|
||||
void __leave() { TODO ("Record we are releasing the mutex"); }
|
||||
void __left() { TODO ("Record we are released the mutex"); }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -126,11 +131,14 @@ namespace lib {
|
|||
protected:
|
||||
Wrapped_LumieraExcCond() { lumiera_condition_init (this, "Obj.Monitor ExclCondition", &NOBUG_FLAG(sync) ); }
|
||||
~Wrapped_LumieraExcCond() { lumiera_condition_destroy (this, &NOBUG_FLAG(sync) ); }
|
||||
|
||||
|
||||
pthread_mutex_t* mutex() { return &cndmutex; }
|
||||
pthread_cond_t* condv() { return &cond; }
|
||||
|
||||
//------------------Resource-Tracking------
|
||||
void __may_block() { TODO ("Record we may block on mutex"); }
|
||||
void __enter() { TODO ("Record we successfully acquired the mutex"); }
|
||||
void __leave() { TODO ("Record we are releasing the mutex"); }
|
||||
void __left() { TODO ("Record we released the mutex"); }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -140,11 +148,14 @@ namespace lib {
|
|||
protected:
|
||||
Wrapped_LumieraRecCond() { lumiera_reccondition_init (this, "Obj.Monitor RecCondition", &NOBUG_FLAG(sync) ); } ////////TODO
|
||||
~Wrapped_LumieraRecCond() { lumiera_reccondition_destroy (this, &NOBUG_FLAG(sync) ); }
|
||||
|
||||
|
||||
pthread_mutex_t* mutex() { return &reccndmutex; }
|
||||
pthread_cond_t* condv() { return &cond; }
|
||||
|
||||
//------------------Resource-Tracking------
|
||||
void __may_block() { TODO ("Record we may block on mutex"); }
|
||||
void __enter() { TODO ("Record we successfully acquired the mutex"); }
|
||||
void __leave() { TODO ("Record we are releasing the mutex"); }
|
||||
void __left() { TODO ("Record we released the mutex"); }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -159,7 +170,7 @@ namespace lib {
|
|||
using MTX::mutex;
|
||||
using MTX::__may_block;
|
||||
using MTX::__enter;
|
||||
using MTX::__leave;
|
||||
using MTX::__left;
|
||||
|
||||
~Mutex () { }
|
||||
Mutex () { }
|
||||
|
|
@ -172,7 +183,7 @@ namespace lib {
|
|||
{
|
||||
__may_block();
|
||||
|
||||
if (pthread_mutex_lock (&mutex))
|
||||
if (pthread_mutex_lock (mutex()))
|
||||
throw lumiera::error::State("Mutex acquire failed."); ///////TODO capture the error-code
|
||||
|
||||
__enter();
|
||||
|
|
@ -181,9 +192,9 @@ namespace lib {
|
|||
void
|
||||
release()
|
||||
{
|
||||
__leave();
|
||||
pthread_mutex_unlock (mutex());
|
||||
|
||||
pthread_mutex_unlock (&mutex);
|
||||
__left();
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -197,7 +208,7 @@ namespace lib {
|
|||
: public Mutex<CDX>
|
||||
{
|
||||
protected:
|
||||
using CDX::cond;
|
||||
using CDX::condv;
|
||||
using CDX::mutex;
|
||||
|
||||
public:
|
||||
|
|
@ -205,9 +216,9 @@ namespace lib {
|
|||
signal (bool wakeAll=false)
|
||||
{
|
||||
if (wakeAll)
|
||||
pthread_cond_broadcast (&cond);
|
||||
pthread_cond_broadcast (condv());
|
||||
else
|
||||
pthread_cond_signal (&cond);
|
||||
pthread_cond_signal (condv());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -218,9 +229,9 @@ namespace lib {
|
|||
int err=0;
|
||||
while (!predicate() && !err)
|
||||
if (waitEndTime)
|
||||
err = pthread_cond_timedwait (&cond, &mutex, &waitEndTime);
|
||||
err = pthread_cond_timedwait (condv(), mutex(), &waitEndTime);
|
||||
else
|
||||
err = pthread_cond_wait (&cond, &mutex);
|
||||
err = pthread_cond_wait (condv(), mutex());
|
||||
|
||||
if (!err) return true;
|
||||
if (ETIMEDOUT==err) return false;
|
||||
|
|
@ -436,3 +447,10 @@ namespace lib {
|
|||
|
||||
} // namespace lumiera
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ TEST "mutex not unlocked asserts" mutexforgotunlock <<END
|
|||
return: 134
|
||||
END
|
||||
|
||||
TEST "mutex explicitly unlocked" mutexexplicitunlock <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "nested mutex section" nestedmutexsection <<END
|
||||
out: outer mutex locked section
|
||||
|
|
@ -25,8 +29,8 @@ END
|
|||
|
||||
|
||||
TEST "recursive mutex section" recursivemutexsection <<END
|
||||
out: mutex locked once
|
||||
out: mutex locked twice
|
||||
out: recmutex locked once
|
||||
out: recmutex locked twice
|
||||
END
|
||||
|
||||
|
||||
|
|
@ -41,6 +45,15 @@ return: 134
|
|||
END
|
||||
|
||||
|
||||
PLANNED "rwlock readlock in writelock asserts" rwlockdeadlockwr <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
PLANNED "rwlock writelock in readlock asserts" rwlockdeadlockrw <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
|
||||
TEST "condition not unlocked asserts" conditionforgotunlock <<END
|
||||
return: 134
|
||||
END
|
||||
|
|
@ -57,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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -109,4 +109,10 @@ test_interfaces_LDADD = \
|
|||
-lboost_program_options-mt \
|
||||
-lboost_regex-mt
|
||||
|
||||
check_PROGRAMS += test-threads
|
||||
test_threads_SOURCES = $(tests_srcdir)/backend/test-threads.c
|
||||
test_threads_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||
test_threads_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
|
||||
test_threads_LDADD = liblumierabackend.la liblumiera.la -lnobugmt -lpthread -ldl -lm liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt
|
||||
|
||||
TESTS = $(tests_srcdir)/test.sh
|
||||
|
|
|
|||
159
tests/backend/test-threads.c
Normal file
159
tests/backend/test-threads.c
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
test-threads.c - test thread management
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
//#include <stdio.h>
|
||||
//#include <string.h>
|
||||
|
||||
#include "common/config.h"
|
||||
|
||||
#include "include/logging.h"
|
||||
#include "lib/mutex.h"
|
||||
#include "backend/threads.h"
|
||||
#include "tests/test.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
void threadfn(void* blah)
|
||||
{
|
||||
(void) blah;
|
||||
struct timespec wait = {0,300000000};
|
||||
|
||||
fprintf (stderr, "thread running %s\n", NOBUG_THREAD_ID_GET);
|
||||
nanosleep (&wait, NULL);
|
||||
fprintf (stderr, "thread done %s\n", NOBUG_THREAD_ID_GET);
|
||||
}
|
||||
|
||||
|
||||
void threadsyncfn(void* blah)
|
||||
{
|
||||
struct timespec wait = {0,200000000};
|
||||
LumieraReccondition sync = (LumieraReccondition) blah;
|
||||
|
||||
ECHO ("thread starting up %s", NOBUG_THREAD_ID_GET);
|
||||
LUMIERA_RECCONDITION_SECTION(cond_sync, sync)
|
||||
{
|
||||
ECHO ("send startup signal %s", NOBUG_THREAD_ID_GET);
|
||||
LUMIERA_RECCONDITION_SIGNAL;
|
||||
ECHO ("wait for trigger %s", NOBUG_THREAD_ID_GET);
|
||||
LUMIERA_RECCONDITION_WAIT(1);
|
||||
}
|
||||
|
||||
ECHO ("thread running %s", NOBUG_THREAD_ID_GET);
|
||||
nanosleep (&wait, NULL);
|
||||
ECHO ("thread done %s", NOBUG_THREAD_ID_GET);
|
||||
}
|
||||
|
||||
|
||||
|
||||
lumiera_mutex testmutex;
|
||||
|
||||
void mutexfn(void* blah)
|
||||
{
|
||||
(void) blah;
|
||||
struct timespec wait = {0,300000000};
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &testmutex)
|
||||
{
|
||||
fprintf (stderr, "mutex thread running %s\n", NOBUG_THREAD_ID_GET);
|
||||
nanosleep (&wait, NULL);
|
||||
fprintf (stderr, "thread done %s\n", NOBUG_THREAD_ID_GET);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
TEST ("simple_thread")
|
||||
{
|
||||
fprintf (stderr, "main before thread %s\n", NOBUG_THREAD_ID_GET);
|
||||
|
||||
lumiera_thread_run (LUMIERA_THREAD_WORKER,
|
||||
threadfn,
|
||||
NULL,
|
||||
NULL,
|
||||
argv[1],
|
||||
NULL);
|
||||
|
||||
struct timespec wait = {0,600000000};
|
||||
nanosleep (&wait, NULL);
|
||||
fprintf (stderr, "main after thread %s\n", NOBUG_THREAD_ID_GET);
|
||||
}
|
||||
|
||||
TEST ("thread_synced")
|
||||
{
|
||||
lumiera_reccondition cnd;
|
||||
lumiera_reccondition_init (&cnd, "threadsync", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_RECCONDITION_SECTION(cond_sync, &cnd)
|
||||
{
|
||||
ECHO ("main before thread %s", NOBUG_THREAD_ID_GET);
|
||||
|
||||
lumiera_thread_run (LUMIERA_THREAD_WORKER,
|
||||
threadsyncfn,
|
||||
&cnd,
|
||||
&cnd,
|
||||
argv[1],
|
||||
NULL);
|
||||
|
||||
ECHO ("main wait for thread being ready %s", NOBUG_THREAD_ID_GET);
|
||||
LUMIERA_RECCONDITION_WAIT(1);
|
||||
|
||||
ECHO ("main trigger thread %s", NOBUG_THREAD_ID_GET);
|
||||
LUMIERA_RECCONDITION_SIGNAL;
|
||||
|
||||
ECHO ("wait for thread end %s", NOBUG_THREAD_ID_GET);
|
||||
LUMIERA_RECCONDITION_WAIT(1);
|
||||
ECHO ("thread ended %s", NOBUG_THREAD_ID_GET);
|
||||
}
|
||||
|
||||
lumiera_reccondition_destroy (&cnd, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("mutex_thread")
|
||||
{
|
||||
lumiera_mutex_init (&testmutex, "test", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &testmutex)
|
||||
{
|
||||
fprintf (stderr, "main before thread %s\n", NOBUG_THREAD_ID_GET);
|
||||
|
||||
lumiera_thread_run (LUMIERA_THREAD_WORKER,
|
||||
mutexfn,
|
||||
NULL,
|
||||
NULL,
|
||||
argv[1],
|
||||
NULL);
|
||||
|
||||
struct timespec wait = {0,600000000};
|
||||
nanosleep (&wait, NULL);
|
||||
fprintf (stderr, "main after thread %s\n", NOBUG_THREAD_ID_GET);
|
||||
}
|
||||
|
||||
lumiera_mutex_destroy (&testmutex, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TESTS_END
|
||||
|
|
@ -21,7 +21,9 @@
|
|||
|
||||
#include "tests/test.h"
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/recmutex.h"
|
||||
#include "lib/condition.h"
|
||||
#include "lib/reccondition.h"
|
||||
#include "lib/rwlock.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
@ -63,6 +65,22 @@ TEST ("mutexforgotunlock")
|
|||
}
|
||||
|
||||
|
||||
TEST ("mutexexplicitunlock")
|
||||
{
|
||||
lumiera_mutex m;
|
||||
lumiera_mutex_init (&m, "mutexforgotunlock", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
ECHO("mutex locked section");
|
||||
LUMIERA_MUTEX_SECTION_UNLOCK;
|
||||
break;
|
||||
}
|
||||
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("nestedmutexsection")
|
||||
{
|
||||
lumiera_mutex m;
|
||||
|
|
@ -107,25 +125,29 @@ 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_recmutex m;
|
||||
lumiera_recmutex_init (&m, "m_recmutexsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
LUMIERA_RECMUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
printf ("mutex locked once\n");
|
||||
printf ("recmutex locked once\n");
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
LUMIERA_RECMUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
printf ("mutex locked twice\n");
|
||||
printf ("recmutex locked twice\n");
|
||||
}
|
||||
}
|
||||
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
lumiera_recmutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("rwlocksection")
|
||||
{
|
||||
lumiera_rwlock rwlock;
|
||||
|
|
@ -144,6 +166,7 @@ TEST ("rwlocksection")
|
|||
lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("rwlockforgotunlock")
|
||||
{
|
||||
lumiera_rwlock rwlock;
|
||||
|
|
@ -158,6 +181,60 @@ TEST ("rwlockforgotunlock")
|
|||
}
|
||||
|
||||
|
||||
|
||||
TEST ("rwdeadlockwr")
|
||||
{
|
||||
lumiera_rwlock rwlock;
|
||||
lumiera_rwlock_init (&rwlock, "rwsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock)
|
||||
{
|
||||
printf ("write locked section 1\n");
|
||||
LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
|
||||
{
|
||||
printf ("read locked section 2\n");
|
||||
}
|
||||
}
|
||||
|
||||
lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("rwdeadlockrw")
|
||||
{
|
||||
lumiera_rwlock rwlock;
|
||||
lumiera_rwlock_init (&rwlock, "rwsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
|
||||
{
|
||||
printf ("read locked section 1\n");
|
||||
LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock)
|
||||
{
|
||||
printf ("write locked section 2\n");
|
||||
}
|
||||
}
|
||||
|
||||
lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
|
@ -177,6 +254,7 @@ TEST ("conditionsection")
|
|||
}
|
||||
|
||||
|
||||
|
||||
TEST ("conditionforgotunlock")
|
||||
{
|
||||
lumiera_condition cond;
|
||||
|
|
@ -190,4 +268,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