Sync with cehteh's code

Merge commit 'd50ab9fe2125f985eb4ae9a610f4944cddc425bd'
This commit is contained in:
Fischlurch 2007-09-02 23:19:56 +02:00
commit d7d3cfe876
9 changed files with 419 additions and 10 deletions

View file

@ -25,11 +25,15 @@ libcin3_a_SOURCES = \
$(libcin3_a_srcdir)/plugin.c \
$(libcin3_a_srcdir)/error.c \
$(libcin3_a_srcdir)/time.c \
$(libcin3_a_srcdir)/framerate.c
$(libcin3_a_srcdir)/framerate.c \
$(libcin3_a_srcdir)/condition.c
noinst_HEADERS += \
$(libcin3_a_srcdir)/plugin.h \
$(libcin3_a_srcdir)/error.h \
$(libcin3_a_srcdir)/time.h \
$(libcin3_a_srcdir)/framerate.h
$(libcin3_a_srcdir)/framerate.h \
$(libcin3_a_srcdir)/locking.h \
$(libcin3_a_srcdir)/condition.h

50
src/lib/condition.c Normal file
View file

@ -0,0 +1,50 @@
/*
condition.c - condition variable
Copyright (C) CinelerraCV
2007, 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/condition.h"
CinelerraCondition
cinelerra_condition_init (CinelerraCondition self)
{
if (self)
{
pthread_cond_init (&self->cond, NULL);
pthread_mutex_init (&self->mutex, NULL);
}
return self;
}
CinelerraCondition
cinelerra_condition_destroy (CinelerraCondition self)
{
if (self)
{
if (pthread_mutex_destroy (&self->mutex))
CINELERRA_DIE;
else if (pthread_cond_destroy (&self->cond))
CINELERRA_DIE;
}
return self;
}

212
src/lib/condition.h Normal file
View file

@ -0,0 +1,212 @@
/*
condition.h - condition variables
Copyright (C) CinelerraCV
2007, 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 CINELERRA_CONDITION_H
#define CINELERRA_CONDITION_H
#include "lib/locking.h"
/**
* Condition variables.
*
*/
struct cinelerra_condition_struct
{
pthread_cond_t cond;
pthread_mutex_t mutex;
};
typedef struct cinelerra_condition_struct cinelerra_condition;
typedef cinelerra_condition* CinelerraCondition;
/**
* Initialize a condition variable
* @param self is a pointer to the condition variable to be initialized
* @return self as given
*/
CinelerraCondition
cinelerra_condition_init (CinelerraCondition self);
/**
* Destroy a condition variable
* @param self is a pointer to the condition variable to be destroyed
* @return self as given
*/
CinelerraCondition
cinelerra_condition_destroy (CinelerraCondition self);
/**
* signal a single waiting thread.
* @param self condition variable to be signaled, must be given, all errors are fatal
*/
static inline void
cinelerra_condition_signal (CinelerraCondition self)
{
REQUIRE (self);
if (pthread_mutex_lock (&self->mutex))
CINELERRA_DIE;
pthread_cond_signal (&self->cond);
if (pthread_mutex_unlock (&self->mutex))
CINELERRA_DIE;
}
/**
* signal all waiting threads
* @param self condition variable to be signaled, must be given, all errors are fatal
*/
static inline void
cinelerra_condition_broadcast (CinelerraCondition self)
{
REQUIRE (self);
if (pthread_mutex_lock (&self->mutex))
CINELERRA_DIE;
pthread_cond_broadcast (&self->cond);
if (pthread_mutex_unlock (&self->mutex))
CINELERRA_DIE;
}
/**
* conditionlock used to manage the state of a condition variable.
*/
struct cinelerra_conditionlock_struct
{
CinelerraCondition cond;
enum cinelerra_lockstate state;
};
typedef struct cinelerra_conditionlock_struct cinelerra_conditionlock;
typedef struct cinelerra_conditionlock_struct* CinelerraConditionlock;
/* helper function for nobug */
static inline void
cinelerra_conditionlock_ensureunlocked (CinelerraConditionlock self)
{
ENSURE (self->state == CINELERRA_UNLOCKED, "forgot to unlock the condition mutex");
}
/* override with a macro to use the cleanup checker */
#define cinelerra_conditionlock \
cinelerra_conditionlock NOBUG_CLEANUP(cinelerra_conditionlock_ensureunlocked)
/**
* initialize a conditionlock state
* @param self conditionlock to be initialized, must be an automatic variable
* @param cond associated condition variable
* @param state initial state of the mutex, either CINELERRA_LOCKED or CINELERRA_UNLOCKED
* @return self as given
* errors are fatal
*/
static inline CinelerraConditionlock
cinelerra_conditionlock_init (CinelerraConditionlock self, CinelerraCondition cond, enum cinelerra_lockstate state)
{
REQUIRE (self);
REQUIRE (cond);
self->cond = cond;
self->state = state;
if (state == CINELERRA_LOCKED)
if (pthread_mutex_lock (&cond->mutex))
CINELERRA_DIE;
return self;
}
/**
* lock the mutex.
* must not already be locked
* @param self conditionlock associated with a condition variable
*/
static inline void
cinelerra_conditionlock_lock (CinelerraConditionlock self)
{
REQUIRE (self);
REQUIRE (self->state == CINELERRA_UNLOCKED, "mutex already locked");
if (pthread_mutex_lock (&self->cond->mutex))
CINELERRA_DIE;
self->state = CINELERRA_LOCKED;
}
/**
* wait on a locked condition.
* Waits until the condition variable gets signaled from another thread. Must already be locked.
* @param self conditionlock associated with a condition variable
*/
static inline void
cinelerra_conditionlock_wait (CinelerraConditionlock self)
{
REQUIRE (self);
REQUIRE (self->state == CINELERRA_LOCKED, "mutex must be locked");
pthread_cond_wait (&self->cond->cond, &self->cond->mutex);
}
/**
* release mutex.
* a conditionlock must be unlocked before leaving scope
* @param self conditionlock associated with a condition variable
*/
static inline int
cinelerra_conditionlock_unlock (CinelerraConditionlock self)
{
REQUIRE (self);
REQUIRE (self->state == CINELERRA_LOCKED, "mutex was not locked");
if (pthread_mutex_unlock (&self->cond->mutex))
CINELERRA_DIE;
self->state = CINELERRA_UNLOCKED;
}
/**
* signal a single waiting thread
* @param self conditionlock associated with the condition variable to be signaled
*/
static inline void
cinelerra_conditionlock_signal (CinelerraConditionlock self)
{
REQUIRE (self);
REQUIRE (self->state == CINELERRA_LOCKED, "mutex was not locked");
pthread_cond_signal (&self->cond->cond);
}
/**
* signal all waiting threads
* @param self conditionlock associated with the condition variable to be signaled
*/
static inline int
cinelerra_conditionlock_broadcast (CinelerraConditionlock self)
{
REQUIRE (self);
REQUIRE (self->state == CINELERRA_LOCKED, "mutex was not locked");
pthread_cond_broadcast (&self->cond->cond);
}
#endif

