merge from backend (plugin loader)

Merge commit 'lumi/master' into proc
This commit is contained in:
Fischlurch 2008-10-16 00:35:57 +02:00
commit d64d822690
38 changed files with 2609 additions and 123 deletions

View file

@ -62,7 +62,6 @@ include $(top_srcdir)/icons/Makefile.am
include $(top_srcdir)/tests/common/Makefile.am
include $(top_srcdir)/tests/components/Makefile.am
include $(top_srcdir)/tests/Makefile.am
include $(top_srcdir)/tests/plugin/Makefile.am
#EXTRA_DIST += admin debian doc depcomp README.BUILD LICENSE \
# cinelerra-cvs-current.spec

View file

@ -1,5 +1,5 @@
AC_INIT(lumiera, 0.1pre)
AC_CONFIG_SRCDIR(src/lib/plugin.c)
AC_CONFIG_SRCDIR(src/lib/luid.c)
AC_CONFIG_AUX_DIR(scripts)
AM_INIT_AUTOMAKE
AC_PREREQ(2.59)

View file

@ -18,7 +18,7 @@
liblumibackend_a_srcdir = $(top_srcdir)/src/backend
noinst_LIBRARIES += liblumibackend.a
liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wextra -Wall -Werror
liblumibackend_a_SOURCES = \
$(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \
@ -27,10 +27,13 @@ liblumibackend_a_SOURCES = \
$(liblumibackend_a_srcdir)/filehandle.c \
$(liblumibackend_a_srcdir)/filedescriptor.c \
$(liblumibackend_a_srcdir)/filehandlecache.c \
$(liblumibackend_a_srcdir)/interface.c \
$(liblumibackend_a_srcdir)/interfaceregistry.c \
$(liblumibackend_a_srcdir)/config.c \
$(liblumibackend_a_srcdir)/config_typed.c \
$(liblumibackend_a_srcdir)/config_wordlist.c \
$(liblumibackend_a_srcdir)/configentry.c \
$(liblumibackend_a_srcdir)/configitem.c \
$(liblumibackend_a_srcdir)/configitem.c \
$(liblumibackend_a_srcdir)/config_lookup.c
@ -41,8 +44,11 @@ noinst_HEADERS += \
$(liblumibackend_a_srcdir)/filehandle.h \
$(liblumibackend_a_srcdir)/filedescriptor.h \
$(liblumibackend_a_srcdir)/filehandlecache.h \
$(liblumibackend_a_srcdir)/interface.h \
$(liblumibackend_a_srcdir)/interfaceregistry.h \
$(liblumibackend_a_srcdir)/interfacedescriptor.h \
$(liblumibackend_a_srcdir)/config.h \
$(liblumibackend_a_srcdir)/configentry.h \
$(liblumibackend_a_srcdir)/configitem.h \
$(liblumibackend_a_srcdir)/configitem.h \
$(liblumibackend_a_srcdir)/config_lookup.h

View file

@ -111,7 +111,7 @@ lumiera_config_init (const char* path)
lumiera_configitem_init (&lumiera_global_config->files);
lumiera_configitem_init (&lumiera_global_config->TODO_unknown);
lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config));
lumiera_mutex_init (&lumiera_global_config->lock, "config mutex", &NOBUG_FLAG (config));
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "config.path = %s", path));
@ -130,7 +130,7 @@ lumiera_config_destroy ()
TRACE (config);
if (lumiera_global_config)
{
lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config));
lumiera_mutex_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config));
lumiera_configitem_destroy (&lumiera_global_config->defaults, &lumiera_global_config->keys);
lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys);
lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys);
@ -146,6 +146,7 @@ lumiera_config_destroy ()
int
lumiera_config_load (const char* file)
{
(void) file;
TRACE (config);
UNIMPLEMENTED();
return -1;
@ -164,6 +165,7 @@ lumiera_config_save ()
int
lumiera_config_purge (const char* filename)
{
(void) filename;
TRACE (config);
UNIMPLEMENTED();
@ -290,7 +292,7 @@ lumiera_config_setdefault (const char* line)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config, &lumiera_global_config->lock)
{
const char* key = line;
while (*key && isspace (*key))
@ -342,6 +344,7 @@ lumiera_config_dump (FILE* out)
int
lumiera_config_reset (const char* key)
{
(void) key;
TRACE (config);
UNIMPLEMENTED();
return -1;
@ -351,6 +354,9 @@ lumiera_config_reset (const char* key)
int
lumiera_config_info (const char* key, const char** filename, unsigned* line)
{
(void) key;
(void) filename;
(void) line;
TRACE (config);
UNIMPLEMENTED();
return -1;

View file

@ -24,7 +24,7 @@
//TODO: Support library includes//
#include "lib/error.h"
#include "lib/rwlock.h"
#include "lib/mutex.h"
//TODO: Forward declarations//
struct lumiera_config_struct;
@ -74,14 +74,7 @@ struct lumiera_config_struct
lumiera_configitem files; /* all loaded files */
lumiera_configitem TODO_unknown; /* all values which are not part of a file and not default TODO: this will be removed when file support is finished */
/*
all access is protected with rwlock's.
We use rwlocks here since concurrent reads are likely common.
So far this is a global config lock, if this is a problem we might granularize it by locking on a file level.
config access is not planned to be transactional yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair
*/
lumiera_rwlock lock;
lumiera_mutex lock;
};
typedef struct lumiera_config_struct lumiera_config;
@ -96,6 +89,7 @@ typedef lumiera_config* LumieraConfig;
LUMIERA_CONFIG_TYPE(number, signed long long) \
LUMIERA_CONFIG_TYPE(real, long double) \
LUMIERA_CONFIG_TYPE(string, const char*) \
LUMIERA_CONFIG_TYPE(wordlist, const char*) \
LUMIERA_CONFIG_TYPE(word, const char*) \
LUMIERA_CONFIG_TYPE(bool, int)
@ -197,7 +191,7 @@ lumiera_config_set (const char* key, const char* delim_value);
* Installs a default value for a config key.
* Any key might have an associated default value which is used when
* no other configuration is available, this can be set once.
* Any subsequent call will be a no-op. This function writelocks the config system.
* Any subsequent call will be a no-op. This function locks the config system.
* @param line line with key, delimiter and value to store as default value
* @return NULL in case of an error, else a pointer to the default configitem
*/
@ -223,7 +217,57 @@ lumiera_config_setdefault (const char* line);
LUMIERA_CONFIG_TYPES
#undef LUMIERA_CONFIG_TYPE
/**
* Wordlists
* Wordlists are lists of single words delimited by any of " \t,;".
* They can be used to store groups of keys and other kinds of simple references into the config
* system. Here are some functions to manipulate single word entries in a wordlist.
*/
/**
* Get nth word of a wordlist.
* @param key key under which this wordlist is stored
* @param nth index of the word to get, starting with 0
* @return pointer to a tempbuf holding the nth word or NULL in case of error
*/
const char*
lumiera_config_wordlist_get_nth (const char* key, unsigned nth);
/**
* Find the index of a word in a wordlist.
* @param key key under which this wordlist is stored
* @param value word to find
* @return index of the first occurence of the word or -1 in case of failure
*/
int
lumiera_config_wordlist_find (const char* key, const char* value);
/**
* Universal word replacement function.
* Replaces a word with up to two new words. This can be used to delete a word (no replacements),
* insert a new word before an existing word (giving the new word as subst1 and the old word as subst2)
* insert a new word after an existing word (giving the old word as subst1 and the new word as subst2)
* or simply give 2 new words.
* @param key key under which this wordlist is stored
* @param value word to be replaced
* @param subst1 first replacement word
* @param subst2 second replacement word
* @return internal representation of the wordlist in a tmpbuf or NULL in case of an error
*/
const char*
lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2);
/**
* Add a word to the end of a wordlist if it doesnt exist already
* @param key key under which this wordlist is stored
* @param value new word to add
* @return internal representation of the wordlist in a tmpbuf or NULL in case of an error
*/
const char*
lumiera_config_wordlist_add (const char* key, const char* value);
// * {{{ lumiera_config_TYPE_set (const char* key, TYPE*value, const char* fmt) }}}
// Highlevel interface for different types, fmt is a printf format specifier for the desired format, when NULL, defaults apply.

View file

@ -41,6 +41,7 @@ extern LumieraConfig lumiera_global_config;
const char*
lumiera_config_link_get (const char* key, const char** value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -49,6 +50,7 @@ lumiera_config_link_get (const char* key, const char** value)
LumieraConfigitem
lumiera_config_link_set (const char* key, const char** value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -66,7 +68,7 @@ lumiera_config_number_get (const char* key, long long* value)
const char* raw_value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
@ -94,7 +96,7 @@ lumiera_config_number_set (const char* key, long long* value)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %lld"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value));
@ -111,6 +113,7 @@ lumiera_config_number_set (const char* key, long long* value)
const char*
lumiera_config_real_get (const char* key, long double* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -119,6 +122,7 @@ lumiera_config_real_get (const char* key, long double* value)
LumieraConfigitem
lumiera_config_real_set (const char* key, long double* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -195,7 +199,7 @@ lumiera_config_string_get (const char* key, const char** value)
const char* raw_value = *value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
@ -218,7 +222,7 @@ lumiera_config_string_set (const char* key, const char** value)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value));
@ -228,6 +232,53 @@ lumiera_config_string_set (const char* key, const char** value)
}
/**
* Wordlist
* words delimited by any of " \t,;"
*/
const char*
lumiera_config_wordlist_get (const char* key, const char** value)
{
TRACE (config_typed, "KEY %s", key);
const char* raw_value = *value = NULL;
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
if (raw_value)
{
*value = raw_value;
}
else
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
TODO ("remove the ERROR_SET because config_get sets it already? also in all other getters in this file");
}
}
return *value;
}
LumieraConfigitem
lumiera_config_wordlist_set (const char* key, const char** value)
{
TRACE (config_typed);
LumieraConfigitem item = NULL;
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, *value));
}
return item;
}
/**
* Word
@ -262,7 +313,7 @@ lumiera_config_word_get (const char* key, const char** value)
const char* raw_value = *value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &raw_value))
{
@ -285,7 +336,7 @@ lumiera_config_word_set (const char* key, const char** value)
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config_typed, &lumiera_global_config->lock)
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
const char* fmt = "= %s"; TODO ("use the config system (config.format*...) to deduce the desired format for this key");
item = lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, fmt, scan_word (*value)));
@ -302,6 +353,7 @@ lumiera_config_word_set (const char* key, const char** value)
const char*
lumiera_config_bool_get (const char* key, int* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
@ -311,6 +363,7 @@ lumiera_config_bool_get (const char* key, int* value)
LumieraConfigitem
lumiera_config_bool_set (const char* key, int* value)
{
(void) key; (void) value;
TRACE (config_typed);
UNIMPLEMENTED();
return 0;

View file

@ -0,0 +1,217 @@
/*
config_wordlist.c - Lumiera wordlist access functions
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.
*/
//TODO: Support library includes//
#include "lib/error.h"
#include "lib/safeclib.h"
//TODO: Lumiera header includes//
#include "backend/config.h"
//TODO: internal/static forward declarations//
extern LumieraConfig lumiera_global_config;
//TODO: System includes//
/**
* return nth word of a wordlist
*/
const char*
lumiera_config_wordlist_get_nth (const char* key, unsigned nth)
{
const char* value;
size_t len;
if (!lumiera_config_wordlist_get (key, &value))
return NULL;
for (;;)
{
value += strspn (value, " \t,;");
len = strcspn (value, " \t,;");
if (!nth && *value)
break;
--nth;
value += len;
if (!*value)
return NULL;
}
return lumiera_tmpbuf_strndup (value, len);
}
int
lumiera_config_wordlist_find (const char* key, const char* value)
{
const char* itr;
size_t vlen = strlen (value);
size_t len;
if (!lumiera_config_wordlist_get (key, &itr))
return -1;
for (int idx = 0; *itr; itr += len, ++idx)
{
itr += strspn (itr, " \t,;");
len = strcspn (itr, " \t,;");
if (len == vlen && !strncmp (itr, value, vlen))
return idx;
}
return -1;
}
const char*
lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2)
{
const char* wordlist;
const char* str = NULL;
size_t vlen = strlen (value);
size_t len;
if (!value)
return NULL;
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &wordlist))
{
const char* start = wordlist + strspn (wordlist, " \t,;");
for (const char* itr = start; *itr; itr += len)
{
const char* left_end = itr;
itr += strspn (itr, " \t,;");
len = strcspn (itr, " \t,;");
if (len == vlen && !strncmp (itr, value, vlen))
{
TODO ("figure delimiter from original string out");
const char* delim = " ";
/* step over the word */
itr += len;
itr += strspn (itr, " \t,;");
/* getting the delimiters right for the corner cases looks ugly, want to refactor it? just do it */
str = lumiera_tmpbuf_snprintf (SIZE_MAX,
"%.*s%.*s%s%s%s%s%s%s",
start - wordlist, wordlist,
left_end - start, start,
(left_end - start && subst1 && *subst1) ? delim : "",
(subst1 && *subst1) ? subst1 : "",
((left_end - start || (subst1 && *subst1)) && subst2 && *subst2) ? delim : "",
(subst2 && *subst2) ? subst2 : "",
((left_end - start || (subst1 && *subst1) || (subst2 && *subst2)) && *itr) ? delim : "",
itr
);
if (!lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, "=%s", str)))
str = NULL;
break;
}
}
}
}
return str;
}
const char*
lumiera_config_wordlist_add (const char* key, const char* value)
{
const char* wordlist = NULL;
if (value && *value)
{
LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock)
{
if (lumiera_config_get (key, &wordlist))
{
size_t vlen = strlen (value);
size_t len;
for (const char* itr = wordlist; *itr; itr += len)
{
itr += strspn (itr, " \t,;");
len = strcspn (itr, " \t,;");
if (len == vlen && !strncmp (itr, value, vlen))
goto end;
}
TODO ("figure delimiter from original string out");
const char* delim = " ";
wordlist = lumiera_tmpbuf_snprintf (SIZE_MAX, "%s%s%s",
wordlist,
wordlist[strspn (wordlist, " \t,;")]?delim:"",
value);
if (!lumiera_config_set (key, lumiera_tmpbuf_snprintf (SIZE_MAX, "=%s", wordlist)))
wordlist = NULL;
}
end:;
}
}
return wordlist;
}
#if 0
const char*
lumiera_config_wordlist_remove_nth (const char* key, unsigned nth)
{
}
LumieraConfigitem
lumiera_config_wordlist_append (const char* key, const char** value, unsigned nth)
{
}
LumieraConfigitem
lumiera_config_wordlist_preprend (const char* key, const char** value, unsigned nth)
{
}
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -241,8 +241,8 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line)
itr += self->key_size;
/*we need a key with a length greather than zero and
* either the end of the line
* or a whitespace after the key */
* either end of line
* or whitespace after key */
if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) ))
{

View file

@ -42,7 +42,7 @@ NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore.
*/
static PSplay registry = NULL;
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER};
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER};
static int
@ -96,7 +96,9 @@ lumiera_filedescriptor_registry_init (void)
if (!registry)
LUMIERA_DIE (NO_MEMORY);
RESOURCE_HANDLE_INIT (registry_mutex.rh);
TODO ("LumieraMutex lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);");
// RESOURCE_HANDLE_INIT (registry_mutex.rh);
RESOURCE_ANNOUNCE (filedescriptor, "mutex", "filedescriptor registry", &registry, registry_mutex.rh);
}
@ -108,6 +110,8 @@ lumiera_filedescriptor_registry_destroy (void)
RESOURCE_FORGET (filedescriptor, registry_mutex.rh);
TODO ("LumieraMutex lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag);");
if (registry)
psplay_destroy (registry);
registry = NULL;

