Merge branch 'devel' of git://git.lumiera.org/lumiera/ct into work

This commit is contained in:
Joel Holdsworth 2008-05-13 22:10:22 +01:00
commit f030798844
33 changed files with 1948 additions and 369 deletions

View file

@ -34,7 +34,7 @@ include $(top_srcdir)/admin/Makefile.am
# core
include $(top_srcdir)/src/lib/Makefile.am
include $(top_srcdir)/src/backend/Makefile.am
#include $(top_srcdir)/src/backend/Makefile.am
# plugins
#include $(top_srcdir)/src...

View file

@ -24,20 +24,25 @@ liblumi_a_CPPFLAGS = -I$(top_srcdir)/src/
liblumi_a_SOURCES = \
$(liblumi_a_srcdir)/plugin.c \
$(liblumi_a_srcdir)/error.c \
$(liblumi_a_srcdir)/framerate.c \
$(liblumi_a_srcdir)/mutex.c \
$(liblumi_a_srcdir)/rwlock.c \
$(liblumi_a_srcdir)/condition.c \
$(liblumi_a_srcdir)/references.c
$(liblumi_a_srcdir)/references.c \
$(liblumi_a_srcdir)/uuid.c \
$(liblumi_a_srcdir)/safeclib.c \
$(liblumi_a_srcdir)/cuckoo.c \
$(liblumi_a_srcdir)/mrucache.c
noinst_HEADERS += \
$(liblumi_a_srcdir)/plugin.h \
$(liblumi_a_srcdir)/error.h \
$(liblumi_a_srcdir)/framerate.h \
$(liblumi_a_srcdir)/locking.h \
$(liblumi_a_srcdir)/mutex.h \
$(liblumi_a_srcdir)/rwlock.h \
$(liblumi_a_srcdir)/condition.h \
$(liblumi_a_srcdir)/references.h
$(liblumi_a_srcdir)/references.h \
$(liblumi_a_srcdir)/uuid.h \
$(liblumi_a_srcdir)/safeclib.h \
$(liblumi_a_srcdir)/cuckoo.h \
$(liblumi_a_srcdir)/mrucache.h

View file