43
src/lib/locking.h Normal file
View file

@ -0,0 +1,43 @@
/*
locking.h - shared declarations for all locking primitives
Copyright (C) CinelerraCV
2007, 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 CINELERRA_LOCKING_H
#define CINELERRA_LOCKING_H
#include <pthread.h>
#include <nobug.h>
#include "lib/error.h"
/**
* used to store the current lock state.
*
*
*/
enum cinelerra_lockstate
{
CINELERRA_UNLOCKED,
CINELERRA_LOCKED,
CINELERRA_RLOCKED,
CINELERRA_WLOCKED
};
#endif

5
tests/.gitignore vendored
View file

@ -1,5 +0,0 @@
,*
test-*
mainsuite
errortest
plugin-example

8
tests/15locking.tests Normal file
View file

@ -0,0 +1,8 @@
TESTING "Locking" ./test-locking
TEST "condition not unlocked asserts" conditionforgotunlock <<END
return: 134
END

View file

@ -18,7 +18,7 @@
tests_srcdir = $(top_srcdir)/tests
check_PROGRAMS += test-error test-time
check_PROGRAMS += test-error test-time test-condition
test_error_SOURCES = $(tests_srcdir)/error/errortest.c
test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
@ -28,4 +28,8 @@ test_time_SOURCES = $(tests_srcdir)/time/test-time.c
test_time_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
test_time_LDADD = $(builddir)/libcin3.a -lnobugmt -lpthread -ldl -lm
test_condition_SOURCES = $(tests_srcdir)/locking/test-condition.c
test_condition_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
test_condition_LDADD = $(builddir)/libcin3.a -lnobugmt -lpthread -ldl -lm
TESTS = $(tests_srcdir)/test.sh