293
src/backend/interface.c Normal file
View file

@ -0,0 +1,293 @@
/*
interface.c - Lumiera interface api
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/mutex.h"
#include "lib/safeclib.h"
#include "backend/interface.h"
#include "backend/interfaceregistry.h"
#include <nobug.h>
/**
* @file
* From a programmers perspective interfaces only need to be opened when needed and closed
* when finished with them. There is no difference if the interface is internally provided
* by the core or provided by an external plugin.
* Interfaces can be opened multiple times and cross reference each other.
*/
static LumieraInterfacenode
lumiera_interface_open_interfacenode (LumieraInterfacenode self);
static void
lumiera_interfacenode_close (LumieraInterfacenode self);
LumieraInterface
lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name)
{
LumieraInterfacenode self = NULL;
TRACE (interface, "%s", name);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
self = lumiera_interfaceregistry_interfacenode_find (interface, version, name);
if (!self)
{
UNIMPLEMENTED ("query plugindb and load plugin if exists");
}
if (self)
{
if (minminorversion > self->interface->size)
{
UNIMPLEMENTED ("set error");
self = NULL;
}
else
{
self = lumiera_interface_open_interfacenode (self);
}
}
}
return self->interface;
}
static void
push_dependency (LumieraInterfacenode parent, LumieraInterfacenode child)
{
/* push a dependency on the dependency array, allcoate or resize it on demand */
TRACE (interface, "%s %s", parent->interface->name, child->interface->name);
/* no dependencies recorded yet, alloc a first block for 4 pointers */
if (!parent->deps_size)
parent->deps = lumiera_calloc (parent->deps_size = 4, sizeof (LumieraInterfacenode));
size_t sz = parent->deps_size;
LumieraInterfacenode* itr = parent->deps;
while (*itr)
{
--sz;
++itr;
if (sz == 1)
{
/* block to small, realloc it with twice its size, we keep the block NULL terminated */
sz = parent->deps_size + 1;
parent->deps_size *= 2;
parent->deps = lumiera_realloc (parent->deps, parent->deps_size * sizeof (LumieraInterface));
itr = parent->deps + sz - 2;
memset (itr, 0, sz * sizeof (LumieraInterface));
}
}
/* found free element, store self in dependencies */
*itr = child;
}
static void
depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack)
{
/* increment refcount for all non-cyclic dependencies recursively */
if (self->deps)
{
TRACE (interface, "%s %d", self->interface->name, self->refcnt);
for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
{
TRACE (interface, "loop %s", (*dep)->interface->name);
int cycle = 0;
for (LumieraInterfacenode itr = *stack; itr; itr = itr->lnk)
{
if (itr == *dep)
{
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
if (!cycle)
{
++(*dep)->refcnt;
(*dep)->lnk = *stack;
*stack = *dep;
depwalk (*dep, stack);
*stack = (*dep)->lnk;
(*dep)->lnk = NULL;
}
}
}
}
static LumieraInterfacenode
lumiera_interface_open_interfacenode (LumieraInterfacenode self)
{
static unsigned collect_dependencies = 0;
static LumieraInterfacenode stack = NULL;
/*
Ok, this got little more complicated than it should be,
but finally it handles any kind of cross dependencies between interfaces gracefully
*/
if (self)
{
TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
/* discover cycles, cycles don't refcount! */
int cycle = 0;
for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
{
if (itr == self)
{
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
/* 'stack' is ensured to be !NULL here because only a parent call can switch collect_dependencies on */
if (collect_dependencies)
push_dependency (stack, self);
if (!cycle)
{
++self->refcnt;
self->lnk = stack;
stack = self;
int collect_dependencies_bak = collect_dependencies;
if (self->refcnt == 1)
{
/* first opening, run acquire, recursive opening shall record its dependencies here */
if (self->interface->acquire)
{
TRACE (interface, "Acquire %s", self->interface->name);
collect_dependencies = self->deps?0:1;
self->interface = self->interface->acquire (self->interface);
}
}
else
{
/* opening again recurse dependencies */
collect_dependencies = 0;
depwalk (self, &stack);
}
collect_dependencies = collect_dependencies_bak;
stack = self->lnk;
self->lnk = NULL;
}
}
}
return self;
}
void
lumiera_interface_close (LumieraInterface self)
{
TRACE (interface);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
lumiera_interfacenode_close ((LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, self, 100));
}
}
/* internal function, does no locking! */
static void
lumiera_interfacenode_close (LumieraInterfacenode self)
{
static LumieraInterfacenode stack = NULL;
if (!self)
return;
TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:"");
REQUIRE (self->refcnt);
int cycle = 0;
for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk)
{
if (itr == self)
{
TRACE (interface, "CYCLE");
cycle = 1;
break;
}
}
if (!cycle)
{
self->lnk = stack;
stack = self;
if (self->refcnt == 1)
{
if (self->interface->release)
{
TRACE (interface, "Release %s", self->interface->name);
self->interface->release (self->interface);
}
}
else
{
if (self->deps)
{
TRACE (interface, "Recurse %s %d", self->interface->name, self->refcnt);
for (LumieraInterfacenode* dep = self->deps; *dep; ++dep)
lumiera_interfacenode_close (*dep);
}
}
stack = self->lnk;
self->lnk = NULL;
--self->refcnt;
}
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

408
src/backend/interface.h Normal file
View file

@ -0,0 +1,408 @@
/*
interface.h - Lumiera interface macros and structures
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_INTERFACE_H
#define LUMIERA_INTERFACE_H
#include "lib/luid.h"
#include "lib/ppmpl.h"
#include "lib/psplay.h"
/* TODO better doxygen formating */
/**
* @file
* Lumiera interface macros and structures.
*
* Instead just simple function/library bindings, Lumiera uses a system of
* versioned interfaces. This interfaces are C-binding compatible and thus
* can be used by any language which can bind to C. This interfaces are versioned
* to provide exceptional forward and backward compatibility for both, source and
* binary deployment of modules. This interfaces play a central role on the Lumiera
* architecture, other facilities, like serializing sessions and distributed computing
* will use them extensively.
*
* Overview
*
* Interfaces are used for two purposes in Lumiera:
* 1. The core uses them internally and exports its functionality though them.
* 2. Plugins (effects,...) extend Lumiera by providing interfaces
*
* We define some macros here which ease the declaration and definition of interfaces.
*
* Declaration of an interface happens in a header and has the form:
* LUMIERA_INTERFACE_DECLARE(name, version,
* LUMIERA_INTERFACE_SLOT(ret, name, params),
* ...
* )
* Any code which want to use this interface must then include its declaration.
*
* Basic definition of an interface is done by mapping functions to slots or giving
* inline definitions for slot functions:
* LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, acquire, release,
* LUMIERA_INTERFACE_MAP (slot, luid, function),
* LUMIERA_INTERFACE_INLINE (slot, luid, ret, params, {body}),
* ...
* )
*
* There are 2 ways to define collections of interfaces:
* LUMIERA_EXPORT(queryfunc,
* LUMIERA_INTERFACE_DEFINE(...),
* ...
* )
* to export interfaces from the core.
*
* LUMIERA_PLUGIN(descriptor, acquire, release, luid,
* LUMIERA_INTERFACE_DEFINE(...),
* ...
* )
* is used to export interfaces from a plugin.
*
* Naming and Versioning
* Interfaces have unique names and a major and minor version. The name and the major version
* is used to construct a C identifier for the interface, the minor version is implicit defined
* by the number of functions a interface. Interface instances are not versioned by the
* interface system, versioning these shall be defined somewhere else.
*
* Slot names are normal C identifiers, how these shall be versioned has to be defined somewhere
* else and is not subject of the interface system. Each function can has its own unique uuid.
*/
/*
Interface declaration macros
*/
/**
* Construct a type identifier for an interface
* @param name name of the interface
* @param version major version of this interface
*/
#define LUMIERA_INTERFACE_INAME(name, version) name##_##version
/**
* Construct a definition identifier for an interface
* @param iname name of the interface
* @param version major version of the interface
* @param dname name for the instance
*/
#define LUMIERA_INTERFACE_DNAME(iname, version, dname) PPMPL_CAT (LUMIERA_INTERFACE_INAME(iname, version), _##dname)
/**
* Return a reference (pointer) to an interface implementation
* @param iname name of the interface
* @param version major version of the interface
* @param dname name for the instance
*/
#define LUMIERA_INTERFACE_REF(iname, version, dname) \
(LumieraInterface)&LUMIERA_INTERFACE_DNAME(iname, version, dname)
/**
* Construct the type of the interface
* @param name name of the interface
* @param version major version of this interface
*/
#define LUMIERA_INTERFACE_TYPE(name, version) struct LUMIERA_INTERFACE_INAME(name, version)
/**
* Construct a cast to the target interface type
* Used to cast a generic LumieraInterface to the real type
* @param name name of the interface
* @param version major version of this interface
*/
#define LUMIERA_INTERFACE_CAST(name, version) (LUMIERA_INTERFACE_TYPE(name, version)*)
/**
* Declare an interface.
* @param name name of the interface
* @param version major version of this interface declaration. 0 denotes a experimental interface,
* otherwise this shall be counting from 1 upwards for each new (incompatible) change of an interface.
* The older interface declarations may still be maintained in parallel (backwards compatibility!).
* @param ... Slot declarations for the functions provided by this interface @see LUMIERA_INTERFACE_SLOT
* The number of Slots in an interface defines its 'minor' version.
* New slots must be added at the end. The prototype and order of existing slots must not be changed.
* Slots may be renamed, for example a slot 'foo' can be renamed to 'foo_old' when a new 'foo' slot is
* added. Binary modules will then still use the 'foo_old' slot which was the 'foo' slot at their
* compile time while compiling modules from source will use the new 'foo' slot. This may be
* intentionally used to break compilation and force the update of modules to a new api.
*/
#define LUMIERA_INTERFACE_DECLARE(name, version, ...) \
LUMIERA_INTERFACE_TYPE(name, version) \
{ \
lumiera_interface interface_header_; \
PPMPL_FOREACH(_, __VA_ARGS__) \
}
/**
* Declare function slot inside an interface.
* @param ret return type of the function
* @param name name of this slot
* @param params parentized list of parameters for the function
*/
#define PPMPL_FOREACH_LUMIERA_INTERFACE_SLOT(ret, name, params) ret (*name) params; lumiera_uid name##_uid;
/*
Interface definition macros
*/
/**
* Define a interface instance.
* @param iname name of the interface to instance
* @param version major version of the interface to instance
* @param name name of the instance
* @param descriptor pointer to an interface instance which provides a description of this interface, might be NULL
* @param acquire a function which is called whenever this interface is opened for using, might be NULL
* @param release a function which is called whenever this interface is closed after use, might be NULL
* @param ... map functions to interface slots @see LUMIERA_INTERFACE_MAP
*/
#define LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, acquire, release, ...) \
PPMPL_FOREACH(_P1_, __VA_ARGS__) \
LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, version, name) = \
{ \
{ \
#iname, \
version, \
#name, \
sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \
descriptor, \
acquire, \
release \
}, \
PPMPL_FOREACH(_P2_, __VA_ARGS__) \
}
/**
* Map a function to a interface slot
* @param slot name of the slot to be mapped
* @param luid unique identifier for this function, use the magic word LUIDGEN here and run the
* lumiera uuid generator tool (to be written) over the source file to generate luid's automatically
* @param function name of the function to be mapped on slot
*
* @note C++ requires that all mappings are in the same order than defined in the interface declaration,
* this would be good style for C too anyways
*/
#define PPMPL_FOREACH_P1_LUMIERA_INTERFACE_MAP(slot, luid, function)
#ifdef __cplusplus
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_MAP(slot, luid, function) \
function, LUMIERA_UID_INITIALIZER (luid),
#else
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_MAP(slot, luid, function) \
.slot = function, .slot##_uid = LUMIERA_UID_INITIALIZER (luid),
#endif
/**
* Map a inline defined function to a interface slot
* @param slot name of the slot to be mapped
* @param luid unique identifier for this function, use the magic word LUIDGEN here and run the
* lumiera uuid generator tool (to be written) over the source file to generate luid's automatically
* @param ret return type of the inline function
* @param params parentized list of parameters given to the function
* @param ... braced function body
*
* @note C++ requires that all mappings are in the same order than defined in the interface declaration,
* this would be good style for C too anyways
*/
#define PPMPL_FOREACH_P1_LUMIERA_INTERFACE_INLINE(slot, luid, ret, params, ...) \
static ret \
LUMIERA_INTERFACE_INLINE_NAME(slot) params \
__VA_ARGS__
#ifdef __cplusplus
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_INLINE(slot, luid, ret, params, ...) \
LUMIERA_INTERFACE_INLINE_NAME(slot), LUMIERA_UID_INITIALIZER (luid),
#else
#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_INLINE(slot, luid, ret, params, ...) \
.slot = LUMIERA_INTERFACE_INLINE_NAME(slot), .slot##_uid = LUMIERA_UID_INITIALIZER (luid),
#endif
#define LUMIERA_INTERFACE_INLINE_NAME(slot) PPMPL_CAT(lumiera_##slot##_l, __LINE__)
#define PPMPL_FOREACH_L1_P1_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, acquire, release, ...) \
LUMIERA_INTERFACE_INSTANCE (iname, version, \
name, \
descriptor, \
acquire, \
release, \
__VA_ARGS__ \
);
#define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, acquire, release, ...) \
&LUMIERA_INTERFACE_DNAME(iname, version, name).interface_header_,
/**
* Generate interface container suitable for enumerating interfaces.
* This takes a list of interface definitions, instantiates them and places pointers to them
* into a zero terminated array which address is returned by the a created function.
* For interfaces generated by he core, the user is responsible to register these at the
* plugindb dynamically
* @param queryfunc name of the function to be created.
* @param ... list of LUMIERA_INTERFACE_DEFINE() for all interfaces this plugin provides.
*/
#define LUMIERA_EXPORT(queryfunc, ...) \
PPMPL_FOREACH_L1(_P1_, __VA_ARGS__) \
static LumieraInterface* \
queryfunc (void) \
{ \
static LumieraInterface interfaces[] = \
{ \
PPMPL_FOREACH_L1(_P2_, __VA_ARGS__) \
NULL \
}; \
return interfaces; \
}
/**
* Generate interface container suitable for a lumiera plugin.
* This takes a list of interface definitions and places pointers to them into a zero terminated array. Further
* it instances a local 'plugin interface' which will be picked up by the plugin loader to query the array of
* provided interfaces.
* @param descriptor pointer to an interface instance which provides a description of this plugin, might be NULL
* @param acquire a function which is called whenever the plugin interface is opened for using, might be NULL
* @param release a function which is called whenever this plugin interface is closed after use, might be NULL
* @param luid unique identifier for the this plugin interfaces query, use the magic word LUIDGEN here and run the
* lumiera uuid generator tool (to be written) over the source file to generate luid's automatically
* @param ... list of LUMIERA_INTERFACE_DEFINE() for all interfaces this plugin provides.
*/
#define LUMIERA_PLUGIN(descriptor, acquire, release, luid, ...) \
LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \
LUMIERA_INTERFACE_DEFINE (lumieraorg_plugin, 0, \
lumieraorg_plugin_0, \
NULL, \
NULL, \
NULL, \
LUMIERA_INTERFACE_MAP (plugin_interfaces, plugin_interfaces, luid) \
)
/**
* create a handle for a interface (WIP)
*/
#define LUMIERA_INTERFACE_HANDLE(interface, version) \
LUMIERA_INTERFACE_TYPE(interface, version)*
#define LUMIERA_INTERFACE_OPEN(interface, version, minminor, name) \
LUMIERA_INTERFACE_CAST(interface, version) lumiera_interface_open (#interface, version, minminor, #name)
typedef struct lumiera_interfaceslot_struct lumiera_interfaceslot;
typedef lumiera_interfaceslot* LumieraInterfaceslot;
typedef struct lumiera_interface_struct lumiera_interface;
typedef lumiera_interface* LumieraInterface;
/**
* This is just a placeholder for an entry in a interface table.
* It consists of one here generic, later correctly prototyped function pointer and
* a unique identifier which is associated with this function.
*/
struct lumiera_interfaceslot_struct
{
void (*func)(void);
lumiera_uid uid;
};
/**
* Header for an interface, just the absolute necessary metadata.
*/
struct lumiera_interface_struct
{
/** name of the interface (type) */
const char* interface;
/** major version, 0 means experimental */
unsigned version;
/** name of this instance */
const char* name;
/** size of the whole interface structure (minor version) */
size_t size;
/** metadata descriptor, itself a interface (or NULL) */
LumieraInterface descriptor;
/**
* Must be called before this interface is used.
* might be nested.
* @param self pointer to the interface to be acquired
* @return pointer to the interface or NULL on error
*/
LumieraInterface (*acquire)(LumieraInterface self);
/**
* called when finished using this interface
* must match the acquire calls
* @param self pointer to the interface to be released
*/
void (*release)(LumieraInterface self);
#ifndef __cplusplus
/** placeholder array for the following function slots, C++ doesn't support flexible arrays */
lumiera_interfaceslot functions[];
#endif
};
/*
API to handle interfaces
*/
/**
* Open an interface by version and name.
* Looks up the requested interface, possibly loading it from a plugin.
* @param interface name of the interface definition
* @param version major version of the interface definition
* @param minminorversion required minor version (structure size)
* @param name name of the interface implementation
* @return the queried interface handle on success, else NULL
*/
LumieraInterface
lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name);
/**
* Close an interface after use.
* @param self interface to be closed
* consider 'self' to be invalidated after this call
*/
void
lumiera_interface_close (LumieraInterface iface);
#endif /* LUMIERA_INTERFACE_H */
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,48 @@
/*
interfacedescriptor.h - Metadata interface for Lumiera interfaces
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_INTERFACEDESCRIPTOR_H
#define LUMIERA_INTERFACEDESCRIPTOR_H
#include "backend/interface.h"
/**
* WIP: interface descriptor, needs some generic metadata interface
*/
LUMIERA_INTERFACE_DECLARE (lumieraorg_interfacedescriptor, 0,
/* The following slots are some human-readable descriptions of certain properties */
LUMIERA_INTERFACE_SLOT (const char*, name, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, version, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, author, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, copyright, (LumieraInterface)),
LUMIERA_INTERFACE_SLOT (const char*, license, (LumieraInterface))
/* TODO add more things here, dependencies, provisions etc */
);
#endif /* LUMIERA_INTERFACEDESCRIPTORS_H */
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,255 @@
/*
interfaceregistry.c - Lumiera interface registry
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/mutex.h"
#include "lib/error.h"
#include "lib/psplay.h"
#include "lib/safeclib.h"
#include <nobug.h>
#include "backend/interfaceregistry.h"
/**
* @file
* Interface instances are published and activated by registering them
* into a global registry, which is defined here. This instances are identified
* by their name and major version.
*/
NOBUG_DEFINE_FLAG_PARENT (interface_all, backend);
NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, interface_all);
NOBUG_DEFINE_FLAG_PARENT (interface, interface_all);
PSplay lumiera_interfaceregistry;
lumiera_mutex lumiera_interface_mutex;
static int
cmp_fn (const void* keya, const void* keyb);
static const void*
key_fn (const PSplaynode node);
static LumieraInterfacenode
lumiera_interfacenode_new (LumieraInterface iface)
{
LumieraInterfacenode self = lumiera_malloc (sizeof (*self));
psplaynode_init (&self->node);
self->interface = iface;
self->refcnt = 0;
self->lnk = NULL;
self->deps_size = 0;
self->deps = NULL;
return self;
}
static void
lumiera_interfacenode_delete (LumieraInterfacenode self)
{
if (self)
{
REQUIRE (self->refcnt == 0);
lumiera_free (self->deps);
lumiera_free (self);
}
}
/**
* Initialize the interface registry
*/
void
lumiera_interfaceregistry_init (void)
{
NOBUG_INIT_FLAG (interface_all);
NOBUG_INIT_FLAG (interfaceregistry);
NOBUG_INIT_FLAG (interface);
TRACE (interfaceregistry);
REQUIRE (!lumiera_interfaceregistry);
lumiera_interfaceregistry = psplay_new (cmp_fn, key_fn, NULL);
if (!lumiera_interfaceregistry)
LUMIERA_DIE (ERRNO);
lumiera_recmutex_init (&lumiera_interface_mutex, "interfaceregistry", &NOBUG_FLAG(interfaceregistry));
}
void
lumiera_interfaceregistry_destroy (void)
{
TRACE (interfaceregistry);
REQUIRE (!psplay_nelements (lumiera_interfaceregistry));
lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry));
if (lumiera_interfaceregistry)
psplay_destroy (lumiera_interfaceregistry);
lumiera_interfaceregistry = NULL;
}
void
lumiera_interfaceregistry_register_interface (LumieraInterface self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", self->interface, self->version, self->name);
psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (self)->node, 100);
}
}
void
lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
while (*self)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name);
psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (*self)->node, 100);
++self;
}
}
}
void
lumiera_interfaceregistry_remove_interface (LumieraInterface self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, self, 0);
REQUIRE (node->refcnt == 0, "but is %d", node->refcnt);
lumiera_interfacenode_delete ((LumieraInterfacenode)psplay_remove (lumiera_interfaceregistry, &node->node));
}
}
void
lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self)
{
TRACE (interfaceregistry);
REQUIRE (self);
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
while (*self)
{
TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name);
LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, *self, 0);
REQUIRE (node->refcnt == 0, "but is %d", node->refcnt);
lumiera_interfacenode_delete ((LumieraInterfacenode) psplay_remove (lumiera_interfaceregistry, &node->node));
++self;
}
}
}
LumieraInterfacenode
lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name)
{
TRACE (interfaceregistry);
struct lumiera_interface_struct cmp;
cmp.interface = interface;
cmp.version = version;
cmp.name = name;
LumieraInterfacenode ret = NULL;
LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex)
{
ret = (LumieraInterfacenode)psplay_find (lumiera_interfaceregistry, &cmp, 100);
}
return ret;
}
LumieraInterface
lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name)
{
return lumiera_interfaceregistry_interfacenode_find (interface, version, name)->interface;
}
static int
cmp_fn (const void* keya, const void* keyb)
{
const LumieraInterface a = (const LumieraInterface)keya;
const LumieraInterface b = (const LumieraInterface)keyb;
int r = strcmp (a->interface, b->interface);
if (r<0)
return -1;
else if (r>0)
return 1;
if (a->version < b->version)
return -1;
else if (a->version > b->version)
return 1;
r = strcmp (a->name, b->name);
if (r<0)
return -1;
else if (r>0)
return 1;
return 0;
}
static const void*
key_fn (const PSplaynode node)
{
return ((LumieraInterfacenode)node)->interface;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -0,0 +1,114 @@
/*
interfaceregistry.h - Lumiera interface registry
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_INTERFACEREGISTRY_H
#define LUMIERA_INTERFACEREGISTRY_H
#include "lib/mutex.h"
#include "lib/psplay.h"
#include "backend/interface.h"
#include <nobug.h>
/**
* @file
* Interface instances are published and activated by registering them
* into a gloabl registry, which is defined here. This instances are identified
* by their name and major version.
*/
NOBUG_DECLARE_FLAG (interface_all);
NOBUG_DECLARE_FLAG (interfaceregistry);
NOBUG_DECLARE_FLAG (interface);
extern PSplay lumiera_interfaceregistry;
extern lumiera_mutex lumiera_interface_mutex;
/**
* Interface management node.
* All active interfaces managed through this node which contains the dynamic data for
* dependency tracking and reference counting.
*/
typedef struct lumiera_interfacenode_struct lumiera_interfacenode;
typedef lumiera_interfacenode* LumieraInterfacenode;
struct lumiera_interfacenode_struct
{
/** all known interfaces are registered in a tree */
psplaynode node;
/** the interface itself */
LumieraInterface interface;
/** reference counters and link used for internal reference management */
unsigned refcnt;
/** temporary used to stack interfaces when recursively opening/closing them */
LumieraInterfacenode lnk;
/** allocated size of the following deps table */
size_t deps_size;
/** NULL terminated table of all dependenncies (interfaces opened on initialization) */
LumieraInterfacenode* deps;
};
extern lumiera_mutex lumiera_interface_mutex;
/**
* Initialize the interface registry
*/
void
lumiera_interfaceregistry_init (void);
void
lumiera_interfaceregistry_destroy (void);
void
lumiera_interfaceregistry_register_interface (LumieraInterface self);
void
lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self);
void
lumiera_interfaceregistry_remove_interface (LumieraInterface self);
void
lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self);
LumieraInterfacenode
lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name);
LumieraInterface
lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name);
#endif /* LUMIERA_INTERFACEREGISTRY_H */
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -27,8 +27,9 @@
#include <time.h>
#include <limits.h>
#include "plugin.h"
#include "safeclib.h"
#include "lib/safeclib.h"
#include "backend/plugin.h"
/**
* @file

View file

@ -20,22 +20,20 @@ noinst_LIBRARIES += liblumi.a
liblumi_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
liblumi_a_SOURCES = \
$(liblumi_a_srcdir)/plugin.c \
$(liblumi_a_srcdir)/error.c \
$(liblumi_a_srcdir)/mutex.c \
$(liblumi_a_srcdir)/rwlock.c \
$(liblumi_a_srcdir)/condition.c \
$(liblumi_a_srcdir)/luid.c \
$(liblumi_a_srcdir)/safeclib.c \
$(liblumi_a_srcdir)/cuckoo.c \
$(liblumi_a_srcdir)/psplay.c \
$(liblumi_a_srcdir)/mrucache.c \
$(liblumi_a_srcdir)/time.c \
liblumi_a_SOURCES = \
$(liblumi_a_srcdir)/error.c \
$(liblumi_a_srcdir)/mutex.c \
$(liblumi_a_srcdir)/rwlock.c \
$(liblumi_a_srcdir)/condition.c \
$(liblumi_a_srcdir)/luid.c \
$(liblumi_a_srcdir)/safeclib.c \
$(liblumi_a_srcdir)/cuckoo.c \
$(liblumi_a_srcdir)/psplay.c \
$(liblumi_a_srcdir)/mrucache.c \
$(liblumi_a_srcdir)/time.c \
$(liblumi_a_srcdir)/appconfig.cpp
noinst_HEADERS += \
$(liblumi_a_srcdir)/plugin.h \
$(liblumi_a_srcdir)/error.h \
$(liblumi_a_srcdir)/mutex.h \
$(liblumi_a_srcdir)/rwlock.h \
@ -46,6 +44,7 @@ noinst_HEADERS += \
$(liblumi_a_srcdir)/psplay.h \
$(liblumi_a_srcdir)/mrucache.h \
$(liblumi_a_srcdir)/time.h \
$(liblumi_a_srcdir)/ppmpl.h \
$(liblumi_a_srcdir)/appconfig.hpp \
$(liblumi_a_srcdir)/lifecycleregistry.hpp

View file

@ -31,6 +31,22 @@
*/
typedef unsigned char lumiera_uid[16];
typedef lumiera_uid* LumieraUid;
/*
C++ can't initialize arrays from string literals with the trailing \0 cropped
C can't initialize non constant members,
there we go
*/
#ifdef __cplusplus
#define LUMIERA_UID_INITIALIZER(l) \
{ \
l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], \
l[8], l[9], l[10], l[11], l[12], l[13], l[14], l[15] \
}
#else
#define LUMIERA_UID_INITIALIZER(l) l
#endif
/**
* Retrieve a generic pointer stored in a luid

View file

@ -44,6 +44,30 @@ lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* f
}
static pthread_once_t recursive_mutexattr_once = PTHREAD_ONCE_INIT;
static pthread_mutexattr_t recursive_mutexattr;
static void recursive_mutexattr_init()
{
pthread_mutexattr_init (&recursive_mutexattr);
pthread_mutexattr_settype (&recursive_mutexattr, PTHREAD_MUTEX_RECURSIVE);
}
LumieraMutex
lumiera_recmutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_once(&recursive_mutexattr_once, recursive_mutexattr_init);
pthread_mutex_init (&self->mutex, &recursive_mutexattr);
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "recmutex", purpose, self, self->rh);
}
return self;
}
LumieraMutex
lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag)
{

View file

@ -39,15 +39,78 @@ 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}; \
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ \
= {(LumieraMutex)1 NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
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); \
} \
}))
/**
* Mutual exclusion chainbuilder section.
* Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(b){run();}}
* calls lock(a); lock(b); unlock(a); run(); unlock(b);
* This macro should only be used inside LUMIERA_MUTEX_SECTION and should be
* called on the correct mutexes, period.
*/
#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \
for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \
NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1 \
NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
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); \
} \
}))
/**
* Recursive Mutual exclusive section.
*/
#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1 \
NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
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); \
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; \
@ -61,6 +124,43 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
}))
/**
* 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_RESOURCE_HANDLE_COMMA_INITIALIZER}; \
lumiera_mutex_section_.mutex;) \
for ( \
({ \
lumiera_mutex_section_.mutex = (mtx); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_mutex_section_, \
NOBUG_RESOURCE_RECURSIVE, lumiera_mutex_section_.rh); \
if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
if (lumiera_mutex_section_old_->mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_old_->mutex->mutex); \
lumiera_mutex_section_old_->mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_old_->rh); \
} \
}); \
lumiera_mutex_section_.mutex; \
({ \
if (lumiera_mutex_section_.mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \
lumiera_mutex_section_.mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \
} \
}))
/**
* Mutex.
*
@ -76,12 +176,22 @@ typedef lumiera_mutex* LumieraMutex;
/**
* Initialize a mutex variable
* This initializes a 'fast' default mutex which must not be locked recursively from one thread.
* @param self is a pointer to the mutex to be initialized
* @return self as given
*/
LumieraMutex
lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);
/**
* Initialize a mutex variable
* Initializes a 'recursive' mutex which might be locked by the same thread multiple times.
* @param self is a pointer to the mutex to be initialized
* @return self as given
*/
LumieraMutex
lumiera_recmutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);
/**
* Destroy a mutex variable

158
src/lib/ppmpl.h Normal file
View file

@ -0,0 +1,158 @@
/*
ppmpl.h - preprocessor meta programming library
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 PPMPL_H
#define PPMPL_H
/**
* @file
* Preprocessor metaprogramming library. We define some useful preprocessor
* tricks here.
*/
/**
* Iterate over a list of macros.
* @param p used to disambiguate up to three passes, use _, _P1_ or _P2_
* @param ... list of macros to be expanded. The user has to supply a definition
* in the form of PPMPL_FOREACH##p##macroname which shall expand to the desired text.
*
* This user defined macro shall be undefed after use.
*
* @example
* #define PPMPL_FOREACH_P1_FOO(arg) arg,
*
* {PPMPL_FOREACH(P1, FOO(1), FOO(2), FOO(3)), -1}
*
* #undef PPMPL_FOREACH_P1_FOO
*
* Would expand to the sequence:
* {1, 2, 3, -1}
*
* One can not recursively nest preprocessor macros. To allow this we define PPMPL_FOREACH_L1
* to PPMPL_FOREACH_L2 with the same semantics as PPMPL_FOREACH, This allowes to nest the
* FOREACH loop up to three nesting levels.
*/
#define PPMPL_FOREACH(p, ...) PPMPL_FOREACH0(p, __VA_ARGS__, PPMPL_FOREACH_NIL))
/* internal */
#define PPMPL_FOREACH0(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH1(p, __VA_ARGS__)
#define PPMPL_FOREACH1(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH2(p, __VA_ARGS__)
#define PPMPL_FOREACH2(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH3(p, __VA_ARGS__)
#define PPMPL_FOREACH3(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH4(p, __VA_ARGS__)
#define PPMPL_FOREACH4(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH5(p, __VA_ARGS__)
#define PPMPL_FOREACH5(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH6(p, __VA_ARGS__)
#define PPMPL_FOREACH6(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH7(p, __VA_ARGS__)
#define PPMPL_FOREACH7(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH8(p, __VA_ARGS__)
#define PPMPL_FOREACH8(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH9(p, __VA_ARGS__)
#define PPMPL_FOREACH9(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH10(p, __VA_ARGS__)
#define PPMPL_FOREACH10(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH11(p, __VA_ARGS__)
#define PPMPL_FOREACH11(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH12(p, __VA_ARGS__)
#define PPMPL_FOREACH12(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH13(p, __VA_ARGS__)
#define PPMPL_FOREACH13(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH14(p, __VA_ARGS__)
#define PPMPL_FOREACH14(p, h, ...) PPMPL_FOREACH##p##h PPMPL_FOREACH15(p, __VA_ARGS__)
#define PPMPL_FOREACH15(p, h, ...) PPMPL_FOREACH##p##h
#define PPMPL_FOREACH_
#define PPMPL_FOREACH_P1_
#define PPMPL_FOREACH_P2_
#define PPMPL_FOREACH_PPMPL_FOREACH_NIL PPMPL_FOREACH_FINAL(
#define PPMPL_FOREACH_P1_PPMPL_FOREACH_NIL PPMPL_FOREACH_FINAL(
#define PPMPL_FOREACH_P2_PPMPL_FOREACH_NIL PPMPL_FOREACH_FINAL(
#define PPMPL_FOREACH_FINAL(...)
#define PPMPL_FOREACH_L1(p, ...) PPMPL_FOREACH_L1_0(p, __VA_ARGS__, PPMPL_FOREACH_L1_NIL))
/* internal */
#define PPMPL_FOREACH_L1_0(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_1(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_1(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_2(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_2(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_3(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_3(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_4(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_4(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_5(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_5(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_6(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_6(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_7(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_7(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_8(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_8(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_9(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_9(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_10(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_10(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_11(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_11(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_12(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_12(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_13(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_13(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_14(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_14(p, h, ...) PPMPL_FOREACH_L1##p##h PPMPL_FOREACH_L1_15(p, __VA_ARGS__)
#define PPMPL_FOREACH_L1_15(p, h, ...) PPMPL_FOREACH_L1##p##h
#define PPMPL_FOREACH_L1_
#define PPMPL_FOREACH_L1_P1_
#define PPMPL_FOREACH_L1_P2_
#define PPMPL_FOREACH_L1_PPMPL_FOREACH_L1_NIL PPMPL_FOREACH_L1_FINAL(
#define PPMPL_FOREACH_L1_P1_PPMPL_FOREACH_L1_NIL PPMPL_FOREACH_L1_FINAL(
#define PPMPL_FOREACH_L1_P2_PPMPL_FOREACH_L1_NIL PPMPL_FOREACH_L1_FINAL(
#define PPMPL_FOREACH_L1_FINAL(...)
#define PPMPL_FOREACH_L2(p, ...) PPMPL_FOREACH_L2_0(p, __VA_ARGS__, PPMPL_FOREACH_L2_NIL))
/* internal */
#define PPMPL_FOREACH_L2_0(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_1(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_1(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_2(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_2(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_3(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_3(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_4(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_4(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_5(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_5(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_6(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_6(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_7(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_7(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_8(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_8(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_9(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_9(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_10(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_10(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_11(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_11(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_12(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_12(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_13(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_13(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_14(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_14(p, h, ...) PPMPL_FOREACH_L2##p##h PPMPL_FOREACH_L2_15(p, __VA_ARGS__)
#define PPMPL_FOREACH_L2_15(p, h, ...) PPMPL_FOREACH_L2##p##h
#define PPMPL_FOREACH_L2_
#define PPMPL_FOREACH_L2_P1_
#define PPMPL_FOREACH_L2_P2_
#define PPMPL_FOREACH_L2_PPMPL_FOREACH_L2_NIL PPMPL_FOREACH_L2_FINAL(
#define PPMPL_FOREACH_L2_P1_PPMPL_FOREACH_L2_NIL PPMPL_FOREACH_L2_FINAL(
#define PPMPL_FOREACH_L2_P2_PPMPL_FOREACH_L2_NIL PPMPL_FOREACH_L2_FINAL(
#define PPMPL_FOREACH_L2_FINAL(...)
/**
* Canonical preprocessor concat implementation which evaluates its arguments
*/
#define PPMPL_CAT(a,b) PPMPL_CAT_(a,b)
#define PPMPL_CAT_(a,b) a##b
#define PPMPL_STRINGIFY(a) PPMPL_STRINGIFY_(a)
#define PPMPL_STRINGIFY_(a) #a
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -51,6 +51,7 @@ struct psplaynode_struct
PSplaynode right;
};
#define PSPLAYNODE_INITIALIZER {NULL, NULL}
/**
* Function use to compare keys

View file

@ -51,6 +51,17 @@ lumiera_calloc (size_t n, size_t size)
}
void*
lumiera_realloc (void* ptr, size_t size)
{
void* o = size ? realloc (ptr, size) : NULL;
if (!o)
LUMIERA_DIE (NO_MEMORY);
return o;
}
char*
lumiera_strndup (const char* str, size_t len)
{

View file

@ -50,6 +50,16 @@ void*
lumiera_calloc (size_t n, size_t size);
/**
* Change the size of a memory block.
* @param ptr pointer to the old memory block obtained by lumiera_malloc or lumiera_calloc
* @param size new size of the block
* @return address of new block
*/
void*
lumiera_realloc (void* ptr, size_t size);
/**
* Free previously allocated memory.
* @param mem pointer to the memory block obtained by lumiera_malloc or lumiera_calloc

View file

@ -18,6 +18,18 @@ out: inner mutex locked section
END
TEST "chained mutex section" chainedmutexsection <<END
out: outer mutex locked section
out: inner but not outer mutex locked section
END
TEST "recursive mutex section" recursivemutexsection <<END
out: mutex locked once
out: mutex locked twice
END
TEST "rwlock section" rwlocksection <<END
out: write locked section 1
out: read locked section 2

View file

@ -21,6 +21,73 @@ out: delim = '='
out: value = ' baz'
END
TEST "reset a value" change_value foo.bar '=foo' '=bar' <<END
out: foo
out: bar
END
TEST "create configitem with empty line" configitem_simple_ctor_dtor '' <<END
END
TEST "create configitem with blank line" configitem_simple_ctor_dtor $' \t \t' <<END
END
TEST "create configitem with comment" configitem_simple_ctor_dtor $' #\t comment bla' <<END
END
TEST "create configitem with section" configitem_simple_ctor_dtor $'\t[prefix suffix ] bla' <<END
END
TEST "create configitem with directive" configitem_simple_ctor_dtor $' @include \t\t file \t' <<END
END
TEST "create configitem with configentry" configitem_simple_ctor_dtor $' key \t=\t value' <<END
END
TEST "create configitem with configentry (redirect)" configitem_simple_ctor_dtor $'keya <\t\t keyb ' <<END
END
TEST "check content of configitem with empty line" configitem_simple_content_check $'' << END
END
TEST "check content of configitem with comment" configitem_simple_content_check $'\t #comment bla' << END
out: item->line = ' #comment bla'
END
TEST "check content of configitem with section" configitem_simple_content_check $'[ key.foo suffix.bar ] ' << END
out: item->line = '[ key.foo suffix.bar ] '
out: item->key_size = '7'
out: item->key = 'key.foo suffix.bar ] '
out: item->delim = ' suffix.bar ] '
END
TEST "check content of configitem with directive (without argument)" configitem_simple_content_check $'\t @directive ' << END
out: item->line = ' @directive '
out: item->key_size = '9'
out: item->key = '@directive '
END
TEST "check content of configitem with directive (with argument)" configitem_simple_content_check $'\t @directive \targument' << END
out: item->line = ' @directive argument'
out: item->key_size = '9'
out: item->key = '@directive argument'
out: item->delim = ' argument'
END
TEST "check content of configitem with configentry" configitem_simple_content_check $' \t\t key.foo \t\t=\tbar' << END
out: item->line = ' key.foo = bar'
out: item->key_size = '7'
out: item->key = 'key.foo = bar'
out: item->delim = '= bar'
END
TEST "check content of configitem with configentry (redirect)" configitem_simple_content_check $' \t\t key.foo \t\t<\tkey.bar' << END
out: item->line = ' key.foo < key.bar'
out: item->key_size = '7'
out: item->key = 'key.foo < key.bar'
out: item->delim = '< key.bar'
END
TEST "set a config and retrieve it" basic_set_get 'foo' '=bar' <<END
out: bar

View file

@ -1,6 +1,6 @@
TESTING "test plugin example code" ./test-plugin
TEST "C plugin example" C <<END
PLANNED "C plugin example" C <<END
out: opened
out: Hallo Welt!
out: Tschuess C
@ -11,7 +11,7 @@ out: closed
out: closed
END
TEST "C++ plugin example" C++ <<END
PLANNED "C++ plugin example" C++ <<END
out: opened
out: Hallo Welt!
out: Tschuess C++

View file

@ -131,64 +131,116 @@ END
PLANNED "bool set" <<END
END
TEST "create configitem with empty line" configitem_simple_ctor_dtor '' <<END
TEST "wordlist get item from empty list should fail" wordlist_get_nth 'foo.bar' '' 0 << END
out: 'NULL'
END
TEST "create configitem with blank line" configitem_simple_ctor_dtor $' \t \t' <<END
TEST "wordlist get item past end should fail" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 3 << END
out: 'NULL'
END
TEST "create configitem with comment" configitem_simple_ctor_dtor $' #\t comment bla' <<END
TEST "wordlist get first item" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 0 << END
out: 'baz'
END
TEST "create configitem with section" configitem_simple_ctor_dtor $'\t[prefix suffix ] bla' <<END
TEST "wordlist get last item" wordlist_get_nth 'foo.bar' 'baz barf; gnarf' 2 << END
out: 'gnarf'
END
TEST "create configitem with directive" configitem_simple_ctor_dtor $' @include \t\t file \t' <<END
TEST "wordlist get middle" wordlist_get_nth 'foo.bar' 'baz barf, gnarf' 1 << END
out: 'barf'
END
TEST "create configitem with configentry" configitem_simple_ctor_dtor $' key \t=\t value' <<END
TEST "wordlist find, non existing" wordlist_find 'foo.bar' 'baz barf, gnarf' blah << END
out: '-1'
END
TEST "create configitem with configentry (redirect)" configitem_simple_ctor_dtor $'keya <\t\t keyb ' <<END
TEST "wordlist find, first" wordlist_find 'foo.bar' 'baz barf, gnarf' baz << END
out: '0'
END
TEST "check content of configitem with empty line" configitem_simple_content_check $'' << END
TEST "wordlist find, middle" wordlist_find 'foo.bar' 'baz barf, gnarf' barf << END
out: '1'
END
TEST "check content of configitem with comment" configitem_simple_content_check $'\t #comment bla' << END
out: item->line = ' #comment bla'
TEST "wordlist find, last" wordlist_find 'foo.bar' 'baz barf, gnarf' gnarf << END
out: '2'
END
TEST "check content of configitem with section" configitem_simple_content_check $'[ key.foo suffix.bar ] ' << END
out: item->line = '[ key.foo suffix.bar ] '
out: item->key_size = '7'
out: item->key = 'key.foo suffix.bar ] '
out: item->delim = ' suffix.bar ] '
TEST "wordlist replace, middle, insert after" wordlist_replace 'foo.bar' 'baz barf gnarf' barf barf foof << END
out: ' baz barf foof gnarf'
END
TEST "check content of configitem with directive (without argument)" configitem_simple_content_check $'\t @directive ' << END
out: item->line = ' @directive '
out: item->key_size = '9'
out: item->key = '@directive '
TEST "wordlist replace, middle, insert before" wordlist_replace 'foo.bar' 'baz barf gnarf' barf foof barf << END
out: ' baz foof barf gnarf'
END
TEST "check content of configitem with directive (with argument)" configitem_simple_content_check $'\t @directive \targument' << END
out: item->line = ' @directive argument'
out: item->key_size = '9'
out: item->key = '@directive argument'
out: item->delim = ' argument'
TEST "wordlist replace, middle, remove" wordlist_replace 'foo.bar' 'baz barf gnarf' barf '' '' << END
out: ' baz gnarf'
END
TEST "check content of configitem with configentry" configitem_simple_content_check $' \t\t key.foo \t\t=\tbar' << END
out: item->line = ' key.foo = bar'
out: item->key_size = '7'
out: item->key = 'key.foo = bar'
out: item->delim = '= bar'
TEST "wordlist replace, middle, replace1" wordlist_replace 'foo.bar' 'baz barf gnarf' barf 'foof' '' << END
out: ' baz foof gnarf'
END
TEST "check content of configitem with configentry (redirect)" configitem_simple_content_check $' \t\t key.foo \t\t<\tkey.bar' << END
out: item->line = ' key.foo < key.bar'
out: item->key_size = '7'
out: item->key = 'key.foo < key.bar'
out: item->delim = '< key.bar'
TEST "wordlist replace, middle, replace2" wordlist_replace 'foo.bar' 'baz barf gnarf' barf '' 'foof' << END
out: ' baz foof gnarf'
END
TEST "wordlist replace, first, insert before" wordlist_replace 'foo.bar' 'baz barf gnarf' baz 'first' 'baz' << END
out: ' first baz barf gnarf'
END
TEST "wordlist replace, first, replace1" wordlist_replace 'foo.bar' 'baz barf gnarf' baz 'first' '' << END
out: ' first barf gnarf'
END
TEST "wordlist replace, first, replace2" wordlist_replace 'foo.bar' 'baz barf gnarf' baz '' 'first' << END
out: ' first barf gnarf'
END
TEST "wordlist replace, last, insert after" wordlist_replace 'foo.bar' 'baz barf gnarf' gnarf 'gnarf' 'last' << END
out: ' baz barf gnarf last'
END
TEST "wordlist add 2 words" wordlist_add 'foo.bar' 'baz barf gnarf' first second << END
out: ' baz barf gnarf first'
out: ' baz barf gnarf first second'
END
TEST "wordlist add same word" wordlist_add 'foo.bar' 'baz barf gnarf' same same << END
out: ' baz barf gnarf same'
out: ' baz barf gnarf same'
END
TEST "wordlist add to empty list" wordlist_add 'foo.bar' '' first second << END
out: ' first'
out: ' first second'
END
TEST "wordlist add to empty list, same" wordlist_add 'foo.bar' '' same same << END
out: ' same'
out: ' same'
END
TEST "wordlist get item from empty list should fail" wordlist_get_nth 'foo.bar' '' 0 << END
out: 'NULL'
END
TEST "wordlist get item past end should fail" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 3 << END
out: 'NULL'
END
TEST "wordlist get first item" wordlist_get_nth 'foo.bar' 'baz barf gnarf' 0 << END
out: 'baz'
END
TEST "wordlist get last item" wordlist_get_nth 'foo.bar' 'baz barf; gnarf' 2 << END
out: 'gnarf'
END
TEST "wordlist get middle" wordlist_get_nth 'foo.bar' 'baz barf, gnarf' 1 << END
out: 'barf'
END

View file

@ -48,6 +48,11 @@ test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c
test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_luid_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-interfaces
test_interfaces_SOURCES = $(tests_srcdir)/backend/test-interfaces.c
test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_interfaces_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-filedescriptors
test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c
test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror

View file

@ -83,6 +83,36 @@ TEST ("lookup")
}
TEST ("change_value")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
lumiera_config_init ("./");
const char* value;
if (!lumiera_config_set (argv[2], argv[3]))
printf ("failure setting first time '%s%s': %s\n", argv[2], argv[3], lumiera_error ());
if (lumiera_config_get (argv[2], &value))
printf ("%s\n", value);
else
printf ("failure retrieving '%s': %s\n", argv[2], lumiera_error ());
if (!lumiera_config_set (argv[2], argv[4]))
printf ("failure setting second time '%s%s': %s\n", argv[2], argv[4], lumiera_error ());
if (lumiera_config_get (argv[2], &value))
printf ("%s\n", value);
else
printf ("failure retrieving '%s': %s\n", argv[2], lumiera_error ());
lumiera_config_destroy ();
}
TEST ("basic_set_get")
{
REQUIRE (argv[2]);
@ -258,6 +288,7 @@ TEST ("configitem_simple_ctor_dtor")
lumiera_config_destroy ();
}
TEST ("configitem_simple_content_check")
{
REQUIRE (argv[2]);
@ -287,4 +318,95 @@ TEST ("configitem_simple_content_check")
lumiera_config_destroy ();
}
TEST ("wordlist_get_nth")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
const char* word = lumiera_config_wordlist_get_nth (argv[2], atoi (argv[4]));
printf ("'%s'\n", word?word:"NULL");
lumiera_config_destroy ();
}
TEST ("wordlist_find")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
int n = lumiera_config_wordlist_find (argv[2], argv[4]);
printf ("'%d'\n", n);
lumiera_config_destroy ();
}
TEST ("wordlist_replace")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
REQUIRE (argv[5]);
REQUIRE (argv[6]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
const char* wordlist = lumiera_config_wordlist_replace (argv[2], argv[4], *argv[5]?argv[5]:NULL, *argv[6]?argv[6]:NULL);
if (wordlist)
printf ("'%s'\n", wordlist);
else
printf ("%s\n", lumiera_error ());
lumiera_config_destroy ();
}
TEST ("wordlist_add")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
REQUIRE (argv[4]);
REQUIRE (argv[5]);
lumiera_config_init ("./");
if (!lumiera_config_wordlist_set (argv[2], &argv[3]))
printf ("failed setting word '%s=%s': %s\n", argv[2], argv[3], lumiera_error ());
const char* wordlist = lumiera_config_wordlist_add (argv[2], argv[4]);
if (wordlist)
printf ("'%s'\n", wordlist);
else
printf ("%s\n", lumiera_error ());
wordlist = lumiera_config_wordlist_add (argv[2], argv[5]);
if (wordlist)
printf ("'%s'\n", wordlist);
else
printf ("%s\n", lumiera_error ());
lumiera_config_destroy ();
}
TESTS_END

View file

@ -0,0 +1,452 @@
/*
test-interfaces.c - test interfaces declaration and implementation
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 "backend/interface.h"
#include "backend/interfaceregistry.h"
#include "backend/interfacedescriptor.h"
#include "tests/test.h"
/*
define 2 example interfaces
*/
LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_one, 0,
LUMIERA_INTERFACE_SLOT (void, foo1, (const char*)),
LUMIERA_INTERFACE_SLOT (void, bar1, (const char*)),
);
LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_two, 0,
LUMIERA_INTERFACE_SLOT (void, foo2, (const char*)),
LUMIERA_INTERFACE_SLOT (void, bar2, (const char*)),
);
LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_void, 0
);
/*
now the functions we want to bind to them
*/
void
testfunc (const char* message)
{
printf ("Called as '%s'\n", message);
}
LumieraInterface
testacquire (LumieraInterface self)
{
printf ("Acquire %s_%d_%s\n", self->interface, self->version, self->name);
return self;
}
void
testrelease (LumieraInterface self)
{
printf ("Release %s_%d_%s\n", self->interface, self->version, self->name);
}
/*
implementation of some example interfaces
*/
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0,
lumieraorg_tests_descriptor,
/*self reference, yay*/
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire,
testrelease,
LUMIERA_INTERFACE_INLINE (name, "\073\003\054\127\344\046\324\321\221\262\232\026\376\123\125\243",
const char*, (LumieraInterface iface),
{return "Lumiera Test suite examples";}
),
LUMIERA_INTERFACE_INLINE (version, "\271\330\345\066\304\217\211\065\157\120\031\365\304\363\364\074",
const char*, (LumieraInterface iface),
{return "No Version";}
),
LUMIERA_INTERFACE_INLINE (author, "\367\160\342\065\147\007\237\371\141\335\371\131\025\030\257\232",
const char*, (LumieraInterface iface),
{return "Christian Thaeter <ct@pipapo.org>";}
),
LUMIERA_INTERFACE_INLINE (copyright, "\163\106\344\014\251\125\111\252\236\322\174\120\335\225\333\245",
const char*, (LumieraInterface iface),
{
return
"Copyright (C) Lumiera.org\n"
" 2008 Christian Thaeter <ct@pipapo.org>";
}
),
LUMIERA_INTERFACE_INLINE (license, "\343\031\207\122\225\217\014\163\015\023\243\101\165\377\222\350",
const char*, (LumieraInterface iface),
{
return
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
"(at your option) any later version.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
}
)
);
LUMIERA_EXPORT (interfaces_defined_here,
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_one, 0,
lumieraorg_first_test,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire,
testrelease,
LUMIERA_INTERFACE_MAP (foo1, "\214\310\136\372\003\344\163\377\075\100\070\200\375\221\227\324",
testfunc),
LUMIERA_INTERFACE_MAP (bar1, "\262\253\067\211\157\052\212\140\114\334\231\250\340\075\214\030",
testfunc)
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_two, 0,
lumieraorg_second_test,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire,
testrelease,
LUMIERA_INTERFACE_MAP (foo2, "\110\152\002\271\363\052\324\272\373\045\132\270\277\000\271\217",
testfunc),
LUMIERA_INTERFACE_MAP (bar2, "\376\042\027\336\355\113\132\233\350\312\170\077\377\370\356\167",
testfunc)
)
);
/*
Now we rig a cross dependency test
we have 4 instances, the respective acquire/release operations set following up:
one depends on two and three
two depends on one and four
three depends on two and four
four depends on one, two three
These all are empty interfaces with no slots
*/
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) one_keeps_two;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) one_keeps_three;
LumieraInterface
testacquire_one (LumieraInterface self)
{
TRACE (tests, "Acquire one %s_%d_%s", self->interface, self->version, self->name);
one_keeps_two = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
one_keeps_three = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
return self;
}
void
testrelease_one (LumieraInterface self)
{
TRACE (tests, "Release one %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)one_keeps_two);
lumiera_interface_close ((LumieraInterface)one_keeps_three);
}
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) two_keeps_one;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) two_keeps_four;
LumieraInterface
testacquire_two (LumieraInterface self)
{
TRACE (tests, "Acquire two %s_%d_%s", self->interface, self->version, self->name);
two_keeps_one = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
two_keeps_four = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
return self;
}
void
testrelease_two (LumieraInterface self)
{
TRACE (tests, "Release two %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)two_keeps_one);
lumiera_interface_close ((LumieraInterface)two_keeps_four);
}
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) three_keeps_two;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) three_keeps_four;
LumieraInterface
testacquire_three (LumieraInterface self)
{
TRACE (tests, "Acquire three %s_%d_%s", self->interface, self->version, self->name);
three_keeps_two = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
three_keeps_four = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
return self;
}
void
testrelease_three (LumieraInterface self)
{
TRACE (tests, "Release three %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)three_keeps_two);
lumiera_interface_close ((LumieraInterface)three_keeps_four);
}
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) four_keeps_one;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) four_keeps_two;
static LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) four_keeps_three;
LumieraInterface
testacquire_four (LumieraInterface self)
{
TRACE (tests, "Acquire four %s_%d_%s", self->interface, self->version, self->name);
four_keeps_one = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
four_keeps_two = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
four_keeps_three = LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
return self;
}
void
testrelease_four (LumieraInterface self)
{
TRACE (tests, "Release four %s_%d_%s", self->interface, self->version, self->name);
lumiera_interface_close ((LumieraInterface)four_keeps_one);
lumiera_interface_close ((LumieraInterface)four_keeps_two);
lumiera_interface_close ((LumieraInterface)four_keeps_three);
}
LUMIERA_EXPORT (dependencytests,
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_one,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_one,
testrelease_one
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_two,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_two,
testrelease_two
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_three,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_three,
testrelease_three
),
LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_void, 0,
lumieraorg_dependencytest_four,
LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_tests_descriptor),
testacquire_four,
testrelease_four
)
);
TESTS_BEGIN
TEST ("basic")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here());
/* some ugly lowlevel handling tests */
LumieraInterface handle1 =
lumiera_interfaceregistry_interface_find ("lumieraorg_testexample_one", 0, "lumieraorg_first_test");
(LUMIERA_INTERFACE_CAST(lumieraorg_testexample_one, 0)handle1)->bar1 ("this is bar1");
LUMIERA_INTERFACE_TYPE(lumieraorg_testexample_two, 0)* handle2 = LUMIERA_INTERFACE_CAST(lumieraorg_testexample_two, 0)
lumiera_interfaceregistry_interface_find ("lumieraorg_testexample_two", 0, "lumieraorg_second_test");
handle2->foo2 ("this is foo2");
lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here());
lumiera_interfaceregistry_destroy ();
}
TEST ("open_close")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (interfaces_defined_here());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_one, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_one, 0, 0, lumieraorg_first_test);
ENSURE (handle);
handle->bar1 ("this is bar1");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_one")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_two")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_three")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_four")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
ENSURE (handle);
TRACE (tests, "Sucessfully opened");
lumiera_interface_close ((LumieraInterface)handle);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("dependencies_all")
{
lumiera_interfaceregistry_init ();
lumiera_interfaceregistry_bulkregister_interfaces (dependencytests());
TRACE (tests, "OPEN one");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_one =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_one);
ENSURE (handle_one);
TRACE (tests, "OPEN three");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_three =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_three);
ENSURE (handle_three);
TRACE (tests, "OPEN two");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_two =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_two);
ENSURE (handle_two);
TRACE (tests, "OPEN four");
LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_void, 0) handle_four =
LUMIERA_INTERFACE_OPEN (lumieraorg_testexample_void, 0, 0, lumieraorg_dependencytest_four);
ENSURE (handle_four);
TRACE (tests, "Sucessfully OPENED");
TRACE (tests, "CLOSE four");
lumiera_interface_close ((LumieraInterface)handle_four);
TRACE (tests, "CLOSE two");
lumiera_interface_close ((LumieraInterface)handle_two);
TRACE (tests, "CLOSE three");
lumiera_interface_close ((LumieraInterface)handle_three);
TRACE (tests, "CLOSE one");
lumiera_interface_close ((LumieraInterface)handle_one);
lumiera_interfaceregistry_bulkremove_interfaces (dependencytests());
lumiera_interfaceregistry_destroy ();
}
TEST ("highlevel, plugin")
{
}
TESTS_END
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -85,7 +85,46 @@ TEST ("nestedmutexsection")
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("chainedmutexsection")
{
lumiera_mutex m;
lumiera_mutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
lumiera_mutex n;
lumiera_mutex_init (&n, "n_mutexsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("outer mutex locked section\n");
LUMIERA_MUTEX_SECTION_CHAIN (NOBUG_ON, &n)
{
printf ("inner but not outer mutex locked section\n");
}
}
lumiera_mutex_destroy (&n, &NOBUG_FLAG(NOBUG_ON));
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("recursivemutexsection")
{
lumiera_mutex m;
lumiera_recmutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("mutex locked once\n");
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("mutex locked twice\n");
}
}
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("rwlocksection")
{

View file

@ -1,3 +0,0 @@
working example code for Lumiera's plugin system
This directory contains example code which shows how to use specific features.
All examples will be build and run as part of the testsuite

View file

@ -1,37 +0,0 @@
# Copyright (C) Lumiera.org
# 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.
examples_srcdir = $(top_srcdir)/tests/plugin
noinst_PROGRAMS += test-plugin
test_plugin_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Werror
test_plugin_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_plugin_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl
test_plugin_SOURCES = $(examples_srcdir)/plugin_main.c
noinst_HEADERS += $(examples_srcdir)/hello_interface.h
check_LTLIBRARIES += example_plugin.la example_plugin_cpp.la
example_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
example_plugin_la_SOURCES = $(examples_srcdir)/example_plugin.c
# the -rpath option is required, prolly a automake bug?
example_plugin_la_LDFLAGS = -avoid-version -module -rpath $(shell pwd)
example_plugin_cpp_la_CPPFLAGS = $(AM_CPPFLAGS) -Wall -Werror
example_plugin_cpp_la_SOURCES = $(examples_srcdir)/example_plugin.cpp
# the -rpath option is required, prolly a automake bug?
example_plugin_cpp_la_LDFLAGS = -avoid-version -module -rpath $(shell pwd)