@ -25,6 +25,8 @@
* @file Condition variables
*/
LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed");
/**
* Initialize a condition variable
* @param self is a pointer to the condition variable to be initialized
@ -53,9 +55,9 @@ lumiera_condition_destroy (LumieraCondition self)
if (self)
{
if (pthread_mutex_destroy (&self->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_DESTROY);
else if (pthread_cond_destroy (&self->cond))
LUMIERA_DIE;
LUMIERA_DIE (CONDITION_DESTROY);
}
return self;
}

View file

@ -28,6 +28,7 @@
* @file Condition variables, header
*/
LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
/**
* Condition variables.
@ -59,10 +60,10 @@ lumiera_condition_signal (LumieraCondition self)
{
REQUIRE (self);
if (pthread_mutex_lock (&self->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_LOCK);
pthread_cond_signal (&self->cond);
if (pthread_mutex_unlock (&self->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_UNLOCK);
}
/**
@ -74,10 +75,10 @@ lumiera_condition_broadcast (LumieraCondition self)
{
REQUIRE (self);
if (pthread_mutex_lock (&self->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_LOCK);
pthread_cond_broadcast (&self->cond);
if (pthread_mutex_unlock (&self->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_UNLOCK);
}
@ -124,7 +125,7 @@ lumiera_conditionacquirer_init (LumieraConditionacquirer self, LumieraCondition
self->state = state;
if (state == LUMIERA_LOCKED)
if (pthread_mutex_lock (&cond->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_LOCK);
return self;
}
@ -141,7 +142,7 @@ lumiera_conditionacquirer_lock (LumieraConditionacquirer self)
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
if (pthread_mutex_lock (&self->cond->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_LOCK);
self->state = LUMIERA_LOCKED;
}
@ -172,7 +173,7 @@ lumiera_conditionacquirer_unlock (LumieraConditionacquirer self)
REQUIRE (self);
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
if (pthread_mutex_unlock (&self->cond->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_UNLOCK);
self->state = LUMIERA_UNLOCKED;
}

497
src/lib/cuckoo.c Normal file
View file

@ -0,0 +1,497 @@
/*
A cuckoo hash implementation
Copyright (C)
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 "cuckoo.h"
#include <string.h>
enum compact_state
{
COMPACTING_OFF,
COMPACTING_AUTO,
COMPACTED
};
struct cuckoo_struct
{
size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */
size_t itemsize;
cuckoo_hashfunc h1; /* hash function */
uint32_t r1; /* random, reset for each rehash */
cuckoo_hashfunc h2;
uint32_t r2;
cuckoo_hashfunc h3;
uint32_t r3;
cuckoo_cmpfunc cmp;
void* t1;
void* t2;
void* t3;
unsigned maxloops; /* sqrt (4 * size) */
enum compact_state autocompact;
size_t elements;
};
static inline uint32_t cuckoo_fast_prng ()
{
static uint32_t rnd = 0xbabeface;
return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1);
}
Cuckoo
cuckoo_init (Cuckoo self,
cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize)
{
if (!self)
return NULL;
self->size = 1<<startsize;
self->itemsize = itemsize;
self->h1 = h1;
self->r1 = cuckoo_fast_prng ();
self->h2 = h2;
self->r2 = cuckoo_fast_prng ();
self->h3 = h3;
self->r3 = cuckoo_fast_prng ();
self->cmp = cmp;
self->t1 = calloc (self->size * 4, itemsize);
self->t2 = calloc (self->size * 2, itemsize);
self->t3 = calloc (self->size, itemsize);
if (!self->t1 || !self->t2 || !self->t3)
{
free (self->t1);
free (self->t2);
free (self->t3);
return NULL;
}
self->maxloops = 1;
while (self->maxloops * self->maxloops < self->size * 4)
++self->maxloops;
self->autocompact = COMPACTING_AUTO;
self->elements = 0;
return self;
}
Cuckoo
cuckoo_new (cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize)
{
Cuckoo self = malloc (sizeof (struct cuckoo_struct));
if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize))
{
free (self);
return NULL;
}
return self;
}
Cuckoo
cuckoo_destroy (Cuckoo self)
{
if (self)
{
free (self->t1);
free (self->t2);
free (self->t3);
}
return self;
}
void
cuckoo_free (Cuckoo self)
{
free (cuckoo_destroy (self));
}
static inline int
iszero (void* mem, size_t size)
{
while (size && !*(int*)mem)
{
size -= sizeof (int);
mem += sizeof (int);
}
return !size;
}
static inline void
xmemcpy (void* dst, void* src, size_t size)
{
while (size)
{
size -= sizeof (int);
*(int*)(dst + size) = *(int*)(src + size);
}
}
static int
cuckoo_insert_internal_ (Cuckoo self, void* item)
{
void* pos;
char tmp[self->itemsize];
for (unsigned n = 0; n < self->maxloops; ++n)
{
/* find nest */
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
/* kick old egg out */
xmemcpy (tmp, pos, self->itemsize);
/* lay egg */
xmemcpy (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
return 1;
/* find nest */
pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size));
/* kick old egg out */
xmemcpy (item, pos, self->itemsize);
/* lay egg */
xmemcpy (pos, tmp, self->itemsize);
if (iszero (item, self->itemsize))
return 1;
/* find nest */
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
/* kick old egg out */
xmemcpy (tmp, pos, self->itemsize);
/* lay egg */
xmemcpy (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
return 1;
/* copy tmp to item, which will be reinserted on next interation / after rehashing */
xmemcpy (item, tmp, self->itemsize);
}
return 0;
}
static void
cuckoo_rehash (Cuckoo self)
{
retry1:
self->r1 = cuckoo_fast_prng ();
for (size_t i = 0; i < 4*self->size; ++i)
{
unsigned n;
void* pos = self->t1 + self->itemsize * i;
if (!iszero (pos, self->itemsize))
{
for (n = 0; n < self->maxloops; ++n)
{
unsigned hash = self->h1 (pos, self->r1) % (4*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t1 + self->itemsize * hash;
xmemcpy (t, hpos, self->itemsize);
xmemcpy (hpos, pos, self->itemsize);
xmemcpy (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
else
break;
}
if (n == self->maxloops)
goto retry1;
}
}
retry2:
self->r2 = cuckoo_fast_prng ();
for (size_t i = 0; i < 2*self->size; ++i)
{
unsigned n;
void* pos = self->t2 + self->itemsize * i;
if (!iszero (pos, self->itemsize))
{
for (n = 0; n < self->maxloops; ++n)
{
unsigned hash = self->h2 (pos, self->r2) % (2*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t2 + self->itemsize * hash;
xmemcpy (t, hpos, self->itemsize);
xmemcpy (hpos, pos, self->itemsize);
xmemcpy (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
else
break;
}
if (n == self->maxloops)
goto retry2;
}
}
retry3:
self->r3 = cuckoo_fast_prng ();
for (size_t i = 0; i < self->size; ++i)
{
unsigned n;
void* pos = self->t3 + self->itemsize * i;
if (!iszero (pos, self->itemsize))
{
for (n = 0; n < self->maxloops; ++n)
{
unsigned hash = self->h3 (pos, self->r3) % self->size;
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t3 + self->itemsize * hash;
xmemcpy (t, hpos, self->itemsize);
xmemcpy (hpos, pos, self->itemsize);
xmemcpy (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
else
break;
}
if (n == self->maxloops)
goto retry3;
}
}
}
static int
cuckoo_grow (Cuckoo self)
{
/* rotate hashfuncs, tables, randoms */
cuckoo_hashfunc th = self->h3;
self->h3 = self->h2;
self->h2 = self->h1;
self->h1 = th;
uint32_t tr = self->r3;
self->r3 = self->r2;
self->r2 = self->r1;
self->r1 = tr;
void* tt = self->t3;
self->t3 = self->t2;
self->t2 = self->t1;
/* double new base size */
self->size *= 2;
while (self->maxloops * self->maxloops < self->size * 4)
++self->maxloops;
/* alloc new t1 */
self->t1 = calloc (self->size * 4, self->itemsize);
if (!self->t1)
{
self->t1 = tt;
return 0;
}
/* reinsert tt */
size_t ttsize = self->size / 2;
for (size_t i = 0; i < ttsize; ++i)
{
void* pos = tt + i * self->itemsize;
if (!iszero (pos, self->itemsize))
{
while (!cuckoo_insert_internal_ (self, pos))
cuckoo_rehash (self);
}
}
free (tt);
self->autocompact = COMPACTING_AUTO;
return 1;
}
int
cuckoo_reserve (Cuckoo self, size_t more)
{
int ret = 1;
if (more)
while (self->elements+self->maxloops+more >= 6*self->size)
ret = cuckoo_grow (self);
self->autocompact = COMPACTING_OFF;
return ret;
}
int
cuckoo_compact (Cuckoo self)
{
if (self->autocompact == COMPACTED)
return 1;
if (self->size > 2 && self->elements < self->size * 3)
{
cuckoo_hashfunc th = self->h1;
self->h1 = self->h2;
self->h2 = self->h3;
self->h3 = th;
uint32_t tr = self->r1;
self->r1 = self->r2;
self->r2 = self->r3;
self->r3 = tr;
void* tt = self->t1;
self->t1 = self->t2;
self->t2 = self->t3;
/* halve base size */
self->size /= 2;
while (self->maxloops * self->maxloops >= self->size * 4)
--self->maxloops;
/* alloc new t3 */
self->t3 = calloc (self->size, self->itemsize);
if (!self->t3)
{
self->t3 = tt;
return 0;
}
/* reinsert tt */
size_t ttsize = self->size * 8;
for (size_t i = 0; i < ttsize; ++i)
{
void* pos = tt + i * self->itemsize;
if (!iszero (pos, self->itemsize))
{
--self->elements;
cuckoo_insert (self, pos);
}
}
free (tt);
self->autocompact = COMPACTED;
}
return 1;
}
int
cuckoo_insert (Cuckoo self, void* item)
{
char tmp[self->itemsize];
void* found;
if ((found = cuckoo_find (self, item)))
{
xmemcpy (found, item, self->itemsize);
return 1;
}
xmemcpy (tmp, item, self->itemsize);
for (unsigned n = 6; n; --n) /* rehash/grow loop */
{
if (cuckoo_insert_internal_ (self, tmp))
{
++self->elements;
return 1;
}
if (self->elements > n*self->size)
{
n = 6;
if (!cuckoo_grow (self))
return 0;
}
else
cuckoo_rehash (self);
}
return 0;
}
void*
cuckoo_find (Cuckoo self, void* item)
{
void* pos;
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
return pos;
pos = self->t2 + self->itemsize * (self->h2 (item, self->r2) % (2*self->size));
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
return pos;
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
return pos;
return NULL;
}
void
cuckoo_remove (Cuckoo self, void* item)
{
if (item)
{
memset (item, 0, self->itemsize);
--self->elements;
if (self->autocompact == COMPACTING_AUTO && self->size > 2 && self->elements <= self->size*2)
cuckoo_compact (self);
}
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

167
src/lib/cuckoo.h Normal file
View file

@ -0,0 +1,167 @@
/*
A cuckoo hash implementation
Copyright (C)
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 CUCKOO_H
#define CUCKOO_H
/**
* @file Cuckoo hashing
* This hashing gives guaranteed O(1) lookup complexity and amortized O(1) insert and remove complexity.
* Hash tables by default grow and shrink automatically. It is posible to preallocate entries and turn
* automatic shrinking off taking out the memory management factors for insert and remove operations.
* This implementation uses 3 Tables which exponential growing sizes.
*/
#include <stdlib.h>
#include <stdint.h>
struct cuckoo_struct;
typedef struct cuckoo_struct * Cuckoo;
/**
* Hash function.
* User supplied universal hash function
* @param item address of the item to be hashed
* @param r pseudo random number, 31 significant bits, regenerated on each rehash
* @return hash value
*/
typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r);
/**
* Compare function.
* User supplied compare function
* @param item1 address of the first item
* @param item2 address of the second item
* @return 1 when the items are identical, 0 otherwise
*/
typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2);
/**
* Initialize a cuckoo hash.
* @param self pointer to a uninitialized cuckoo datastructure
* @param h1 hash function for the first table
* @param h2 hash function for the second table
* @param h3 hash function for the third table
* @param cmp function which compares two keys
* @param startsize initial size of table t3, as 2's exponent
* @return The initialized hashtable or NULL at allocation failure
*/
Cuckoo
cuckoo_init (Cuckoo self,
cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize);
/**
* Allocate a new cuckoo hash.
* @param h1 hash function for the first table
* @param h2 hash function for the second table
* @param h3 hash function for the third table
* @param cmp function which compares two keys
* @param startsize initial size of table t3, as 2's exponent
* @return The initialized hashtable or NULL at allocation failure
*/
Cuckoo
cuckoo_new (cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize);
/**
* Destroy a cuckoo hash.
* Frees internal used resources.
* @param self cuckoo hash to destroy
* @return The now uninitialized hashtable
*/
Cuckoo
cuckoo_destroy (Cuckoo self);
/**
* Deallocate a cuckoo hash.
* @param self handle of the hash table to be freed
*/
void
cuckoo_free (Cuckoo self);
/**
* Insert an element into a hash.
* amortized O(1) complexity because it may rarely rehash the tables or even grow them.
* see cuckoo_reserve() about how to preallocate entries to prevent the growing costs.
* @param self handle to the hash table
* @param item pointer to a item to be inserted
* @return 1 on successful insert, 0 on allocation failure
* Note: at failure there is one arbitary hash cell lost!
*/
int
cuckoo_insert (Cuckoo self, void* item);
/**
* Find a value by key in a hash.
* @param self handle to the hash table
* @param item pointer to an item to be looked up
* @return found object or NULL if not present
*/
void*
cuckoo_find (Cuckoo self, void* item);
/**
* Remove a item from a hash.
* amortized O(1) complexity when it automatically shrink its tables.
* guaranteed O(1) complexity when automatic shrinking is turned off.
* see cuckoo_reserve() about how turn automatic shrinking off.
* @param self handle to the hash table
* @param item pointer to the item to be removed
*/
void
cuckoo_remove (Cuckoo self, void* item);
/**
* Shrink the hash sizes when possible and turn autocompacting on.
* only useful when autmatic shrinking is turned off.
* see cuckoo_reserve() about how turn shrinking off.
* @param self handle to the hash table
*/
int
cuckoo_compact (Cuckoo self);
/**
* Prereserve hash entries and turn autocompacting off.
* @param self handle to the hash table
* @param more number of entries to be additionally reserved
* In rare circumstances inserting into a hash which has reserved some entries
* it may still need to rehash (or even rarer) to grow the table.
* While autocompacting is turned off, removing is completely O(1).
*/
int
cuckoo_reserve (Cuckoo self, size_t more);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -39,7 +39,8 @@ extern "C" {
* Abort unconditionally with a 'Fatal Error!' message.
* This macro is used whenever the program end up in a invalid state from which no runtime recovery is possible
*/
#define LUMIERA_DIE do { NOBUG_ERROR(NOBUG_ON, "Fatal Error!"); abort(); } while(0)
#define LUMIERA_DIE(err) \
do { NOBUG_ERROR(NOBUG_ON, "Fatal Error: %s ", strchr(LUMIERA_ERROR_##err, ':')); abort(); } while(0)
/**
* Forward declare an error constant.
@ -58,7 +59,8 @@ extern const char* LUMIERA_ERROR_##err
#define LUMIERA_ERROR_DEFINE(err, msg) \
const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
/** Helper macro to raise an error for the current thread.
/**
* Helper macro to raise an error for the current thread.
* This macro eases setting an error. It adds NoBug logging support to the low level error handling.
* @param flag NoBug flag describing the subsystem where the error was raised
* @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY)

View file

@ -1,107 +0,0 @@
/*
framerate.h - framerate calculations
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_FRAMERATE_H
#define LUMIERA_FRAMERATE_H
#include <limits.h>
#include "lib/error.h"
/**
* @file Framerate calculations, header.
*/
/**
* framerates are defined as a rational number
* for example NTSC with 30000/1001fps
*/
struct lumiera_framerate_struct
{
unsigned n; //numerator
unsigned d; //denominator
};
typedef struct lumiera_framerate_struct lumiera_framerate;
typedef lumiera_framerate* LumieraFramerate;
typedef signed long lumiera_framepos;
LUMIERA_ERROR_DECLARE(FRAMERATE_ILLEGAL_TIME);
LUMIERA_ERROR_DECLARE(FRAMERATE_ILLEGAL_FRAME);
#define LUMIERA_FRAMEPOS_ERROR LONG_MIN
/**
* Get the frame number of a given time at a given frame rate.
* frame indexing starts with 1
* @param framerate is a pointer to the framerate used, defined as rational number. Must be given.
* @param time is a pointer to a lumiera_time which shall be converted.
* @return frame at the given time or LUMIERA_FRAMEPOS_ERROR on error.
*/
static inline lumiera_framepos
lumiera_framerate_frame_get_time (const LumieraFramerate framerate, LumieraTime time)
{
REQUIRE (framerate);
if (!time || time->tv_sec == (time_t)-1)
{
lumiera_error_set(LUMIERA_ERROR_FRAMERATE_ILLEGAL_TIME);
return LUMIERA_FRAMEPOS_ERROR;
}
/* we add a magic microsecond for rounding, because of integer truncation frames may be calculated at most 1us earlier,
the idea is to compensate odd framerates which fall out off microsecond precision.
*/
return ((time->tv_sec * 1000000ULL + time->tv_usec + /*magic*/1) * framerate->n)/(framerate->d * 1000000ULL) + 1;
}
/**
* Get the start time for a frame.
* frame indexing starts with 1
* @param framerate is a pointer to the framerate used, defined as rational number. Must be given.
* @param time is a pointer to a lumiera_time which shall take the result.
* @param frame frame number to be converted to time. This frame number must be greater than 0.
* @return the pointer given in time or NULL on error (or when it was given as time).
*/
static inline LumieraTime
lumiera_framerate_time_get_time_frame (const LumieraFramerate framerate,
LumieraTime time,
lumiera_framepos frame)
{
REQUIRE (framerate);
if (time)
{
if (frame < 1)
{
lumiera_error_set(LUMIERA_ERROR_FRAMERATE_ILLEGAL_FRAME);
return NULL;
}
unsigned long long usec = ((frame-1) * framerate->d * 1000000ULL - (/*magic*/frame>1?1:0)) / framerate->n;
time->tv_sec = usec / 1000000;
time->tv_usec = usec % 1000000;
}
return time;
}
#endif

View file

@ -88,6 +88,7 @@ typedef llist * LList;
typedef const llist * const_LList;
typedef llist ** LList_ref;
/**
* Macro to instantiate a local llist.
* @param name of the llist node
@ -95,6 +96,14 @@ typedef llist ** LList_ref;
#define LLIST_AUTO(name) llist name = {&name,&name}
/*
some macros for convenience
*/
#define llist_insert_head(list, element) llist_insert_next (list, element)
#define llist_insert_tail(list, element) llist_insert_prev (list, element)
#define llist_head llist_next
#define llist_tail llist_prev
/**
* cast back from a member of a structure to a pointer of the structure
*/
@ -129,6 +138,30 @@ typedef llist ** LList_ref;
! llist_is_end (node, list); \
llist_backward (&node))
/**
* Iterate forward over a range.
* @param start first node to be interated
* @param end node after the last node be iterated
* @param node pointer to the iterated node
*/
#define LLIST_FORRANGE(start, end, node) \
for (LList node = start; \
node != end; \
llist_forward (&node))
/**
* Iterate backward over a range.
* @param rstart first node to be interated
* @param rend node before the last node be iterated
* @param node pointer to the iterated node
*/
#define LLIST_FORRANGE_REV(rstart, rend, node) \
for (LList node = rstart; \
node != rend; \
llist_backward (&node))
/**
* Consume a list from head.
* The body of this statement should remove the head from the list, else it would be a infinite loop
@ -290,7 +323,7 @@ LLIST_FUNC (LList llist_insert_next (LList self, LList next),
/**
* Insert a node before another.
* @param self node before which we want to insert
* @param prev node which shall be inserted nefore self. Could already linked to a list from where it will be removed.
* @param prev node which shall be inserted before self. Could already linked to a list from where it will be removed.
* @return self
*/
LLIST_FUNC (LList llist_insert_prev (LList self, LList prev),
@ -314,10 +347,9 @@ LLIST_FUNC (LList llist_insertlist_next (LList self, LList next),
if (!llist_is_empty (next))
{
self->next->prev = next->prev;
self->next = next->next;
next->next->prev = self;
next->prev->next = self->next;
self->next = next->next;
next->next->prev = self;
next->prev = next->next = next;
}
@ -335,10 +367,9 @@ LLIST_FUNC (LList llist_insertlist_prev (LList self, LList prev),
if (!llist_is_empty (prev))
{
self->prev->next = prev->next;
self->prev = prev->prev;
prev->prev->next = self;
prev->next->prev = self->prev;
self->prev = prev->prev;
prev->prev->next = self;
prev->prev = prev->next = prev;
}
@ -494,20 +525,45 @@ LLIST_FUNC (LList llist_get_nth_stop (LList self, int n, const_LList stop),
return self;
);
/*
some macros for convenience
*/
#define llist_insert_head(list, element) llist_insert_next (list, element)
#define llist_insert_tail(list, element) llist_insert_prev (list, element)
#define llist_head llist_next
#define llist_tail llist_prev
/**
* Sort a list.
* @param self list to be sorted
* @param cmp function takeing 2 LLists
* simple recursive mergesort
*/
typedef int (*llist_cmpfn)(LList a, LList b);
LLIST_FUNC (LList llist_sort (LList self, llist_cmpfn cmp),
llist left;
llist right;
llist_init (&left);
llist_init (&right);
unsigned n = 0;
if (!llist_is_single (self))
{
LLIST_WHILE_HEAD (self, head)
llist_insert_prev (++n & 1 ? &left : &right, head);
llist_sort (&left, cmp);
llist_sort (&right, cmp);
while (!llist_is_empty (&left) && !llist_is_empty (&right))
llist_insert_prev (self, cmp (left.next, right.next) < 0 ? left.next : right.next);
if (!llist_is_empty (&left))
llist_insertlist_prev (self, &left);
if (!llist_is_empty (&right))
llist_insertlist_prev (self, &right);
}
return self;
)
#endif /* LLIST_H */
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// End:
// arch-tag: e8fe4a59-fd55-4c45-b860-5cd1e0771213
// end_of_file
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -28,6 +28,11 @@
#include "lib/error.h"
LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
/**
* @file Shared declarations for all locking primitives.
*/

67
src/lib/mrucache.c Normal file
View file

@ -0,0 +1,67 @@
/*
mrucache.h - most recent used cache
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 "lib/mrucache.h"
/**
* @file Most recent used cache
* Elements (addressed by a LList node) are either in the cache and thereby subject of aging
* or checked out under control of the user.
*/
LumieraMruCache
lumiera_mrucache_init (LumieraMruCache self, lumiera_cache_destructor_fn destructor_cb)
{
REQUIRE (self);
llist_init (&self->cache_list);
self->cached = 0;
self->destructor_cb = destructor_cb;
return self;
}
LumieraMruCache
lumiera_mrucache_destroy (LumieraMruCache self)
{
LLIST_WHILE_TAIL (&self->cache_list, node)
{
if (self->destructor_cb)
free (self->destructor_cb (node));
else
free (node);
}
self->cached = 0;
return self;
}
/**
* destroy and free the nelem oldest elements
*/
int
lumiera_mrucache_age (LumieraMruCache self, int nelem)
{
REQUIRE (self);
while (self->cached && nelem--)
free (lumiera_mrucache_pop (self));
return nelem;
}

119
src/lib/mrucache.h Normal file
View file

@ -0,0 +1,119 @@
/*
mrucache.h - most recent used cache
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_CACHE_H
#define LUMIERA_CACHE_H
#include "lib/llist.h"
#include <nobug.h>
/**
* @file Most recent used cache
* Elements (addressed by a LList node) are either in the cache and thereby subject of aging
* or checked out under control of the user.
*/
/**
* Callback function used to destruct/cleanup aged elements.
* shall clean the element sufficiently up to be ready for being freed or reused
* @param node the llist node used to link cache elements (will be empty at call)
* @return pointer to the begin of the element.
*/
typedef void* (*lumiera_cache_destructor_fn)(LList node);
struct lumiera_mrucache_struct
{
llist cache_list;
size_t cached;
lumiera_cache_destructor_fn destructor_cb;
};
typedef struct lumiera_mrucache_struct lumiera_mrucache;
typedef lumiera_mrucache* LumieraMruCache;
/**
* Initialize a mrucache
*/
LumieraMruCache
lumiera_mrucache_init (LumieraMruCache self, lumiera_cache_destructor_fn destructor_cb);
/**
* Destroy a mrucache
*/
LumieraMruCache
lumiera_mrucache_destroy (LumieraMruCache self);
/**
* add an element to a mrucache
*/
static inline void
lumiera_mrucache_add (LumieraMruCache self, LList node)
{
REQUIRE (self);
REQUIRE (node && llist_is_empty (node));
llist_insert_head (&self->cache_list, node);
++self->cached;
}
/**
* Remove an element from a mrucache.
*/
static inline void
lumiera_mrucache_remove (LumieraMruCache self, LList node)
{
REQUIRE (self);
REQUIRE (node && llist_is_member (&self->cache_list, node)); /* speedup loop warning :P, this check is costly */
llist_unlink (node);
--self->cached;
}
/**
* destroy the oldest element and return a pointer to it for reuse.
*/
static inline void*
lumiera_mrucache_pop (LumieraMruCache self)
{
REQUIRE (self);
if (llist_is_empty (&self->cache_list))
return NULL;
LList node = llist_tail (&self->cache_list);
llist_unlink (node);
--self->cached;
if (self->destructor_cb)
return self->destructor_cb (node);
else
return node;
}
/**
* destroy and free the nelem oldest elements
*/
int
lumiera_mrucache_age (LumieraMruCache self, int nelem);
#endif

View file

@ -25,6 +25,10 @@
* @file 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");
/**
* Initialize a mutex variable
@ -52,7 +56,7 @@ lumiera_mutex_destroy (LumieraMutex self)
if (self)
{
if (pthread_mutex_destroy (&self->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_DESTROY);
}
return self;
}

View file

@ -28,6 +28,12 @@
* @file Mutual exclusion locking, header.
*/
#define LUMIERA_MUTEX_SECTION(mutex) \
lumiera_mutexacquirer lock_##__LINE__##_; \
for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKED); \
lock_##__LINE__##_.state == LUMIERA_LOCKED; \
lumiera_mutexacquirer_unlock (&lock_##__LINE__##_))
/**
* Mutex.
@ -106,7 +112,7 @@ lumiera_mutexacquirer_init_mutex (LumieraMutexacquirer self, LumieraMutex mutex,
self->state = state;
if (state == LUMIERA_LOCKED)
if (pthread_mutex_lock (&mutex->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_LOCK);
return self;
}
@ -124,7 +130,7 @@ lumiera_mutexacquirer_lock (LumieraMutexacquirer self)
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
if (pthread_mutex_lock (&self->mutex->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_LOCK);
self->state = LUMIERA_LOCKED;
}
@ -164,7 +170,7 @@ lumiera_mutexacquirer_try_mutex (LumieraMutexacquirer self, LumieraMutex mutex)
case EBUSY:
return LUMIERA_UNLOCKED;
default:
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_LOCK);
}
}
@ -180,7 +186,7 @@ lumiera_mutexacquirer_unlock (LumieraMutexacquirer self)
REQUIRE (self);
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
if (pthread_mutex_unlock (&self->mutex->mutex))
LUMIERA_DIE;
LUMIERA_DIE (MUTEX_UNLOCK);
self->state = LUMIERA_UNLOCKED;
}

View file

@ -25,8 +25,10 @@
#include <dlfcn.h>
#include <pthread.h>
#include <time.h>
#include <limits.h>
#include "plugin.h"
#include "safeclib.h"
/**
* @file Plugin loader.
@ -159,8 +161,8 @@ lumiera_plugin_lookup (struct lumiera_plugin* self, const char* path)
{
/* got it */
TRACE (lumiera_plugin, "found %s", pathname);
self->pathname = strdup (pathname);
if (!self->pathname) LUMIERA_DIE;
self->pathname = lumiera_strndup (pathname, PATH_MAX);
self->type = lumiera_plugin_extensions[i].type;
return 0;
}
@ -195,21 +197,20 @@ lumiera_interface_open (const char* name, const char* interface, size_t min_revi
plugin.name = name; /* for searching */
found = tsearch (&plugin, &lumiera_plugin_registry, lumiera_plugin_name_cmp);
if (!found) LUMIERA_DIE;
if (!found)
LUMIERA_DIE (NO_MEMORY);
if (*found == &plugin)
{
NOTICE (lumiera_plugin, "new plugin");
/* now really create new item */
*found = malloc (sizeof (struct lumiera_plugin));
if (!*found) LUMIERA_DIE;
*found = lumiera_malloc (sizeof (struct lumiera_plugin));
if (name) /* NULL is main app, no lookup needed */
{
/*lookup for $LUMIERA_PLUGIN_PATH*/
(*found)->name = strdup (name);
if (!(*found)->name) LUMIERA_DIE;
(*found)->name = lumiera_strndup (name, PATH_MAX);
if (!!lumiera_plugin_lookup (*found, getenv("LUMIERA_PLUGIN_PATH"))
#ifdef LUMIERA_PLUGIN_PATH

View file

@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/references.h"
#include "lib/safeclib.h"
/**
* @file Strong and Weak references
@ -43,8 +44,7 @@
LumieraReference
lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*))
{
LumieraReftarget target = malloc (sizeof(lumiera_reftarget));
if (!target) LUMIERA_DIE;
LumieraReftarget target = lumiera_malloc (sizeof(lumiera_reftarget));
target->object = obj;
target->dtor = dtor;

View file

@ -25,6 +25,10 @@
LUMIERA_ERROR_DEFINE(RWLOCK_AGAIN, "maximum number of readlocks exceed");
LUMIERA_ERROR_DEFINE(RWLOCK_DEADLOCK, "deadlock detected");
LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroy rwlock");
LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock");
LUMIERA_ERROR_DEFINE(RWLOCK_RLOCK, "rlock");
LUMIERA_ERROR_DEFINE(RWLOCK_WLOCK, "wlock");
/**
* @file Read/write locks.
@ -57,7 +61,7 @@ lumiera_rwlock_destroy (LumieraRWLock self)
if (self)
{
if (pthread_rwlock_destroy (&self->rwlock))
LUMIERA_DIE;
LUMIERA_DIE (RWLOCK_DESTROY);
}
return self;
}
@ -95,7 +99,7 @@ lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, e
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE;
LUMIERA_DIE (RWLOCK_RLOCK);
}
case LUMIERA_WRLOCKED:
switch (pthread_rwlock_wrlock (&rwlock->rwlock))
@ -106,7 +110,7 @@ lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, e
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE;
LUMIERA_DIE (RWLOCK_WLOCK);
}
default:
break;
@ -138,7 +142,7 @@ lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self)
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE;
LUMIERA_DIE (RWLOCK_RLOCK);
}
self->state = LUMIERA_RDLOCKED;
@ -166,7 +170,7 @@ lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self)
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE;
LUMIERA_DIE (RWLOCK_WLOCK);
}
self->state = LUMIERA_WRLOCKED;

View file

@ -33,6 +33,10 @@
LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN);
LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY);
LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
/**
* @file Read/write locks, header.
@ -106,7 +110,7 @@ lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self)
REQUIRE (self);
REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked");
if (pthread_rwlock_unlock (&self->rwlock->rwlock))
LUMIERA_DIE;
LUMIERA_DIE (RWLOCK_UNLOCK);
self->state = LUMIERA_UNLOCKED;
}

214
src/lib/safeclib.c Normal file
View file

@ -0,0 +1,214 @@
/*
safe_clib.c - Portable and safe wrapers around some clib functions and some tools
Copyright (C) CinelerraCV
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.
*/
#define _GNU_SOURCE
#include "error.h"
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <stdarg.h>
/**
* @file Portable and safe wrapers around some clib functions and some tools
*/
LUMIERA_ERROR_DEFINE (NO_MEMORY, "Out of Memory!");
/**
* Allocate memory.
* always succeeds or dies
* @param size memory to be allocated
* @return pointer to the allocated memory
*/
void*
lumiera_malloc (size_t sz)
{
void* o = sz? malloc (sz) : NULL;
if (!o)
LUMIERA_DIE (NO_MEMORY);
return o;
}
/**
* Duplicate a C string.
* always succeeds or dies
* @param str string to be copied
* @param len maximal length to be copied
* @return pointer to the new string, "" if NULL was passed as str
*/
char*
lumiera_strndup (const char* str, size_t len)
{
char* o;
if (str)
o = strndup (str, len);
else
o = strdup ("");
if (!o)
LUMIERA_DIE (NO_MEMORY);
return o;
}
/**
* Compare two C strings.
* Handles NULL pointers as "", shortcut for same addresses
* @param a first string for comparsion
* @param b second string for comparsion
* @param len maximal length for the comparsion
* @return 0 if the strings are identical, -1 if smaller 1 if bigger.
*/
int
lumiera_strncmp (const char* a, const char* b, size_t len)
{
return a == b ? 0 : strncmp (a?a:"", b?b:"", len);
}
/**
* check 2 strings for identity.
* @param a first string for comparsion
* @param b second string for comparsion
* @return 1 when the strings are the the same, 0 if not.
*/
int
lumiera_streq (const char* a, const char* b)
{
return !lumiera_strncmp (a, b, SIZE_MAX);
}
/**
* Round robin temporary buffers.
* This provides 64 buffers per thread which are recycled with each use.
* The idea here is to have fast buffers for temporal data without need for explicit heap management.
*/
struct lumiera_tmpbuf_struct
{
void* buffers[64];
size_t sizes[64];
unsigned idx;
};
static pthread_once_t lumiera_tmpbuf_tls_once = PTHREAD_ONCE_INIT;
static pthread_key_t lumiera_tmpbuf_tls_key;
void
lumiera_tmpbuf_freeall (void);
static void
lumiera_tmpbuf_destroy (void* buf)
{
lumiera_tmpbuf_freeall ();
free (buf);
}
static void
lumiera_tmpbuf_init (void)
{
pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy);
}
/**
* free all buffers associated with this thread.
* This function is called automatically, usually one doesnt need to call it.
*/
void
lumiera_tmpbuf_freeall (void)
{
pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init);
struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key);
if (!buf)
pthread_setspecific (lumiera_tmpbuf_tls_key,
buf = lumiera_malloc (sizeof (struct lumiera_tmpbuf_struct)));
for (buf->idx = 0; buf->idx < 64; ++buf->idx)
{
free (buf->buffers[buf->idx]);
buf->buffers[buf->idx] = NULL;
buf->sizes[buf->idx] = 0;
}
buf->idx = 0;
}
/**
* Query a thread local buffer.
* @param size minimal needed size for the buffer
* @return the buffer
*/
void*
lumiera_tmpbuf_provide (size_t size)
{
pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init);
struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key);
if (!buf)
pthread_setspecific (lumiera_tmpbuf_tls_key,
buf = lumiera_malloc (sizeof (struct lumiera_tmpbuf_struct)));
buf->idx = (buf->idx + 1) & 0x3f;
if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size)
{
free (buf->buffers[buf->idx]);
buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1);
buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]);
}
return buf->buffers[buf->idx];
}
char*
lumiera_tmpbuf_strndup (const char* src, size_t size)
{
size_t len = strlen (src);
len = len > size ? size : len;
char* buf = lumiera_tmpbuf_provide (len + 1);
strncpy (buf, src, len);
buf[len] = '\0';
return buf;
}
char*
lumiera_tmpbuf_sprintf (size_t size, const char* fmt, ...)
{
va_list args;
va_start (args, fmt);
size_t len = vsnprintf (NULL, 0, fmt, args);
va_end (args);
len = len > size ? size : len;
char* buf = lumiera_tmpbuf_provide (len);
va_start (args, fmt);
vsnprintf (buf, len, fmt, args);
va_end (args);
return buf;
}

114
src/lib/safeclib.h Normal file
View file

@ -0,0 +1,114 @@
/*
safe_clib.h - Portable and safe wrapers around some clib functions and some tools
Copyright (C) CinelerraCV
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 "error.h"
#include <stdlib.h>
/**
* @file Portable and safe wrapers around some clib functions and some tools
*/
LUMIERA_ERROR_DECLARE(NO_MEMORY);
/**
* Allocate memory.
* always succeeds or dies
* @param size memory to be allocated
* @return pointer to the allocated memory
*/
void*
lumiera_malloc (size_t sz);
/**
* Duplicate a C string.
* always succeeds or dies
* @param str string to be copied
* @param len maximal length to be copied
* @return pointer to the new string, "" if NULL was passed as str
*/
char*
lumiera_strndup (const char* str, size_t len);
/**
* Compare two C strings.
* Handles NULL pointers as "", shortcut for same addresses
* @param a first string for comparsion
* @param b second string for comparsion
* @param len maximal length for the comparsion
* @return 0 if the strings are identical, -1 if smaller 1 if bigger.
*/
int
lumiera_strncmp (const char* a, const char* b, size_t len);
/**
* check 2 strings for identity.
* @param a first string for comparsion
* @param b second string for comparsion
* @return 1 when the strings are the the same, 0 if not.
*/
int
lumiera_streq (const char* a, const char* b);
/**
* Round robin temporary buffers.
* This provides 64 buffers per thread which are recycled with each use.
* The idea here is to have fast buffers for temporal data without need for explicit heap management.
*/
/**
* free all buffers associated with this thread.
* This function is called automatically, usually one doesnt need to call it.
*/
void
lumiera_tmpbuf_freeall (void);
/**
* Query a thread local tmpbuf.
* @param size minimal needed size for the tmpbuf
* @return the tmpbuf
*/
void*
lumiera_tmpbuf_provide (size_t size);
/**
* Duplicate string to a tmpbuf.
* @param src string to be duplicated
* @param size maximal length to be copied
* @return temporary buffer containing a copy of the string
*/
char*
lumiera_tmpbuf_strndup (const char* src, size_t size);
/**
* Construct a string in a tmpbuf.
* @param size maximal length for the string
* @param fmt printf like formatstring
* @param ... parameters
* @return temporary buffer containing the constructed of the string
*/
char*
lumiera_tmpbuf_sprintf (size_t size, const char* fmt, ...);

95
src/lib/uuid.c Normal file
View file

@ -0,0 +1,95 @@
/*
uuid - Universal unique identifiers
Copyright (C) CinelerraCV
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 "lib/uuid.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
void
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr)
{
memset (uuid, 0, 16);
*(void**)uuid = ptr;
}
void*
lumiera_uuid_ptr_get (lumiera_uuid* uuid)
{
return *(void**)uuid;
}
void
lumiera_uuid_gen (lumiera_uuid* uuid)
{
static int fd = -2;
if (!uuid)
return;
if (fd == -2)
{
fd = open ("/dev/urandom", O_RDONLY);
if (fd == -1)
fd = open ("/dev/random", O_RDONLY);
if (fd >= 0)
fcntl (fd, F_SETFD, FD_CLOEXEC);
else
srand (getpid () + time (NULL));
}
if (fd < 0)
{
for (int i = 0; i < 16; ++i)
((unsigned char*)uuid)[i] = (unsigned char)(rand()>>7);
}
else
{
if (read (fd, uuid, 16) < 0)
abort ();
}
}
void
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src)
{
memcpy (dest, src, 16);
}
int
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb)
{
return !memcmp (uuida, uuidb, 16);
}
size_t
lumiera_uuid_hash (lumiera_uuid* uuid)
{
return *(size_t*)uuid;
}

67
src/lib/uuid.h Normal file
View file

@ -0,0 +1,67 @@
/*
uuid - Universal unique identifiers
Copyright (C) CinelerraCV
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_UUID_H
#define LUMIERA_UUID_H
#include <stdlib.h>
typedef unsigned char lumiera_uuid[16];
/**
* Retrieve a generic pointer stored in a uuid
*/
void*
lumiera_uuid_ptr_get (lumiera_uuid* uuid);
/**
* Generate a new uuid
*/
void
lumiera_uuid_gen (lumiera_uuid* uuid);
/**
* Store a generic pointer in a uuid
*/
void
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr);
/**
* Copy an uuid
*/
void
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src);
/**
* Test 2 uuid's for equality
*/
int
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb);
/**
* Generate a hashsum over an uuid
*/
size_t
lumiera_uuid_hash (lumiera_uuid* uuid);
#endif

28
tests/15safeclib.tests Normal file
View file

@ -0,0 +1,28 @@
TESTING "Safe clib and tools" ./test-safeclib
TEST "Allocating 0 bytes" allocation0 <<END
return: 134
END
TEST "Allocating some memory" allocation1024 <<END
return: 0
END
TEST "Allocation error" allocationtoobig <<END
return: 134
END
TEST "string equal check" streq <<END
return: 0
END
TEST "temporary buffers" tmpbuf <<END
return: 0
END

15
tests/15uuid.tests Normal file
View file

@ -0,0 +1,15 @@
TESTING "UUID's" ./test-uuid
TEST "uuid generate" uuidgen_2 <<END
out: 0
END
TEST "uuid copy" uuidgen_copy <<END
out: 1
END
TEST "storing pointers" ptrs <<END
out: 1
END

View file

@ -36,6 +36,16 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c
test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
test_llist_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm
check_PROGRAMS += test-safeclib
test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c
test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
test_safeclib_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm
check_PROGRAMS += test-uuid
test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c
test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
test_uuid_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm
check_PROGRAMS += test-references
test_references_SOURCES = $(tests_srcdir)/library/test-references.c
test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/

View file

@ -23,173 +23,166 @@
//#include <string.h>
#include "lib/llist.h"
#include "lib/error.h"
#include "tests/test.h"
TESTS_BEGIN
LUMIERA_ERROR_DEFINE(TEST, "test error");
int
main (int argc, char** argv)
TEST ("basic")
{
NOBUG_INIT;
LLIST_AUTO (node1);
if (argc == 1)
return 0;
llist node2;
llist_init (&node2);
if (!strcmp(argv[1], "basic"))
{
LLIST_AUTO (node1);
llist node2;
llist_init (&node2);
printf ("%d\n", llist_is_empty (&node1));
printf ("%d\n", llist_is_empty (&node2));
}
else if (!strcmp(argv[1], "nodeinsert"))
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
llist_insert_next (&list, &node1);
printf ("%d\n", llist_is_empty (&list));
printf ("%d\n", llist_is_empty (&node1));
printf ("%d\n", llist_is_single (&node1));
llist_insert_next (&node1, &node2);
printf ("%d\n", llist_is_single (&node1));
llist_insert_prev (&node1, &node3);
printf ("%d\n", llist_next (&list) == &node3);
printf ("%d\n", llist_next (&node3) == &node1);
printf ("%d\n", llist_next (&node1) == &node2);
printf ("%d\n", llist_prev (&list) == &node2);
printf ("%d\n", llist_count (&list));
}
else if (!strcmp(argv[1], "predicates"))
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
LLIST_AUTO (node4);
LLIST_AUTO (nil);
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
printf ("%d\n", llist_is_head (&list, &node1));
printf ("%d\n", llist_is_tail (&list, &node4));
printf ("%d\n", llist_is_head (&list, &node4));
printf ("%d\n", llist_is_tail (&list, &node1));
printf ("%d\n", llist_is_end (&list, &list));
printf ("%d\n", llist_is_member (&list, &node3));
printf ("%d\n", llist_is_member (&list, &nil));
printf ("%d\n", llist_is_before_after (&list, &node1, &node3));
printf ("%d\n", llist_is_before_after (&list, &node3, &node1));
printf ("%d\n", llist_is_before_after (&list, &node1, &nil));
}
else if (!strcmp(argv[1], "unlink"))
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
LLIST_AUTO (node4);
LLIST_AUTO (nil);
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
LLIST_FOREACH_REV (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
llist_unlink (&nil);
llist_unlink (&node2);
llist_unlink (&node3);
LLIST_FOREACH (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
printf ("%d\n", llist_is_empty (&node2));
printf ("%d\n", llist_is_empty (&node3));
printf ("%d\n", llist_is_empty (&nil));
}
else if (!strcmp(argv[1], "whiles"))
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
LLIST_AUTO (node4);
LLIST_AUTO (nil);
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
LLIST_FOREACH_REV (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
LLIST_WHILE_HEAD (&list, head)
llist_unlink (head);
LLIST_FOREACH (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
LLIST_WHILE_TAIL (&list, tail)
llist_unlink (tail);
LLIST_FOREACH (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
}
else
return 1;
return 0;
printf ("%d\n", llist_is_empty (&node1));
printf ("%d\n", llist_is_empty (&node2));
}
TEST ("nodeinsert")
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
llist_insert_next (&list, &node1);
printf ("%d\n", llist_is_empty (&list));
printf ("%d\n", llist_is_empty (&node1));
printf ("%d\n", llist_is_single (&node1));
llist_insert_next (&node1, &node2);
printf ("%d\n", llist_is_single (&node1));
llist_insert_prev (&node1, &node3);
printf ("%d\n", llist_next (&list) == &node3);
printf ("%d\n", llist_next (&node3) == &node1);
printf ("%d\n", llist_next (&node1) == &node2);
printf ("%d\n", llist_prev (&list) == &node2);
printf ("%d\n", llist_count (&list));
}
TEST ("predicates")
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
LLIST_AUTO (node4);
LLIST_AUTO (nil);
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
printf ("%d\n", llist_is_head (&list, &node1));
printf ("%d\n", llist_is_tail (&list, &node4));
printf ("%d\n", llist_is_head (&list, &node4));
printf ("%d\n", llist_is_tail (&list, &node1));
printf ("%d\n", llist_is_end (&list, &list));
printf ("%d\n", llist_is_member (&list, &node3));
printf ("%d\n", llist_is_member (&list, &nil));
printf ("%d\n", llist_is_before_after (&list, &node1, &node3));
printf ("%d\n", llist_is_before_after (&list, &node3, &node1));
printf ("%d\n", llist_is_before_after (&list, &node1, &nil));
}
TEST ("unlink")
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
LLIST_AUTO (node4);
LLIST_AUTO (nil);
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
LLIST_FOREACH_REV (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
llist_unlink (&nil);
llist_unlink (&node2);
llist_unlink (&node3);
LLIST_FOREACH (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
printf ("%d\n", llist_is_empty (&node2));
printf ("%d\n", llist_is_empty (&node3));
printf ("%d\n", llist_is_empty (&nil));
}
TEST ("whiles")
{
LLIST_AUTO (list);
LLIST_AUTO (node1);
LLIST_AUTO (node2);
LLIST_AUTO (node3);
LLIST_AUTO (node4);
LLIST_AUTO (nil);
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
LLIST_FOREACH_REV (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
LLIST_WHILE_HEAD (&list, head)
llist_unlink (head);
LLIST_FOREACH (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
llist_insert_tail (&list, &node2);
llist_insert_tail (&list, &node3);
llist_insert_tail (&list, &node4);
llist_insert_head (&list, &node1);
LLIST_WHILE_TAIL (&list, tail)
llist_unlink (tail);
LLIST_FOREACH (&list, itr)
{
if(itr == &node1) printf ("node1 ");
else if(itr == &node2) printf ("node2 ");
else if(itr == &node3) printf ("node3 ");
else if(itr == &node4) printf ("node4 ");
else printf ("unknown ");
}
printf (".\n");
}
TESTS_END

View file

@ -0,0 +1,85 @@
/*
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 "lib/safeclib.h"
#include "tests/test.h"
#include <sys/time.h>
#include <sys/resource.h>
TESTS_BEGIN
TEST ("allocation0")
{
lumiera_malloc (0);
NOTREACHED;
}
TEST ("allocation1024")
{
void* data[1024];
for (int i = 0; i < 1024; ++i)
{
data[i] = lumiera_malloc (1024);
ENSURE (data[i]);
}
for (int i = 0; i < 1024; ++i)
{
free (data[i]);
}
}
TEST ("allocationtoobig")
{
struct rlimit rl;
rl.rlim_cur = 100*1024*1024;
rl.rlim_max = 100*1024*1024;
setrlimit (RLIMIT_AS, &rl);
lumiera_malloc (200*1024*1024);
NOTREACHED;
}
TEST ("streq")
{
if (!lumiera_streq ("foo", "foo"))
LUMIERA_DIE (TEST);
if (!lumiera_streq (NULL, NULL))
LUMIERA_DIE (TEST);
if (!!lumiera_streq (NULL, "foo"))
LUMIERA_DIE (TEST);
if (!!lumiera_streq ("foo", NULL))
LUMIERA_DIE (TEST);
if (!!lumiera_streq ("foo", "bar"))
LUMIERA_DIE (TEST);
}
TEST ("tmpbuf")
{
for (int i = 0; i < 256; ++i)
{
char* buf = lumiera_tmpbuf_provide (1024);
for (int j = 0; j < 1024; ++j)
{
buf[j] = i;
}
}
}
TESTS_END

73
tests/library/test-uuid.c Normal file
View file

@ -0,0 +1,73 @@
/*
test-uuid.c - test the uuid lib
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 "cinelerra-config.h"
//#include <stdio.h>
#include "lib/uuid.h"
#include <nobug.h>
//CINELERRA_ERROR_DEFINE(TEST, "test error");
int
main (int argc, char** argv)
{
NOBUG_INIT;
if (argc == 1)
return 0;
if (!strcmp(argv[1], "uuidgen_2"))
{
lumiera_uuid uuid1;
lumiera_uuid uuid2;
lumiera_uuid_gen (&uuid1);
lumiera_uuid_gen (&uuid2);
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
}
else if (!strcmp(argv[1], "uuidgen_copy"))
{
lumiera_uuid uuid1;
lumiera_uuid uuid2;
lumiera_uuid_gen (&uuid1);
lumiera_uuid_copy (&uuid2, &uuid1);
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
}
else if (!strcmp(argv[1], "ptrs"))
{
lumiera_uuid uuid;
lumiera_uuid_set_ptr (&uuid, &uuid);
printf ("%d\n", lumiera_uuid_ptr_get (&uuid) == &uuid);
}
else
return 1;
return 0;
}

View file

@ -21,33 +21,21 @@
#include <stdio.h>
#include <string.h>
#include "lib/error.h"
LUMIERA_ERROR_DEFINE(TEST, "test error");
#include "tests/test.h"
int conditionforgotunlock ();
int mutexforgotunlock ();
TESTS_BEGIN
int
main (int argc, char** argv)
TEST ("conditionforgotunlock")
{
NOBUG_INIT;
if (argc == 1)
return 0;
if (!strcmp(argv[1], "conditionforgotunlock"))
{
return conditionforgotunlock ();
}
if (!strcmp(argv[1], "mutexforgotunlock"))
{
return mutexforgotunlock ();
}
else
return 1;
return 0;
return conditionforgotunlock ();
}
TEST ("mutexforgotunlock")
{
return mutexforgotunlock ();
}
TESTS_END

View file

@ -3,6 +3,7 @@
#include "lib/plugin.h"
#include "hello_interface.h"
LUMIERA_ERROR_DEFINE(FAILURE, "test failure");
int
main(int argc, char** argv)
@ -25,7 +26,7 @@ main(int argc, char** argv)
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_de =
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin", "german_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
if (!hello_de) LUMIERA_DIE;
if (!hello_de) LUMIERA_DIE (FAILURE);
hello_de->hello();
hello_de->goodbye(argv[1]);
@ -33,7 +34,7 @@ main(int argc, char** argv)
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_en =
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin", "english_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
if (!hello_en) LUMIERA_DIE;
if (!hello_en) LUMIERA_DIE (FAILURE);
hello_en->hello();
hello_en->goodbye(argv[1]);
@ -48,7 +49,7 @@ main(int argc, char** argv)
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_de =
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin_cpp", "german_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
if (!hello_de) LUMIERA_DIE;
if (!hello_de) LUMIERA_DIE (FAILURE);
hello_de->hello();
hello_de->goodbye(argv[1]);
@ -56,7 +57,7 @@ main(int argc, char** argv)
LUMIERA_INTERFACE_TYPE(hello, 1)* hello_en =
(LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin_cpp", "english_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1)));
if (!hello_en) LUMIERA_DIE;
if (!hello_en) LUMIERA_DIE (FAILURE);
hello_en->hello();
hello_en->goodbye(argv[1]);

52
tests/test.h Normal file
View file

@ -0,0 +1,52 @@
/*
test.h - macros for running tests
Copyright (C) CinelerraCV
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 TEST_H
#define TEST_H
#include <nobug.h>
#include "lib/error.h"
LUMIERA_ERROR_DEFINE (TEST, "test error");
#define TESTS_BEGIN \
int \
main (int argc, char** argv) \
{ \
NOBUG_INIT; \
\
if (argc == 1) \
return 1;
#define TEST(name) \
else if (!strcmp(argv[1], name))
#define TESTS_END \
else \
return 1; \
\
return 0; \
}
#endif

View file

@ -2104,13 +2104,26 @@ if (oldText.indexOf(&quot;SplashScreen&quot;)==-1)
}
//}}}</pre>
</div>
<div title="StyleGuide" modifier="CehTeh" modified="200803261336" created="200803261258" changecount="4">
<div title="StyleGuide" modifier="CehTeh" modified="200803261924" created="200803261258" changecount="6">
<pre>! Source code formatting
http://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting
We decided to use the 'gnu-style' for indenting (using spaces and never tabs!):
http://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting
It is reasonable to be relaxed about soem formatting rules:
* line length might be longer when required
* inter expession spacing can be changed to the actual needed ex: (2*x + 2)
Things we are pedantic about:
* use never ever tab characters in C/C++ sources
* be consistent
* source files should end with a newline
* no trailing or bogus whitespaces
! Coding Practices
! Writing Tests
! Contibuting
! Tests
</pre>
</div>
<div title="StyleSheet" modifier="CehTeh" modified="200706090017" created="200701131624" tags="MPTWTheme" server.type="file" server.host="file:///home/ct/.homepage/home.html" server.page.revision="200706090017">

View file

@ -930,11 +930,10 @@ git push git://git.pipapo.org/lumiera/mob
lumiera/mob is an anonymous account at pipapo.org where everyone can commit changes. </pre>
</div>
<div title="IRC-Transcripts" modifier="Ichthyostega" modified="200804120322" created="200708120209" tags="discuss irclog" changecount="8">
<div title="IRC-Transcripts" modifier="CehTeh" modified="200803262159" created="200708120209" tags="discuss irclog" changecount="8">
<pre>We keep a protocol or short summary of each important discussion. The summaries of the monthly developer meetings are posted to the Mailinglist and can be found on pipapo.org too
* [[04-08 developer meeting 3.Apr.2008|IRC_2008-04-03]]
* [[03-08 developer meeting 6.Mar.2008|IRC_2008-03-06]]
* [[2.official developer meeting 6.March.2008|IRC_2008-03-06]]
* [[1.official developer meeting 1.Feb.2008|IRC_2008-02-01]]
* [[informal developer meeting 10.Aug.2007|IRC_2007-08-10]]
</pre>
@ -1807,17 +1806,16 @@ Wiki works. It is simple to use and just flexible enough to handle the task. I d
Please __end your tiddlers in a newline__, this makes merging in git easier since the /pre tag used in tiddlywiki will become on a single line.
----
!Architecture and Subsystems
!Design Draft
to get started, we create design drafts emphasizing different aspects and regions of Lumiera
* Cehteh works on the data backend, see [[this page|backend.html]]
* Ichthyo focuses mainly on Edit operations and Builder, [[see this separate page|renderengine.html]]
* Gmerlin is in charge of [[GAVL|http://gmerlin.sourceforge.net/gavl.html]] for processing of video data
* as of 4/08 a GuiWorkingGroup is emerging...
* Ichthyo focuses mainly on the Render Engine and its interconnection to the EDL, [[see this separate page|renderengine.html]]
* Cehteh works on the data backend draft, see [[this page|backend.html]]
* Some tools which don't fit somewhere else and are used everywhere are put into a [[Support Library|support_library.html]]
* [[Description of the Test System|TestSh]]
!Coding &amp;mdash; Building &amp;mdash; Testing
how to organize several aspects of the practical coding...
!Coding Structures
next we should //start thinking// on how to organize several aspects of the practical coding...
* what to do in BOUML? &amp;rarr; [[more|whatInBOUML]]
* how to organize packages, files, includes? &amp;rarr; [[more|SrcTreeStructure]]
* how to organize the executable to be built?