View file

@ -0,0 +1,65 @@
/*
test-locking.c - test locking functions
Copyright (C) CinelerraCV
2007, 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 "lib/condition.h"
CINELERRA_ERROR_DEFINE(TEST, "test error");
#if 0
waiting_thread()
{
lock;
wait;
unlock;
}
signaling_thread()
{
signal();
}
#endif
int
main (int argc, char** argv)
{
NOBUG_INIT;
if (argc == 1)
return 0;
if (!strcmp(argv[1], "conditionforgotunlock"))
{
cinelerra_condition c;
cinelerra_condition_init (&c);
cinelerra_conditionlock NOBUG_CLEANUP(cinelerra_conditionlock_ensureunlocked) l;
cinelerra_conditionlock_init (&l, &c, CINELERRA_LOCKED);
}
else
return 1;
return 0;
}

View file

@ -1134,6 +1134,34 @@ config.formatters.push( {
} )
//}}}</pre>
</div>
<div title="LockingPrimitives" modifier="CehTeh" modified="200709021253" created="200709021250" changecount="3">
<pre>! Provided Locking Primitives
The support library provides wrappers around some pthread locking primitives to make their usage more robust and easier.
The basic concept is that each locking primitive is an object as well as each locker is implemented as object too, this adds a small convenience layer for robustness. We use ~NoBug to assert that locks are properly unlocked.
!! Mutex
We only support fast (non recursive, non errorcheck) mutexes for now. Debugging deadlock detection will be done in ~NoBug. If we need dynamic deadlock detection we will have to support errorcheck mutexes at demand. Same for recursive mutexes.
!! Condition Variables
Condition variables are simple synchronization devices, refer to the doxygen docs about using them. One needs to lock them when preparing to wait on them and finally unlock them. While signaling can optionally be done without a locker object (locking is implicit then).
!! Read/Write Locks
Similar to mutexes we support multiple-reader/one-writer locks, they can be used whenever many concurrent read accesses and rare write accesses are expected to some datastructure (profile this later). When congestion rather unexpected then prefer a mutex.
! No Semaphores Rationale
Semaphores have quite ugly semantics and are very hard to debug. For now (and likely forever) we will not to use them.
! ~ToDo
!! trylock and timedlock
.. is not yet implemented but will be added in request.
!! Barriers
... will be added on request too.
!! Thread Cancellation
Thread cancellation policies are not yet finally decided, for now we consider threads uncancelable!</pre>
</div>
<div title="MainMenu" modifier="CehTeh" modified="200707152251" created="200707102300" changecount="2">
<pre>''[[Cinelerra3|index.html]]''
SupportLibrary
@ -2391,7 +2419,7 @@ h1,h2,h3,h4,h5,h6 {
/*}}}*/
</pre>
</div>
<div title="SupportLibrary" modifier="CehTeh" modified="200708261935" created="200707102314" changecount="8">
<div title="SupportLibrary" modifier="CehTeh" modified="200709021227" created="200707102314" changecount="9">
<pre>The Support Library contains all tools we need at various places, but by themselves don't defines a subsystem on their own.
These things are:
@ -2399,7 +2427,7 @@ These things are:
* [[ErrorHandling]]
* a wrapper for POSIX Threads
** Thread creation joining and canceling
** Locking primitives like Condition variables and Mutexes
** [[Locking primitives like Condition variables and Mutexes|LockingPrimitives]]
* [[Frame and Time handling and calculations|FrameAndTime]]
(... to be continued)