From f777f05ab8cbda356a4cf68546c9eeef1f8c64bb Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 15 Oct 2008 00:05:44 +0200 Subject: [PATCH 01/46] plugin.c got removed from lib, let configure check for luid.c --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0ef7ffd00..4df50f245 100644 --- a/configure.ac +++ b/configure.ac @@ -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) From 14a9e95492475df7d7420e1da4c85912f690ea32 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 10 Sep 2008 16:32:59 +0200 Subject: [PATCH 02/46] moved plugin code from lib to backend Plugin management will become stateful. This qualifies it to become a backend subsystem. --- Makefile.am | 1 - src/backend/Makefile.am | 6 ++-- src/{lib => backend}/plugin.c | 0 src/{lib => backend}/plugin.h | 0 src/lib/Makefile.am | 2 -- tests/{plugin => backend}/example_plugin.c | 0 tests/{plugin => backend}/example_plugin.cpp | 0 tests/{plugin => backend}/hello_interface.h | 0 tests/{plugin => backend}/plugin_main.c | 0 tests/plugin/DIR_INFO | 3 -- tests/plugin/Makefile.am | 37 -------------------- 11 files changed, 4 insertions(+), 45 deletions(-) rename src/{lib => backend}/plugin.c (100%) rename src/{lib => backend}/plugin.h (100%) rename tests/{plugin => backend}/example_plugin.c (100%) rename tests/{plugin => backend}/example_plugin.cpp (100%) rename tests/{plugin => backend}/hello_interface.h (100%) rename tests/{plugin => backend}/plugin_main.c (100%) delete mode 100644 tests/plugin/DIR_INFO delete mode 100644 tests/plugin/Makefile.am diff --git a/Makefile.am b/Makefile.am index f3ae3ef41..d236fbfd8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index abb576021..ce63e44de 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -23,6 +23,7 @@ liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ $(liblumibackend_a_srcdir)/backend.c \ + $(liblumibackend_a_srcdir)/plugin.c \ $(liblumibackend_a_srcdir)/file.c \ $(liblumibackend_a_srcdir)/filehandle.c \ $(liblumibackend_a_srcdir)/filedescriptor.c \ @@ -30,19 +31,20 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/config.c \ $(liblumibackend_a_srcdir)/config_typed.c \ $(liblumibackend_a_srcdir)/configentry.c \ - $(liblumibackend_a_srcdir)/configitem.c \ + $(liblumibackend_a_srcdir)/configitem.c \ $(liblumibackend_a_srcdir)/config_lookup.c noinst_HEADERS += \ $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ $(liblumibackend_a_srcdir)/backend.h \ + $(liblumibackend_a_srcdir)/plugin.h \ $(liblumibackend_a_srcdir)/file.h \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ $(liblumibackend_a_srcdir)/filehandlecache.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 diff --git a/src/lib/plugin.c b/src/backend/plugin.c similarity index 100% rename from src/lib/plugin.c rename to src/backend/plugin.c diff --git a/src/lib/plugin.h b/src/backend/plugin.h similarity index 100% rename from src/lib/plugin.h rename to src/backend/plugin.h diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index e7c22abdb..eab9b1465 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -21,7 +21,6 @@ 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 \ @@ -35,7 +34,6 @@ liblumi_a_SOURCES = \ $(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 \ diff --git a/tests/plugin/example_plugin.c b/tests/backend/example_plugin.c similarity index 100% rename from tests/plugin/example_plugin.c rename to tests/backend/example_plugin.c diff --git a/tests/plugin/example_plugin.cpp b/tests/backend/example_plugin.cpp similarity index 100% rename from tests/plugin/example_plugin.cpp rename to tests/backend/example_plugin.cpp diff --git a/tests/plugin/hello_interface.h b/tests/backend/hello_interface.h similarity index 100% rename from tests/plugin/hello_interface.h rename to tests/backend/hello_interface.h diff --git a/tests/plugin/plugin_main.c b/tests/backend/plugin_main.c similarity index 100% rename from tests/plugin/plugin_main.c rename to tests/backend/plugin_main.c diff --git a/tests/plugin/DIR_INFO b/tests/plugin/DIR_INFO deleted file mode 100644 index c051168cc..000000000 --- a/tests/plugin/DIR_INFO +++ /dev/null @@ -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 diff --git a/tests/plugin/Makefile.am b/tests/plugin/Makefile.am deleted file mode 100644 index c8cf9a22f..000000000 --- a/tests/plugin/Makefile.am +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) Lumiera.org -# 2007, Christian Thaeter -# -# 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) From 973348fdb82a19979aa74399443311a2949cf7aa Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 13 Sep 2008 10:42:54 +0200 Subject: [PATCH 03/46] preprocessor metaprogramming ftw Added a header for generalized preprocessor idioms. This will grow over time, as needed things will be added. --- src/lib/ppmpl.h | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/lib/ppmpl.h diff --git a/src/lib/ppmpl.h b/src/lib/ppmpl.h new file mode 100644 index 000000000..62de24104 --- /dev/null +++ b/src/lib/ppmpl.h @@ -0,0 +1,84 @@ +/* + ppmpl.h - preprocessor meta programming library + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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} + */ +#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(...) + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From 4d65f0394d0f705ffd0332ace350e9ae2b8661ec Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 14 Sep 2008 11:15:30 +0200 Subject: [PATCH 04/46] Add FOREACH variants for nesting to ppmpl Three levels of nesting are enough for anyone! --- src/lib/ppmpl.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/lib/ppmpl.h b/src/lib/ppmpl.h index 62de24104..f1553ccd0 100644 --- a/src/lib/ppmpl.h +++ b/src/lib/ppmpl.h @@ -46,6 +46,10 @@ * * 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)) @@ -74,6 +78,67 @@ #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(...) + + #endif /* // Local Variables: From 16d2fcf2e95531dd07d8eab6e4d572b684fa9d15 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 14 Sep 2008 19:06:20 +0200 Subject: [PATCH 05/46] macro for initializing a uchar[16] from a string literal in C++ --- src/lib/luid.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/lib/luid.h b/src/lib/luid.h index a93d004a3..553d22765 100644 --- a/src/lib/luid.h +++ b/src/lib/luid.h @@ -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 From 7d863679096f66e3b90fe71e2b106f4fe9162a98 Mon Sep 17 00:00:00 2001 From: Nicholas Sinnott-Armstrong Date: Mon, 15 Sep 2008 18:45:05 -0400 Subject: [PATCH 06/46] Added preliminary support for chained mutex calls. --- src/lib/mutex.h | 33 +++++++++++++++++++++++++++++++++ tests/15locking.tests | 6 ++++++ tests/library/test-locking.c | 22 +++++++++++++++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 681d29432..0de69c2f7 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -60,6 +60,39 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); } \ })) +/** + * Mutual exclusion chainbuilder section. + * Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(a,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, mtxa, mtxb) \ + for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ + lumiera_mutex_section_.mutex;) \ + for ( \ + ({ \ + lumiera_mutex_section_.mutex = (mtxb); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ + RESOURCE_ENTER (nobugflag, (mtxb)->rh, "acquire mutex", &lumiera_mutex_section_, \ + NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \ + if (pthread_mutex_lock (&(mtxb)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ + if (mtxa) \ + { \ + pthread_mutex_unlock (&mtxa->mutex); \ + mtxa = NULL; \ + RESOURCE_LEAVE(nobugflag, mtxa.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. diff --git a/tests/15locking.tests b/tests/15locking.tests index c7e8340e5..fab6431bf 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -18,6 +18,12 @@ out: inner mutex locked section END +TEST "chained mutex section" chainedmutexsection < Date: Tue, 16 Sep 2008 15:15:34 +0200 Subject: [PATCH 07/46] add a static initializer to psplay.h --- src/lib/psplay.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/psplay.h b/src/lib/psplay.h index 26639910a..b3c016c52 100644 --- a/src/lib/psplay.h +++ b/src/lib/psplay.h @@ -51,6 +51,7 @@ struct psplaynode_struct PSplaynode right; }; +#define PSPLAYNODE_INITIALIZER {NULL, NULL} /** * Function use to compare keys From a7f75b3f6f5ed4513c4e8461a096b2d7b5b71621 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 16 Sep 2008 15:16:39 +0200 Subject: [PATCH 08/46] preprocessor concat implementation which evaluates its arguments --- src/lib/ppmpl.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib/ppmpl.h b/src/lib/ppmpl.h index f1553ccd0..3a175c322 100644 --- a/src/lib/ppmpl.h +++ b/src/lib/ppmpl.h @@ -138,6 +138,11 @@ #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 #endif /* From 2a723bc5bae63b5d842942491d25655413a7dcce Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 19 Sep 2008 15:39:12 +0200 Subject: [PATCH 09/46] add 'STRINGIFY' to ppmpl.h --- src/lib/ppmpl.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/ppmpl.h b/src/lib/ppmpl.h index 3a175c322..edc7bec7c 100644 --- a/src/lib/ppmpl.h +++ b/src/lib/ppmpl.h @@ -144,6 +144,10 @@ #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: From 9cdfd02e9b8d5f242c4f8c6ff765f8cfe93bd871 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 19 Sep 2008 15:46:25 +0200 Subject: [PATCH 10/46] makefile update for library --- src/lib/Makefile.am | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index eab9b1465..0b42926ad 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -20,17 +20,19 @@ noinst_LIBRARIES += liblumi.a liblumi_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror -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_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)/interface.c \ + $(liblumi_a_srcdir)/interfacedescriptor.c \ $(liblumi_a_srcdir)/appconfig.cpp noinst_HEADERS += \ @@ -44,6 +46,9 @@ 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)/interface.h \ + $(liblumi_a_srcdir)/interfacedescriptor.h \ $(liblumi_a_srcdir)/appconfig.hpp \ $(liblumi_a_srcdir)/lifecycleregistry.hpp From ed246ab2224667db40faa8021da2bfa61063ac38 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 27 Sep 2008 04:19:43 +0200 Subject: [PATCH 11/46] Adding recursive mutexes, fix chained mutex to take only one parameter Recursive mutex can be locked multiple times by a single thread they are initialitzed by lumiera_recmutex_init() and used by LUMIERA_RECMUTEX_* macros. Chained mutex use the mutexacquirer from the outer scope now. Maybe its later needed to pass acquirers explicit, we will see. --- src/lib/mutex.c | 24 +++++++++ src/lib/mutex.h | 97 +++++++++++++++++++++++++++++++----- tests/15locking.tests | 6 +++ tests/library/test-locking.c | 23 ++++++++- 4 files changed, 136 insertions(+), 14 deletions(-) diff --git a/src/lib/mutex.c b/src/lib/mutex.c index 99ef8897f..b228de746 100644 --- a/src/lib/mutex.c +++ b/src/lib/mutex.c @@ -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) { diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 0de69c2f7..9645cfd35 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -62,27 +62,28 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); /** * Mutual exclusion chainbuilder section. - * Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_MUTEX_SECTION_CHAIN(a,b){run();}} + * 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, mtxa, mtxb) \ - for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ +#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}; \ lumiera_mutex_section_.mutex;) \ for ( \ ({ \ - lumiera_mutex_section_.mutex = (mtxb); \ + lumiera_mutex_section_.mutex = (mtx); \ NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ - RESOURCE_ENTER (nobugflag, (mtxb)->rh, "acquire mutex", &lumiera_mutex_section_, \ + RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \ NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \ - if (pthread_mutex_lock (&(mtxb)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ - if (mtxa) \ - { \ - pthread_mutex_unlock (&mtxa->mutex); \ - mtxa = NULL; \ - RESOURCE_LEAVE(nobugflag, mtxa.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; \ ({ \ @@ -94,6 +95,68 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); } \ })) + +/** + * Recursive Mutual exclusive section. + */ +#define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \ + for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ + lumiera_mutex_section_.mutex;) \ + for ( \ + ({ \ + lumiera_mutex_section_.mutex = (mtx); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ + RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_mutex_section_, \ + NOBUG_RESOURCE_RECURSIVE, lumiera_mutex_section_.rh); \ + if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ + }); \ + lumiera_mutex_section_.mutex; \ + ({ \ + if (lumiera_mutex_section_.mutex) \ + { \ + pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \ + lumiera_mutex_section_.mutex = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \ + } \ + })) + + +/** + * Mutual exclusion chainbuilder section. + * Usage: LUMIERA_MUTEX_SECTION(a){LUMIERA_RECMUTEX_SECTION_CHAIN(b){run();}} + * calls lock(a); lock(b); unlock(a); run(); unlock(b); + * This macro should only be used inside LUMIERA_MUTEX_SECTION and should be + * called on the correct mutexes, period. + */ +#define LUMIERA_RECMUTEX_SECTION_CHAIN(nobugflag, mtx) \ + for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \ + NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ + 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. * @@ -109,12 +172,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 diff --git a/tests/15locking.tests b/tests/15locking.tests index fab6431bf..3420f3fa1 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -24,6 +24,12 @@ out: inner but not outer mutex locked section END +TEST "recursive mutex section" recursivemutexsection < Date: Sun, 28 Sep 2008 03:49:28 +0200 Subject: [PATCH 12/46] use a recursive mutex to lock interface operations locking interfaceregistry operations and later on open/close etc --- src/backend/interfaceregistry.c | 206 ++++++++++++++++++++++++++++++++ src/backend/interfaceregistry.h | 77 ++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 src/backend/interfaceregistry.c create mode 100644 src/backend/interfaceregistry.h diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c new file mode 100644 index 000000000..89d26fe60 --- /dev/null +++ b/src/backend/interfaceregistry.c @@ -0,0 +1,206 @@ +/* + interfaceregistry.c - Lumiera interface registry + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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 + + + +#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 (interfaceregistry, backend); + +static PSplay interfaceregistry; +lumiera_mutex lumiera_interface_mutex; + + +static int +cmp_fn (const void* keya, const void* keyb); + +static const void* +key_fn (const PSplaynode node); + + + +/** + * Initialize the interface registry + */ +void +lumiera_interfaceregistry_init (void) +{ + NOBUG_INIT_FLAG (interfaceregistry); + TRACE (interfaceregistry); + REQUIRE (!interfaceregistry); + + interfaceregistry = psplay_new (cmp_fn, key_fn, NULL); + if (!interfaceregistry) + LUMIERA_DIE (ERRNO); + + lumiera_recmutex_init (&lumiera_interface_mutex, "interfaceregistry", &NOBUG_FLAG(interfaceregistry)); +} + +void +lumiera_interfaceregistry_destroy (void) +{ + TRACE (interfaceregistry); + REQUIRE (!psplay_nelements (interfaceregistry)); + + lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry)); + + if (interfaceregistry) + psplay_destroy (interfaceregistry); + 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 (interfaceregistry, &self->node, 100); + } +} + + +void +lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self) +{ + TRACE (interfaceregistry); + REQUIRE (self); + + LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + { + while (*self) + { + psplay_insert (interfaceregistry, &(*self)->node, 100); + ++self; + } + } +} + + +void +lumiera_interfaceregistry_remove_interface (LumieraInterface self) +{ + TRACE (interfaceregistry); + REQUIRE (self); + + LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + { + psplay_remove (interfaceregistry, &self->node); + } +} + + +void +lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self) +{ + TRACE (interfaceregistry); + REQUIRE (self); + + LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + { + while (*self) + { + psplay_remove (interfaceregistry, &(*self)->node); + ++self; + } + } +} + + +LumieraInterface +lumiera_interfaceregistry_interface_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; + + LumieraInterface ret = NULL; + + LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + { + ret = (LumieraInterface)psplay_find (interfaceregistry, &cmp, 100); + } + + return ret; +} + + +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 node; +} + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/interfaceregistry.h b/src/backend/interfaceregistry.h new file mode 100644 index 000000000..20f765c90 --- /dev/null +++ b/src/backend/interfaceregistry.h @@ -0,0 +1,77 @@ +/* + interfaceregistry.h - Lumiera interface registry + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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/interface.h" + +#include + + +/** + * @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 (interfaceregistry); + +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); + +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: +*/ From 38f2a9c6c90161ff3a4ee36490de4e7f3708914a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 9 Oct 2008 18:28:44 +0200 Subject: [PATCH 13/46] add a lumiera_realloc() function to the safeclib --- src/lib/safeclib.c | 11 +++++++++++ src/lib/safeclib.h | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/lib/safeclib.c b/src/lib/safeclib.c index 1c5cf28c6..7f8f79eb2 100644 --- a/src/lib/safeclib.c +++ b/src/lib/safeclib.c @@ -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) { diff --git a/src/lib/safeclib.h b/src/lib/safeclib.h index 79f10d024..d949595f8 100644 --- a/src/lib/safeclib.h +++ b/src/lib/safeclib.h @@ -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 From dd9e5051baeb46e40602bc25127a62640348a10f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 10 Oct 2008 00:56:13 +0200 Subject: [PATCH 14/46] use nobug's new RESOURCE_HANDLE_COMMA_INITIALIZER and some cosmetics along --- src/lib/mutex.h | 148 +++++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 72 deletions(-) diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 9645cfd35..86fb48944 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -39,25 +39,26 @@ 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}; \ - lumiera_mutex_section_.mutex;) \ - for ( \ - ({ \ - lumiera_mutex_section_.mutex = (mtx); \ - NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ - RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \ - NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ - }); \ - lumiera_mutex_section_.mutex; \ - ({ \ - if (lumiera_mutex_section_.mutex) \ - { \ - pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \ - lumiera_mutex_section_.mutex = NULL; \ - RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \ - } \ +#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \ + for (lumiera_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); \ + } \ })) /** @@ -67,32 +68,33 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); * This macro should only be used inside LUMIERA_MUTEX_SECTION and should be * called on the correct mutexes, period. */ -#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \ - for (lumiera_mutexacquirer *lumiera_mutex_section_old_ = &lumiera_mutex_section_, \ - NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ - lumiera_mutex_section_.mutex;) \ - for ( \ - ({ \ - lumiera_mutex_section_.mutex = (mtx); \ - NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ - RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \ - NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ - if (lumiera_mutex_section_old_->mutex) \ - { \ - pthread_mutex_unlock (&lumiera_mutex_section_old_->mutex->mutex); \ - lumiera_mutex_section_old_->mutex = NULL; \ - RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_old_->rh); \ - } \ - }); \ - lumiera_mutex_section_.mutex; \ - ({ \ - if (lumiera_mutex_section_.mutex) \ - { \ - pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \ - lumiera_mutex_section_.mutex = NULL; \ - RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \ - } \ +#define LUMIERA_MUTEX_SECTION_CHAIN(nobugflag, mtx) \ + for (lumiera_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); \ + } \ })) @@ -100,7 +102,8 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); * Recursive Mutual exclusive section. */ #define LUMIERA_RECMUTEX_SECTION(nobugflag, mtx) \ - for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \ + for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1 \ + NOBUG_RESOURCE_HANDLE_COMMA_INITIALIZER}; \ lumiera_mutex_section_.mutex;) \ for ( \ ({ \ @@ -128,32 +131,33 @@ LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); * This macro should only be used inside LUMIERA_MUTEX_SECTION and should be * called on the correct mutexes, period. */ -#define LUMIERA_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}; \ - lumiera_mutex_section_.mutex;) \ - for ( \ - ({ \ - lumiera_mutex_section_.mutex = (mtx); \ - NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \ - RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire recmutex", &lumiera_mutex_section_, \ - NOBUG_RESOURCE_RECURSIVE, lumiera_mutex_section_.rh); \ - if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ - if (lumiera_mutex_section_old_->mutex) \ - { \ - pthread_mutex_unlock (&lumiera_mutex_section_old_->mutex->mutex); \ - lumiera_mutex_section_old_->mutex = NULL; \ - RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_old_->rh); \ - } \ - }); \ - lumiera_mutex_section_.mutex; \ - ({ \ - if (lumiera_mutex_section_.mutex) \ - { \ - pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \ - lumiera_mutex_section_.mutex = NULL; \ - RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \ - } \ +#define LUMIERA_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); \ + } \ })) From f754e1521f4145fbad6ff05bc4c228299d0324d9 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 22 Sep 2008 22:38:17 +0200 Subject: [PATCH 15/46] Start of a 'wordlist' type for the config subsystem wordlists are simple not quoted words delimited by semicolon, tab, space or commas. Some special functions will allow to access each of this words by index etc. --- src/backend/Makefile.am | 1 + src/backend/config.h | 7 ++- src/backend/config_wordlist.c | 95 ++++++++++++++++++++++++++++++++++ tests/22config_highlevel.tests | 22 ++++++++ tests/backend/test-config.c | 21 ++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/backend/config_wordlist.c diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index ce63e44de..2cde41ae2 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -30,6 +30,7 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/filehandlecache.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)/config_lookup.c diff --git a/src/backend/config.h b/src/backend/config.h index 80f33a6d5..a603c2cbf 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -96,6 +96,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) @@ -223,7 +224,11 @@ lumiera_config_setdefault (const char* line); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE - +/** + * special functions for accessing wordlists + */ +const char* +lumiera_config_wordlist_get_nth (const char* key, unsigned nth); // * {{{ 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. diff --git a/src/backend/config_wordlist.c b/src/backend/config_wordlist.c new file mode 100644 index 000000000..3bcbf1ca8 --- /dev/null +++ b/src/backend/config_wordlist.c @@ -0,0 +1,95 @@ +/* + config_wordlist.c - Lumiera wordlist access functions + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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// + + +//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); +} + +#if 0 +int +lumiera_config_wordlist_find (const char* key, const char* value) +{ +} + + +LumieraConfigitem +lumiera_config_wordlist_set_nth (const char* key, const char** value, unsigned nth) +{ +} + +LumieraConfigitem +lumiera_config_wordlist_append (const char* key, const char** value, unsigned nth) +{ +} + +LumieraConfigitem +lumiera_config_wordlist_add (const char* key, const char** value, unsigned nth) +{ +} +#endif + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/tests/22config_highlevel.tests b/tests/22config_highlevel.tests index e0e4995c8..42e2561f3 100644 --- a/tests/22config_highlevel.tests +++ b/tests/22config_highlevel.tests @@ -192,3 +192,25 @@ out: item->key_size = '7' out: item->key = 'key.foo < key.bar' out: item->delim = '< key.bar' 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 + diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index ea312a429..2ed4f4234 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -287,4 +287,25 @@ 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 (); +} + + + TESTS_END From 3f273bb0b10eb2eb5dc57ab8b7bdeae051d2bf20 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 25 Sep 2008 00:07:35 +0200 Subject: [PATCH 16/46] move the configitem tests to the lowlevel suite --- tests/20config_lowlevel.tests | 62 +++++++++++++++++++++++++++++++++ tests/22config_highlevel.tests | 63 ---------------------------------- 2 files changed, 62 insertions(+), 63 deletions(-) diff --git a/tests/20config_lowlevel.tests b/tests/20config_lowlevel.tests index 1bebedcbc..795ed11d8 100644 --- a/tests/20config_lowlevel.tests +++ b/tests/20config_lowlevel.tests @@ -21,6 +21,68 @@ out: delim = '=' out: value = ' baz' END +TEST "create configitem with empty line" configitem_simple_ctor_dtor '' <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' <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 "wordlist get item from empty list should fail" wordlist_get_nth 'foo.bar' '' 0 << END out: 'NULL' END From 7d748a39a7ab0b15adb2c50917964961cc6e7b81 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 25 Sep 2008 00:09:00 +0200 Subject: [PATCH 17/46] add a test for value resetting (I wasn't sure it works, but it does) --- tests/20config_lowlevel.tests | 5 +++++ tests/backend/test-config.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/20config_lowlevel.tests b/tests/20config_lowlevel.tests index 795ed11d8..bcc8e71e3 100644 --- a/tests/20config_lowlevel.tests +++ b/tests/20config_lowlevel.tests @@ -21,6 +21,11 @@ out: delim = '=' out: value = ' baz' END +TEST "reset a value" change_value foo.bar '=foo' '=bar' < Date: Thu, 25 Sep 2008 17:29:00 +0200 Subject: [PATCH 18/46] more on config_wordlist * universal replace function * tests * missing declarations --- src/backend/config.h | 6 +++ src/backend/config_typed.c | 47 ++++++++++++++++++ src/backend/config_wordlist.c | 87 +++++++++++++++++++++++++++++++++- tests/22config_highlevel.tests | 51 ++++++++++++++++++++ tests/backend/test-config.c | 44 +++++++++++++++++ 5 files changed, 233 insertions(+), 2 deletions(-) diff --git a/src/backend/config.h b/src/backend/config.h index a603c2cbf..5f711ae0e 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -230,6 +230,12 @@ LUMIERA_CONFIG_TYPES const char* lumiera_config_wordlist_get_nth (const char* key, unsigned nth); +int +lumiera_config_wordlist_find (const char* key, const char* value); + +const char* +lumiera_config_wordlist_replace (const char* key, const char* value, const char* subst1, const char* subst2); + // * {{{ 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. /** diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index ae490ff2b..aec8bbc68 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -228,6 +228,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_RDLOCK_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_WRLOCK_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 diff --git a/src/backend/config_wordlist.c b/src/backend/config_wordlist.c index 3bcbf1ca8..cbaa68d86 100644 --- a/src/backend/config_wordlist.c +++ b/src/backend/config_wordlist.c @@ -28,6 +28,7 @@ #include "backend/config.h" //TODO: internal/static forward declarations// +extern LumieraConfig lumiera_global_config; //TODO: System includes// @@ -61,15 +62,91 @@ lumiera_config_wordlist_get_nth (const char* key, unsigned nth) return lumiera_tmpbuf_strndup (value, len); } -#if 0 + 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; + + LUMIERA_WRLOCK_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; +} + + + +#if 0 + + LumieraConfigitem -lumiera_config_wordlist_set_nth (const char* key, const char** value, unsigned nth) +lumiera_config_wordlist_remove_nth (const char* key, const char** value, unsigned nth) { } @@ -78,6 +155,12 @@ lumiera_config_wordlist_append (const char* key, const char** value, unsigned nt { } +LumieraConfigitem +lumiera_config_wordlist_preprend (const char* key, const char** value, unsigned nth) +{ +} + + LumieraConfigitem lumiera_config_wordlist_add (const char* key, const char** value, unsigned nth) { diff --git a/tests/22config_highlevel.tests b/tests/22config_highlevel.tests index 0349fa8fe..e2400c6ff 100644 --- a/tests/22config_highlevel.tests +++ b/tests/22config_highlevel.tests @@ -151,3 +151,54 @@ TEST "wordlist get middle" wordlist_get_nth 'foo.bar' 'baz barf, gnarf' 1 << END out: 'barf' END +TEST "wordlist find, non existing" wordlist_find 'foo.bar' 'baz barf, gnarf' blah << END +out: '-1' +END + +TEST "wordlist find, first" wordlist_find 'foo.bar' 'baz barf, gnarf' baz << END +out: '0' +END + +TEST "wordlist find, middle" wordlist_find 'foo.bar' 'baz barf, gnarf' barf << END +out: '1' +END + +TEST "wordlist find, last" wordlist_find 'foo.bar' 'baz barf, gnarf' gnarf << END +out: '2' +END + +TEST "wordlist replace, middle, insert after" wordlist_replace 'foo.bar' 'baz barf gnarf' barf barf foof << END +out: ' baz barf foof gnarf' +END + +TEST "wordlist replace, middle, insert before" wordlist_replace 'foo.bar' 'baz barf gnarf' barf foof barf << END +out: ' baz foof barf gnarf' +END + +TEST "wordlist replace, middle, remove" wordlist_replace 'foo.bar' 'baz barf gnarf' barf '' '' << END +out: ' baz gnarf' +END + +TEST "wordlist replace, middle, replace1" wordlist_replace 'foo.bar' 'baz barf gnarf' barf 'foof' '' << END +out: ' baz foof gnarf' +END + +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 diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index 8f0e5597e..89d6d94ad 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -288,6 +288,7 @@ TEST ("configitem_simple_ctor_dtor") lumiera_config_destroy (); } + TEST ("configitem_simple_content_check") { REQUIRE (argv[2]); @@ -337,5 +338,48 @@ TEST ("wordlist_get_nth") } +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 (); +} + + TESTS_END From b0e60e23e0ae94c789e975684374d5866f8734bc Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 25 Sep 2008 17:34:44 +0200 Subject: [PATCH 19/46] change config rwlock to mutex This was overseen with the splay tree transistion. lookups mutate the structure, thus it needs to be locked completely. --- src/backend/config.c | 6 +++--- src/backend/config.h | 13 +++---------- src/backend/config_typed.c | 16 ++++++++-------- src/backend/config_wordlist.c | 2 +- 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 2e724be08..8c917eb8e 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -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); @@ -290,7 +290,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)) diff --git a/src/backend/config.h b/src/backend/config.h index 5f711ae0e..b87f8e2bf 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -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; @@ -198,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 */ diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index aec8bbc68..d17ed77a3 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -66,7 +66,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 +94,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)); @@ -195,7 +195,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 +218,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)); @@ -240,7 +240,7 @@ lumiera_config_wordlist_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)) { @@ -266,7 +266,7 @@ lumiera_config_wordlist_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)); @@ -309,7 +309,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)) { @@ -332,7 +332,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))); diff --git a/src/backend/config_wordlist.c b/src/backend/config_wordlist.c index cbaa68d86..19378bedf 100644 --- a/src/backend/config_wordlist.c +++ b/src/backend/config_wordlist.c @@ -94,7 +94,7 @@ lumiera_config_wordlist_replace (const char* key, const char* value, const char* size_t vlen = strlen (value); size_t len; - LUMIERA_WRLOCK_SECTION (config_typed, &lumiera_global_config->lock) + LUMIERA_MUTEX_SECTION (config_typed, &lumiera_global_config->lock) { if (lumiera_config_get (key, &wordlist)) { From 211b470e85b4669b480a2edaf635ecb7feed6c02 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 25 Sep 2008 22:26:18 +0200 Subject: [PATCH 20/46] docing existing wordlist funcs --- src/backend/config.h | 34 +++++++++++++++++++++++++++++++++- src/backend/config_wordlist.c | 3 --- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/backend/config.h b/src/backend/config.h index b87f8e2bf..96e519c0d 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -217,18 +217,50 @@ lumiera_config_setdefault (const char* line); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE + /** - * special functions for accessing wordlists + * 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); + // * {{{ 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. /** diff --git a/src/backend/config_wordlist.c b/src/backend/config_wordlist.c index 19378bedf..acee07562 100644 --- a/src/backend/config_wordlist.c +++ b/src/backend/config_wordlist.c @@ -33,9 +33,6 @@ 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) { From 2ae274ea51dbd2f9b1d7b6c7ceab6c6335202099 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 26 Sep 2008 03:31:22 +0200 Subject: [PATCH 21/46] add wordlist_add function to add a word to a wordlist --- src/backend/config.h | 9 ++++++ src/backend/config_wordlist.c | 54 +++++++++++++++++++++++++++++----- tests/22config_highlevel.tests | 20 +++++++++++++ tests/backend/test-config.c | 28 ++++++++++++++++++ 4 files changed, 104 insertions(+), 7 deletions(-) diff --git a/src/backend/config.h b/src/backend/config.h index 96e519c0d..0b50c7da2 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -261,6 +261,15 @@ 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. /** diff --git a/src/backend/config_wordlist.c b/src/backend/config_wordlist.c index acee07562..548a4d824 100644 --- a/src/backend/config_wordlist.c +++ b/src/backend/config_wordlist.c @@ -91,6 +91,9 @@ lumiera_config_wordlist_replace (const char* key, const char* value, const char* 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)) @@ -138,15 +141,56 @@ lumiera_config_wordlist_replace (const char* key, const char* value, const char* } +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 - -LumieraConfigitem -lumiera_config_wordlist_remove_nth (const char* key, const char** value, unsigned nth) +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) { @@ -158,10 +202,6 @@ lumiera_config_wordlist_preprend (const char* key, const char** value, unsigned } -LumieraConfigitem -lumiera_config_wordlist_add (const char* key, const char** value, unsigned nth) -{ -} #endif diff --git a/tests/22config_highlevel.tests b/tests/22config_highlevel.tests index e2400c6ff..3d131da3e 100644 --- a/tests/22config_highlevel.tests +++ b/tests/22config_highlevel.tests @@ -202,3 +202,23 @@ 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 diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index 89d6d94ad..deffa7c00 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -381,5 +381,33 @@ TEST ("wordlist_replace") } +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 From fdbab22ce4072a81362561d174d0aeda44849ed6 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 13 Oct 2008 23:39:48 +0200 Subject: [PATCH 22/46] some cosmetics for the config subsystem --- src/backend/config.c | 6 ++++++ src/backend/config_typed.c | 6 ++++++ src/backend/configitem.c | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 8c917eb8e..cec0dbfd8 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -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(); @@ -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; diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index d17ed77a3..963090899 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -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; @@ -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; @@ -349,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; @@ -358,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; diff --git a/src/backend/configitem.c b/src/backend/configitem.c index f3550da38..8015a6e20 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -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)) )) { From de44b83fcd94a8af4414d69313844af8fd9f6b0d Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 14 Sep 2008 19:10:44 +0200 Subject: [PATCH 23/46] New interface header Provides structures used for managing interfaces, macros for declaring and defining interfaces. Convinience macros to bundle buildin and plugin interfaces. --- src/lib/interface.h | 204 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 src/lib/interface.h diff --git a/src/lib/interface.h b/src/lib/interface.h new file mode 100644 index 000000000..bc114f7e7 --- /dev/null +++ b/src/lib/interface.h @@ -0,0 +1,204 @@ +/* + interface.h - Lumiera interface macros and structures + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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" + +/* + Interface declaration macros + */ + +#define LUMIERA_INTERFACE_INAME(name, version) lumiera_interface_##name##_##version +#define LUMIERA_INTERFACE_DNAME(iname, dname, version) dname##_##version##_interface + +#define LUMIERA_INTERFACE_TYPE(name, version) struct LUMIERA_INTERFACE_INAME(name, version) +#define LUMIERA_INTERFACE_CAST(name, version) (LUMIERA_INTERFACE_TYPE(name, version)*) + + + +#define PPMPL_FOREACH_LUMIERA_INTERFACE_SLOT(ret, name, params) ret (*name) params; lumiera_uid name##_uid; + + +#define LUMIERA_INTERFACE_DECLARE(name, version, ...) \ +LUMIERA_INTERFACE_TYPE(name, version) \ +{ \ + lumiera_interface interface_header_; \ + PPMPL_FOREACH(_, __VA_ARGS__) \ +} + + +/* + Interface definition macros + */ + + +#ifdef __cplusplus +#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, uid) \ + function, LUMIERA_UID_INITIALIZER (uid), +#else +#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, uid) \ + .slot = function, .slot##_uid = LUMIERA_UID_INITIALIZER (uid), +#endif + + +/** + * + * + * + * + * + * + * + * + * + * + */ +#define LUMIERA_INTERFACE_INITIALIZER(iname, version, name, descriptor, data, acquire, release, ...) \ +{ \ + { \ + #name, \ + version, \ + sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \ + descriptor, \ + data, \ + acquire, \ + release \ + }, \ + PPMPL_FOREACH(_, __VA_ARGS__) \ +} + + +#define LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ +LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, version) = \ + LUMIERA_INTERFACE_INITIALIZER(iname, version, name, descriptor, data, acquire, release, __VA_ARGS__); + + + +#define PPMPL_FOREACH_L1_P1_LUMIERA_INTERFACE(iname, version, name, descriptor, data, acquire, release, ...) \ +LUMIERA_INTERFACE_DEFINE (iname, version, \ + name, \ + descriptor, \ + data, \ + acquire, \ + release, \ + __VA_ARGS__ \ + ); + + +#define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE(iname, version, name, descriptor, data, acquire, release, ...) \ + &LUMIERA_INTERFACE_DNAME(iname, name, version).interface_header_, + + +#define LUMIERA_PLUGIN(descriptor, data, acquire, release, luid, ...) \ +PPMPL_FOREACH_L1(_P1_, __VA_ARGS__) \ +static const LumieraInterface* \ +plugin_interfaces (void) \ +{ \ + static const LumieraInterface interfaces[] = \ + { \ + PPMPL_FOREACH_L1(_P2_, __VA_ARGS__) \ + NULL \ + }; \ + return interfaces; \ +} \ +LUMIERA_INTERFACE_DEFINE (plugin, 0, \ + lumiera_plugin, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + LUMIERA_INTERFACE_MAP (plugin_interfaces, plugin_interfaces, luid) \ + ) + + + +#define LUMIERA_EXPORT(queryfunc, ...) \ +PPMPL_FOREACH_L1(_P1_, __VA_ARGS__) \ +static const LumieraInterface* \ +queryfunc (void) \ +{ \ + static const LumieraInterface interfaces[] = \ + { \ + PPMPL_FOREACH_L1(_P2_, __VA_ARGS__) \ + NULL \ + }; \ + return interfaces; \ +} \ + + +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 functionppointer 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 */ + const char* name; + /** major version, 0 means experimental */ + unsigned version; + /** size of the whole interface structure (minor version) */ + size_t size; + + /** metadata descriptor, itself a interface (or NULL) */ + LumieraInterface descriptor; + + /** generic data to be used by the implementation */ + void* data; + + /** must be called before this interface is used, might be nested */ + LumieraInterface (*acquire)(LumieraInterface self); + /** called when finished with this interface, must match the acquire calls */ + void (*release)(LumieraInterface self); + + /** placeholder array for the following function slots, C++ doesn't support flexibe arrays */ +#ifndef __cplusplus + lumiera_interfaceslot functions[]; +#endif +}; + + +#endif /* LUMIERA_INTERFACE_H */ +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From f114b04509f333b079bf68de4c61cefbf168ecf7 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 15 Sep 2008 15:55:30 +0200 Subject: [PATCH 24/46] Documentation for the interface system and small refactorings on the fly --- src/lib/interface.h | 248 +++++++++++++++++++++++++++++++++----------- 1 file changed, 186 insertions(+), 62 deletions(-) diff --git a/src/lib/interface.h b/src/lib/interface.h index bc114f7e7..5b3cd6c5d 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -24,21 +24,118 @@ #include "lib/luid.h" #include "lib/ppmpl.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: + * LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, + * LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, + * LUMIERA_INTERFACE_MAP (slot, function, luid), + * ... + * ), + * ... + * ) + * + * There are 2 ways to define collections of interfaces: + * LUMIERA_EXPORT(queryfunc, + * LUMIERA_INTERFACE_DEFINE(...), + * ... + * ) + * to export interfaces from the core. + * + * LUMIERA_PLUGIN(descriptor, data, 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) lumiera_interface_##name##_##version -#define LUMIERA_INTERFACE_DNAME(iname, dname, version) dname##_##version##_interface +/** + * Construct a definition identifier for an interface + * @param iname name of the interface + * @param dname name for the instance + * @param version major version of the interface + */ +#define LUMIERA_INTERFACE_DNAME(iname, dname, version) lumiera_##dname##_##version##_interface + +/** + * 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)*) -#define PPMPL_FOREACH_LUMIERA_INTERFACE_SLOT(ret, name, params) ret (*name) params; lumiera_uid name##_uid; - - +/** + * 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) \ { \ @@ -46,34 +143,34 @@ LUMIERA_INTERFACE_TYPE(name, version) \ 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 LUMIERA_INTERFACE_SLOT(ret, name, params) ret (*name) params; lumiera_uid name##_uid; +#define PPMPL_FOREACH_LUMIERA_INTERFACE_SLOT(ret, name, params) LUMIERA_INTERFACE_SLOT(ret, name, params) + /* Interface definition macros */ -#ifdef __cplusplus -#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, uid) \ - function, LUMIERA_UID_INITIALIZER (uid), -#else -#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, uid) \ - .slot = function, .slot##_uid = LUMIERA_UID_INITIALIZER (uid), -#endif - - /** - * - * - * - * - * - * - * - * - * - * + * 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 data a opaque void* pointer which is passed to the implementation + * @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_INITIALIZER(iname, version, name, descriptor, data, acquire, release, ...) \ +#define LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ +LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, version) = \ { \ { \ #name, \ @@ -88,50 +185,50 @@ LUMIERA_INTERFACE_TYPE(name, version) \ } -#define LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ -LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, version) = \ - LUMIERA_INTERFACE_INITIALIZER(iname, version, name, descriptor, data, acquire, release, __VA_ARGS__); +/** + * Map a function to a interface slot + * @param slot name of the slot to be mapped + * @param function name of the function to be mapped on slot + * @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 + * + * @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 + */ +#ifdef __cplusplus +#define LUMIERA_INTERFACE_MAP(slot, function, luid) \ + function, LUMIERA_UID_INITIALIZER (uid), +#else +#define LUMIERA_INTERFACE_MAP(slot, function, luid) \ + .slot = function, .slot##_uid = LUMIERA_UID_INITIALIZER (luid), +#endif +#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, luid) LUMIERA_INTERFACE_MAP(slot, function, luid) - -#define PPMPL_FOREACH_L1_P1_LUMIERA_INTERFACE(iname, version, name, descriptor, data, acquire, release, ...) \ -LUMIERA_INTERFACE_DEFINE (iname, version, \ - name, \ - descriptor, \ - data, \ - acquire, \ - release, \ - __VA_ARGS__ \ +#define PPMPL_FOREACH_L1_P1_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ +LUMIERA_INTERFACE_DEFINE (iname, version, \ + name, \ + descriptor, \ + data, \ + acquire, \ + release, \ + __VA_ARGS__ \ ); -#define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE(iname, version, name, descriptor, data, acquire, release, ...) \ +#define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ &LUMIERA_INTERFACE_DNAME(iname, name, version).interface_header_, -#define LUMIERA_PLUGIN(descriptor, data, acquire, release, luid, ...) \ -PPMPL_FOREACH_L1(_P1_, __VA_ARGS__) \ -static const LumieraInterface* \ -plugin_interfaces (void) \ -{ \ - static const LumieraInterface interfaces[] = \ - { \ - PPMPL_FOREACH_L1(_P2_, __VA_ARGS__) \ - NULL \ - }; \ - return interfaces; \ -} \ -LUMIERA_INTERFACE_DEFINE (plugin, 0, \ - lumiera_plugin, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - LUMIERA_INTERFACE_MAP (plugin_interfaces, plugin_interfaces, luid) \ - ) - - - +/** + * 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 const LumieraInterface* \ @@ -146,6 +243,33 @@ queryfunc (void) \ } \ +/** + * 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 data a opaque void* pointer which is passed to the implementation + * @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, data, acquire, release, luid, ...) \ +LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \ +LUMIERA_INTERFACE_DEFINE (plugin, 0, \ + lumiera_plugin, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + LUMIERA_INTERFACE_MAP (plugin_interfaces, plugin_interfaces, luid) \ + ) + + + + typedef struct lumiera_interfaceslot_struct lumiera_interfaceslot; typedef lumiera_interfaceslot* LumieraInterfaceslot; @@ -154,7 +278,7 @@ 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 functionppointer and + * 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 @@ -187,8 +311,8 @@ struct lumiera_interface_struct /** called when finished with this interface, must match the acquire calls */ void (*release)(LumieraInterface self); - /** placeholder array for the following function slots, C++ doesn't support flexibe arrays */ #ifndef __cplusplus + /** placeholder array for the following function slots, C++ doesn't support flexible arrays */ lumiera_interfaceslot functions[]; #endif }; From c84d10c9d5663ee5e18c50caea3b415bb738a2b1 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 15 Sep 2008 17:33:43 +0200 Subject: [PATCH 25/46] Add a CALL macro to interface.h --- src/lib/interface.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib/interface.h b/src/lib/interface.h index 5b3cd6c5d..dac45ee91 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -268,6 +268,15 @@ LUMIERA_INTERFACE_DEFINE (plugin, 0, ) +/** + * Calls a function in interface + * @param name name of the interface + * @param version version of the interface + * @param handle pointer to the interface (LumieraInterface) + * @param slot name of the slot to be called + */ +#define LUMIERA_INTERFACE_CALL(name, version, handle, slot) \ + (LUMIERA_INTERFACE_CAST(name, version) handle)->slot typedef struct lumiera_interfaceslot_struct lumiera_interfaceslot; From feb9ba7db9cc9dfc813304cfbc0afc0f58f46324 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 15 Sep 2008 20:42:49 +0200 Subject: [PATCH 26/46] provide some example code for the 'interface' system * test-interfaces.c is just a mockup to show how interfaces are created * fix some bugs introduced with a futile refactoring try at the last commit --- src/lib/interface.h | 37 ++++------ tests/Makefile.am | 5 ++ tests/library/test-interfaces.c | 126 ++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 21 deletions(-) create mode 100644 tests/library/test-interfaces.c diff --git a/src/lib/interface.h b/src/lib/interface.h index dac45ee91..5c1683bae 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -54,13 +54,10 @@ * Any code which want to use this interface must then include its declaration. * * Basic definition of an interface is done by: - * LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, - * LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, - * LUMIERA_INTERFACE_MAP (slot, function, luid), - * ... - * ), - * ... - * ) + * LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, data, acquire, release, + * LUMIERA_INTERFACE_MAP (slot, function, luid), + * ... + * ) * * There are 2 ways to define collections of interfaces: * LUMIERA_EXPORT(queryfunc, @@ -149,8 +146,7 @@ LUMIERA_INTERFACE_TYPE(name, version) \ * @param name name of this slot * @param params parentized list of parameters for the function */ -#define LUMIERA_INTERFACE_SLOT(ret, name, params) ret (*name) params; lumiera_uid name##_uid; -#define PPMPL_FOREACH_LUMIERA_INTERFACE_SLOT(ret, name, params) LUMIERA_INTERFACE_SLOT(ret, name, params) +#define PPMPL_FOREACH_LUMIERA_INTERFACE_SLOT(ret, name, params) ret (*name) params; lumiera_uid name##_uid; /* @@ -169,7 +165,7 @@ LUMIERA_INTERFACE_TYPE(name, version) \ * @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_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ +#define LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, data, acquire, release, ...) \ LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, version) = \ { \ { \ @@ -196,24 +192,23 @@ LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, vers * this would be good style for C too anyways */ #ifdef __cplusplus -#define LUMIERA_INTERFACE_MAP(slot, function, luid) \ +#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, luid) \ function, LUMIERA_UID_INITIALIZER (uid), #else -#define LUMIERA_INTERFACE_MAP(slot, function, luid) \ +#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, luid) \ .slot = function, .slot##_uid = LUMIERA_UID_INITIALIZER (luid), #endif -#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, luid) LUMIERA_INTERFACE_MAP(slot, function, luid) #define PPMPL_FOREACH_L1_P1_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ -LUMIERA_INTERFACE_DEFINE (iname, version, \ - name, \ - descriptor, \ - data, \ - acquire, \ - release, \ - __VA_ARGS__ \ - ); +LUMIERA_INTERFACE_INSTANCE (iname, version, \ + name, \ + descriptor, \ + data, \ + acquire, \ + release, \ + __VA_ARGS__ \ + ); #define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ diff --git a/tests/Makefile.am b/tests/Makefile.am index fa28a115f..f3ae80391 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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)/library/test-interfaces.c +test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror +test_interfaces_LDADD = 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 diff --git a/tests/library/test-interfaces.c b/tests/library/test-interfaces.c new file mode 100644 index 000000000..97c9442c5 --- /dev/null +++ b/tests/library/test-interfaces.c @@ -0,0 +1,126 @@ +/* + test-interfaces.c - test interfaces declaration and implementation + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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/interface.h" +#include "tests/test.h" + +/* + define 2 example interfaces + */ + +LUMIERA_INTERFACE_DECLARE (example1, 0, + LUMIERA_INTERFACE_SLOT (void, foo1, (const char*)), + LUMIERA_INTERFACE_SLOT (void, bar1, (const char*)), +); + +LUMIERA_INTERFACE_DECLARE (example2, 0, + LUMIERA_INTERFACE_SLOT (void, foo2, (const char*)), + LUMIERA_INTERFACE_SLOT (void, bar2, (const char*)), +); + + +/* + now the functions we want to bind to them + */ + +void +testfunc (const char* message) +{ + printf ("Called as '%s'\n", message); +} + + + +/* + implementation of some example interfaces + */ + +LUMIERA_INTERFACE_INSTANCE (example1, 0, + example1_standalone_implementation, + NULL, + NULL, + NULL, + NULL, + LUMIERA_INTERFACE_MAP (foo1, testfunc, + "\066\177\042\305\165\243\236\352\164\250\357\307\211\374\123\066"), + LUMIERA_INTERFACE_MAP (bar1, testfunc, + "\162\335\262\306\101\113\106\055\342\205\300\151\262\073\257\343") + ); + + +LUMIERA_EXPORT (interfaces_defined_here, + LUMIERA_INTERFACE_DEFINE (example1, 0, + example1_implementation, + NULL, + NULL, + NULL, + NULL, + LUMIERA_INTERFACE_MAP (foo1, testfunc, + "\214\310\136\372\003\344\163\377\075\100\070\200\375\221\227\324"), + LUMIERA_INTERFACE_MAP (bar1, testfunc, + "\262\253\067\211\157\052\212\140\114\334\231\250\340\075\214\030") + ), + LUMIERA_INTERFACE_DEFINE (example2, 0, + example2_implementation, + NULL, + NULL, + NULL, + NULL, + LUMIERA_INTERFACE_MAP (foo2, testfunc, + "\110\152\002\271\363\052\324\272\373\045\132\270\277\000\271\217"), + LUMIERA_INTERFACE_MAP (bar2, testfunc, + "\376\042\027\336\355\113\132\233\350\312\170\077\377\370\356\167") + ) + ); + + +TESTS_BEGIN + +TEST ("basic") +{ + interfaces_defined_here(); +} + +TEST ("basic") +{ +} + +TEST ("basic") +{ +} + +TEST ("basic") +{ +} + +TESTS_END + + + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From caa5bd10a0a0358b2e007140ba1fc1830c4a4659 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 16 Sep 2008 15:21:01 +0200 Subject: [PATCH 27/46] interface update * remove the data member from the interface structure * add a psplay node used in a upcoming interface registry * add a INLINE function mapper --- src/lib/interface.h | 84 ++++++++++++++++++++++----------- tests/library/test-interfaces.c | 31 ++++++------ 2 files changed, 72 insertions(+), 43 deletions(-) diff --git a/src/lib/interface.h b/src/lib/interface.h index 5c1683bae..808dfa167 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -23,6 +23,7 @@ #include "lib/luid.h" #include "lib/ppmpl.h" +#include "lib/psplay.h" /* TODO better doxygen formating */ @@ -53,9 +54,11 @@ * ) * Any code which want to use this interface must then include its declaration. * - * Basic definition of an interface is done by: - * LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, data, acquire, release, - * LUMIERA_INTERFACE_MAP (slot, function, luid), + * 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}), * ... * ) * @@ -66,7 +69,7 @@ * ) * to export interfaces from the core. * - * LUMIERA_PLUGIN(descriptor, data, acquire, release, luid, + * LUMIERA_PLUGIN(descriptor, acquire, release, luid, * LUMIERA_INTERFACE_DEFINE(...), * ... * ) @@ -160,58 +163,86 @@ LUMIERA_INTERFACE_TYPE(name, version) \ * @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 data a opaque void* pointer which is passed to the implementation * @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, data, acquire, release, ...) \ +#define LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, acquire, release, ...) \ +PPMPL_FOREACH(_P1_, __VA_ARGS__) \ LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, version) = \ { \ { \ + PSPLAYNODE_INITIALIZER, \ #name, \ version, \ sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \ descriptor, \ - data, \ acquire, \ release \ }, \ - PPMPL_FOREACH(_, __VA_ARGS__) \ + PPMPL_FOREACH(_P2_, __VA_ARGS__) \ } /** * Map a function to a interface slot * @param slot name of the slot to be mapped - * @param function name of the function to be mapped on slot * @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 + * 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_LUMIERA_INTERFACE_MAP(slot, function, luid) \ - function, LUMIERA_UID_INITIALIZER (uid), +#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_MAP(slot, luid, function) \ + function, LUMIERA_UID_INITIALIZER (luid), #else -#define PPMPL_FOREACH_LUMIERA_INTERFACE_MAP(slot, function, luid) \ +#define PPMPL_FOREACH_P2_LUMIERA_INTERFACE_MAP(slot, luid, function) \ .slot = function, .slot##_uid = LUMIERA_UID_INITIALIZER (luid), #endif -#define PPMPL_FOREACH_L1_P1_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, data, acquire, release, ...) \ -LUMIERA_INTERFACE_INSTANCE (iname, version, \ - name, \ - descriptor, \ - data, \ - acquire, \ - release, \ - __VA_ARGS__ \ +/** + * 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, data, acquire, release, ...) \ +#define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, acquire, release, ...) \ &LUMIERA_INTERFACE_DNAME(iname, name, version).interface_header_, @@ -244,21 +275,19 @@ queryfunc (void) \ * 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 data a opaque void* pointer which is passed to the implementation * @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, data, acquire, release, luid, ...) \ +#define LUMIERA_PLUGIN(descriptor, acquire, release, luid, ...) \ LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \ LUMIERA_INTERFACE_DEFINE (plugin, 0, \ lumiera_plugin, \ NULL, \ NULL, \ NULL, \ - NULL, \ LUMIERA_INTERFACE_MAP (plugin_interfaces, plugin_interfaces, luid) \ ) @@ -297,6 +326,8 @@ struct lumiera_interfaceslot_struct */ struct lumiera_interface_struct { + /** all known interfaces are registered in a tree */ + psplaynode node; /** name of the interface */ const char* name; /** major version, 0 means experimental */ @@ -307,9 +338,6 @@ struct lumiera_interface_struct /** metadata descriptor, itself a interface (or NULL) */ LumieraInterface descriptor; - /** generic data to be used by the implementation */ - void* data; - /** must be called before this interface is used, might be nested */ LumieraInterface (*acquire)(LumieraInterface self); /** called when finished with this interface, must match the acquire calls */ diff --git a/tests/library/test-interfaces.c b/tests/library/test-interfaces.c index 97c9442c5..71962bf75 100644 --- a/tests/library/test-interfaces.c +++ b/tests/library/test-interfaces.c @@ -58,11 +58,14 @@ LUMIERA_INTERFACE_INSTANCE (example1, 0, NULL, NULL, NULL, - NULL, - LUMIERA_INTERFACE_MAP (foo1, testfunc, - "\066\177\042\305\165\243\236\352\164\250\357\307\211\374\123\066"), - LUMIERA_INTERFACE_MAP (bar1, testfunc, - "\162\335\262\306\101\113\106\055\342\205\300\151\262\073\257\343") + LUMIERA_INTERFACE_INLINE (foo1, "\066\177\042\305\165\243\236\352\164\250\357\307\211\374\123\066", + void, (const char* msg), + { + printf ("inline\n"); + } + ), + LUMIERA_INTERFACE_MAP (bar1, "\162\335\262\306\101\113\106\055\342\205\300\151\262\073\257\343", + testfunc) ); @@ -72,22 +75,20 @@ LUMIERA_EXPORT (interfaces_defined_here, NULL, NULL, NULL, - NULL, - LUMIERA_INTERFACE_MAP (foo1, testfunc, - "\214\310\136\372\003\344\163\377\075\100\070\200\375\221\227\324"), - LUMIERA_INTERFACE_MAP (bar1, testfunc, - "\262\253\067\211\157\052\212\140\114\334\231\250\340\075\214\030") + 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 (example2, 0, example2_implementation, NULL, NULL, NULL, - NULL, - LUMIERA_INTERFACE_MAP (foo2, testfunc, - "\110\152\002\271\363\052\324\272\373\045\132\270\277\000\271\217"), - LUMIERA_INTERFACE_MAP (bar2, testfunc, - "\376\042\027\336\355\113\132\233\350\312\170\077\377\370\356\167") + 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) ) ); From b252807c556a5f6bcd951761e9eed5408cc6a6bd Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 16 Sep 2008 15:38:39 +0200 Subject: [PATCH 28/46] functions for interface acquire/release --- src/lib/interface.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ src/lib/interface.h | 10 +++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/lib/interface.c diff --git a/src/lib/interface.c b/src/lib/interface.c new file mode 100644 index 000000000..7972fe81e --- /dev/null +++ b/src/lib/interface.c @@ -0,0 +1,54 @@ +/* + interface.c - Lumiera interface api + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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/interface.h" + +/** + * @file + * interface api + */ + + +LumieraInterface +lumiera_interface_acquire (LumieraInterface self) +{ + if (self && self->acquire) + return self->acquire (self); + + return self; +} + +void +lumiera_interface_release (LumieraInterface self) +{ + if (self && self->release) + self->release (self); +} + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/interface.h b/src/lib/interface.h index 808dfa167..7e35887f5 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -349,6 +349,16 @@ struct lumiera_interface_struct #endif }; +/* + API to handle interfaces + */ + +LumieraInterface +lumiera_interface_acquire (LumieraInterface self); + +void +lumiera_interface_release (LumieraInterface self); + #endif /* LUMIERA_INTERFACE_H */ /* From 66a114207994774425fbedd5ae2ce21377fbf895 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 19 Sep 2008 15:39:54 +0200 Subject: [PATCH 29/46] apply the new defined nameing rules to interface.h --- src/lib/interface.h | 59 ++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/lib/interface.h b/src/lib/interface.h index 7e35887f5..865c41a62 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -95,7 +95,7 @@ * @param name name of the interface * @param version major version of this interface */ -#define LUMIERA_INTERFACE_INAME(name, version) lumiera_interface_##name##_##version +#define LUMIERA_INTERFACE_INAME(name, version) name##_##version /** * Construct a definition identifier for an interface @@ -103,7 +103,7 @@ * @param dname name for the instance * @param version major version of the interface */ -#define LUMIERA_INTERFACE_DNAME(iname, dname, version) lumiera_##dname##_##version##_interface +#define LUMIERA_INTERFACE_DNAME(iname, dname, version) PPMPL_CAT (LUMIERA_INTERFACE_INAME(name, version), _##dname) /** * Construct the type of the interface @@ -167,20 +167,21 @@ LUMIERA_INTERFACE_TYPE(name, version) \ * @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, name, version) = \ -{ \ - { \ - PSPLAYNODE_INITIALIZER, \ - #name, \ - version, \ - sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \ - descriptor, \ - acquire, \ - release \ - }, \ - PPMPL_FOREACH(_P2_, __VA_ARGS__) \ +#define LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, acquire, release, ...) \ +PPMPL_FOREACH(_P1_, __VA_ARGS__) \ +LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, version) = \ +{ \ +{ \ + PSPLAYNODE_INITIALIZER, \ + #iname, \ + version, \ + #name, \ + sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \ + descriptor, \ + acquire, \ + release \ +}, \ +PPMPL_FOREACH(_P2_, __VA_ARGS__) \ } @@ -283,8 +284,8 @@ queryfunc (void) \ */ #define LUMIERA_PLUGIN(descriptor, acquire, release, luid, ...) \ LUMIERA_EXPORT(plugin_interfaces, __VA_ARGS__) \ -LUMIERA_INTERFACE_DEFINE (plugin, 0, \ - lumiera_plugin, \ +LUMIERA_INTERFACE_DEFINE (lumieraorg_plugin, 0, \ + lumieraorg_plugin_0, \ NULL, \ NULL, \ NULL, \ @@ -292,15 +293,13 @@ LUMIERA_INTERFACE_DEFINE (plugin, 0, ) + /** - * Calls a function in interface - * @param name name of the interface - * @param version version of the interface - * @param handle pointer to the interface (LumieraInterface) - * @param slot name of the slot to be called + * create a handle for a interface (WIP) */ -#define LUMIERA_INTERFACE_CALL(name, version, handle, slot) \ - (LUMIERA_INTERFACE_CAST(name, version) handle)->slot +#define LUMIERA_INTERFACE_HANDLE(interface, version, reserved, name, handle) \ + LUMIERA_INTERFACE_TYPE(interface, version)* handle = LUMIERA_INTERFACE_CAST(interface, 0) \ + lumiera_interfaceregistry_interface_find (#interface, version, #name); typedef struct lumiera_interfaceslot_struct lumiera_interfaceslot; @@ -328,10 +327,16 @@ struct lumiera_interface_struct { /** all known interfaces are registered in a tree */ psplaynode node; - /** name of the interface */ - const char* name; + + /** 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; From 4bfe430f38ccfcfd40984ad5b8a665782104eb59 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 19 Sep 2008 15:45:24 +0200 Subject: [PATCH 30/46] Interfaceregistry for 'active' interfaces All interfaces which are available get registered in a tree. This will be used internal for lookup interfaces. The higher level calls will be an amalgamation of this lookup and the upcoming plugindb and loader. --- src/backend/Makefile.am | 2 ++ src/backend/interfaceregistry.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 2cde41ae2..c452814db 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -28,6 +28,7 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/filehandle.c \ $(liblumibackend_a_srcdir)/filedescriptor.c \ $(liblumibackend_a_srcdir)/filehandlecache.c \ + $(liblumibackend_a_srcdir)/interfaceregistry.c \ $(liblumibackend_a_srcdir)/config.c \ $(liblumibackend_a_srcdir)/config_typed.c \ $(liblumibackend_a_srcdir)/config_wordlist.c \ @@ -44,6 +45,7 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ $(liblumibackend_a_srcdir)/filehandlecache.h \ + $(liblumibackend_a_srcdir)/interfaceregistry.h \ $(liblumibackend_a_srcdir)/config.h \ $(liblumibackend_a_srcdir)/configentry.h \ $(liblumibackend_a_srcdir)/configitem.h \ diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index 89d26fe60..d3f070b56 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -42,7 +42,6 @@ NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, backend); static PSplay interfaceregistry; lumiera_mutex lumiera_interface_mutex; - static int cmp_fn (const void* keya, const void* keyb); From 0342e19c128ff18adac78d0880f1a8e5fdeea814 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 19 Sep 2008 15:47:55 +0200 Subject: [PATCH 31/46] move the interfaces test to backend, because its going to be stateful --- tests/Makefile.am | 4 +- tests/{library => backend}/test-interfaces.c | 44 ++++++++++++++++---- 2 files changed, 37 insertions(+), 11 deletions(-) rename tests/{library => backend}/test-interfaces.c (71%) diff --git a/tests/Makefile.am b/tests/Makefile.am index f3ae80391..0c7f80f12 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -49,9 +49,9 @@ 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)/library/test-interfaces.c +test_interfaces_SOURCES = $(tests_srcdir)/backend/test-interfaces.c test_interfaces_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_interfaces_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +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 diff --git a/tests/library/test-interfaces.c b/tests/backend/test-interfaces.c similarity index 71% rename from tests/library/test-interfaces.c rename to tests/backend/test-interfaces.c index 71962bf75..fb1c4d30a 100644 --- a/tests/library/test-interfaces.c +++ b/tests/backend/test-interfaces.c @@ -20,18 +20,20 @@ */ #include "lib/interface.h" +#include "backend/interfaceregistry.h" +//#include "lib/interfacedescriptor.h" #include "tests/test.h" /* define 2 example interfaces */ -LUMIERA_INTERFACE_DECLARE (example1, 0, +LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_one, 0, LUMIERA_INTERFACE_SLOT (void, foo1, (const char*)), LUMIERA_INTERFACE_SLOT (void, bar1, (const char*)), ); -LUMIERA_INTERFACE_DECLARE (example2, 0, +LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_two, 0, LUMIERA_INTERFACE_SLOT (void, foo2, (const char*)), LUMIERA_INTERFACE_SLOT (void, bar2, (const char*)), ); @@ -53,8 +55,8 @@ testfunc (const char* message) implementation of some example interfaces */ -LUMIERA_INTERFACE_INSTANCE (example1, 0, - example1_standalone_implementation, +LUMIERA_INTERFACE_INSTANCE (lumieraorg_testexample_one, 0, + lumieraorg_standalone_test, NULL, NULL, NULL, @@ -70,8 +72,8 @@ LUMIERA_INTERFACE_INSTANCE (example1, 0, LUMIERA_EXPORT (interfaces_defined_here, - LUMIERA_INTERFACE_DEFINE (example1, 0, - example1_implementation, + LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_one, 0, + lumieraorg_first_test, NULL, NULL, NULL, @@ -80,8 +82,8 @@ LUMIERA_EXPORT (interfaces_defined_here, LUMIERA_INTERFACE_MAP (bar1, "\262\253\067\211\157\052\212\140\114\334\231\250\340\075\214\030", testfunc) ), - LUMIERA_INTERFACE_DEFINE (example2, 0, - example2_implementation, + LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_two, 0, + lumieraorg_second_test, NULL, NULL, NULL, @@ -97,7 +99,31 @@ TESTS_BEGIN TEST ("basic") { - interfaces_defined_here(); + 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"); + + /* higher level, WIP */ + + LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_two, 0, 0, lumieraorg_second_test, handle3); + handle3->bar2 ("this is bar2"); + + lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here()); + lumiera_interfaceregistry_destroy (); } TEST ("basic") From bb9c53d32d4cc9ae932b426986286cbf32df3963 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 21 Sep 2008 23:52:14 +0200 Subject: [PATCH 32/46] change parameter order for _DNAME in interface.h, add a _REF macro --- src/lib/interface.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/lib/interface.h b/src/lib/interface.h index 865c41a62..836ac934c 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -100,10 +100,21 @@ /** * Construct a definition identifier for an interface * @param iname name of the interface - * @param dname name for the instance * @param version major version of the interface + * @param dname name for the instance */ -#define LUMIERA_INTERFACE_DNAME(iname, dname, version) PPMPL_CAT (LUMIERA_INTERFACE_INAME(name, version), _##dname) +#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 @@ -169,7 +180,7 @@ LUMIERA_INTERFACE_TYPE(name, version) \ */ #define LUMIERA_INTERFACE_INSTANCE(iname, version, name, descriptor, acquire, release, ...) \ PPMPL_FOREACH(_P1_, __VA_ARGS__) \ -LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, name, version) = \ +LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, version, name) = \ { \ { \ PSPLAYNODE_INITIALIZER, \ @@ -244,7 +255,7 @@ LUMIERA_INTERFACE_INSTANCE (iname, version, #define PPMPL_FOREACH_L1_P2_LUMIERA_INTERFACE_DEFINE(iname, version, name, descriptor, acquire, release, ...) \ - &LUMIERA_INTERFACE_DNAME(iname, name, version).interface_header_, + &LUMIERA_INTERFACE_DNAME(iname, version, name).interface_header_, /** From c9ac9564176a57a1773d8111be7eebcdbe58ec08 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 21 Sep 2008 23:52:32 +0200 Subject: [PATCH 33/46] cosmetics --- src/lib/interface.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/interface.h b/src/lib/interface.h index 836ac934c..75eb2bb10 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -267,18 +267,18 @@ LUMIERA_INTERFACE_INSTANCE (iname, version, * @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 const LumieraInterface* \ -queryfunc (void) \ -{ \ - static const LumieraInterface interfaces[] = \ - { \ - PPMPL_FOREACH_L1(_P2_, __VA_ARGS__) \ - NULL \ - }; \ - return interfaces; \ -} \ +#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; \ +} /** From 4414af375127c52a620d6d3a5328d9b238a338d7 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 22 Sep 2008 00:00:43 +0200 Subject: [PATCH 34/46] add a 'weak' flag for interface_acquire/release() When interfaces cross depend on each other nested acquiring from their acquire handlers would introduce cyclic references which cant be cleaned easily. By flagging such nested acquisitions as weak the respective handler functions can account for this. Example: maintain 2 ref counters one for strong and one for weak acquisitions. At release time all acquired nested handles get closed when the strong counter drops to zero, which causes that cross reference releases will eventually drop the weak count to zero too. Then all resources can be freed and the interface is properly shut down. --- src/lib/interface.c | 8 ++++---- src/lib/interface.h | 23 +++++++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/lib/interface.c b/src/lib/interface.c index 7972fe81e..0a566534d 100644 --- a/src/lib/interface.c +++ b/src/lib/interface.c @@ -28,19 +28,19 @@ LumieraInterface -lumiera_interface_acquire (LumieraInterface self) +lumiera_interface_acquire (LumieraInterface self, int weak) { if (self && self->acquire) - return self->acquire (self); + return self->acquire (self, weak); return self; } void -lumiera_interface_release (LumieraInterface self) +lumiera_interface_release (LumieraInterface self, int weak) { if (self && self->release) - self->release (self); + self->release (self, weak); } diff --git a/src/lib/interface.h b/src/lib/interface.h index 75eb2bb10..6713fc428 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -354,10 +354,21 @@ struct lumiera_interface_struct /** metadata descriptor, itself a interface (or NULL) */ LumieraInterface descriptor; - /** must be called before this interface is used, might be nested */ - LumieraInterface (*acquire)(LumieraInterface self); - /** called when finished with this interface, must match the acquire calls */ - void (*release)(LumieraInterface self); + /** + * Must be called before this interface is used. + * might be nested. + * @param self pointer to the interface to be acquired + * @param weak indicates a weak aquisition when this is not null. Used to resolve aquisition for cross dependencies + * @return pointer to the interface or NULL on error + */ + LumieraInterface (*acquire)(LumieraInterface self, int weak); + /** + * called when finished using this interface + * must match the acquire calls + * @param self pointer to the interface to be released + * @param weak indicates a weak release, must be the same value as used for the acquire function + */ + void (*release)(LumieraInterface self, int weak); #ifndef __cplusplus /** placeholder array for the following function slots, C++ doesn't support flexible arrays */ @@ -370,10 +381,10 @@ struct lumiera_interface_struct */ LumieraInterface -lumiera_interface_acquire (LumieraInterface self); +lumiera_interface_acquire (LumieraInterface self, int weak); void -lumiera_interface_release (LumieraInterface self); +lumiera_interface_release (LumieraInterface self, int weak); #endif /* LUMIERA_INTERFACE_H */ From a6ddb55e9b352ae3c0027c218d2cdcb1f2d8a0d4 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 28 Sep 2008 03:49:28 +0200 Subject: [PATCH 35/46] use a recursive mutex to lock interface operations locking interfaceregistry operations and later on open/close etc --- src/backend/interfaceregistry.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index d3f070b56..89d26fe60 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -42,6 +42,7 @@ NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, backend); static PSplay interfaceregistry; lumiera_mutex lumiera_interface_mutex; + static int cmp_fn (const void* keya, const void* keyb); From 405a578c42c3dcc1d707e389ac981ed76087597b Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 13 Oct 2008 21:56:23 +0200 Subject: [PATCH 36/46] WIP: interface open/close handling cross dependencies --- src/backend/Makefile.am | 3 +- src/backend/interface.c | 281 ++++++++++++++++++++++++++++++++ src/backend/interfaceregistry.c | 16 +- src/backend/interfaceregistry.h | 2 + src/lib/Makefile.am | 1 - src/lib/interface.c | 54 ------ src/lib/interface.h | 60 +++++-- 7 files changed, 348 insertions(+), 69 deletions(-) create mode 100644 src/backend/interface.c delete mode 100644 src/lib/interface.c diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index c452814db..78ffea592 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -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 \ @@ -28,6 +28,7 @@ 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 \ diff --git a/src/backend/interface.c b/src/backend/interface.c new file mode 100644 index 000000000..a93088213 --- /dev/null +++ b/src/backend/interface.c @@ -0,0 +1,281 @@ +/* + interface.c - Lumiera interface api + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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 "lib/interface.h" + +#include "backend/interfaceregistry.h" + +#include + +/** + * @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. + */ + + +extern LumieraInterface lumiera_interface_stack; + + +LumieraInterface +lumiera_interface_open (const char* interface, unsigned version, size_t minminorversion, const char* name) +{ + LumieraInterface self = NULL; + TRACE (interface, "%s", name); + + LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + { + self = lumiera_interfaceregistry_interface_find (interface, version, name); + + if (!self) + { + UNIMPLEMENTED ("query plugindb and load plugin if exists"); + } + + if (self) + { + if (minminorversion > self->size) + { + UNIMPLEMENTED ("set error"); + self = NULL; + } + else + { + self = lumiera_interface_open_interface (self); + } + } + } + return self; +} + + +static void +push_dependency (LumieraInterface parent, LumieraInterface child) +{ + /* push a dependency on the dependency array, allcoate or resize it on demand */ + TRACE (interface, "%s %s", parent->name, child->name); + + /* no dependencies recorded yet, alloc a first block for 4 pointers */ + if (!parent->ndeps) + parent->deps = lumiera_calloc (parent->ndeps = 4, sizeof (LumieraInterface)); + + size_t sz = parent->ndeps; + LumieraInterface* 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->ndeps + 1; + parent->ndeps *= 2; + parent->deps = lumiera_realloc (parent->deps, parent->ndeps * sizeof (LumieraInterface)); + itr = parent->deps + sz - 2; + memset (itr, 0, sz * sizeof (LumieraInterface)); + } + } + + TODO ("free the deps when unregistering the interface"); + + /* found free element, store self in dependencies */ + *itr = child; +} + + +static void +depwalk (LumieraInterface self, LumieraInterface* stack) +{ + /* increment refcount for all non-cyclic dependencies recursively */ + if (self->deps) + { + TRACE (interface, "%s %d", self->name, self->refcnt); + for (LumieraInterface* dep = self->deps; *dep; ++dep) + { + TRACE (interface, "loop %s", (*dep)->name); + int cycle = 0; + for (LumieraInterface 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; + } + } + } +} + + +LumieraInterface +lumiera_interface_open_interface (LumieraInterface self) +{ + static unsigned collect_dependencies = 0; + static LumieraInterface 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->name, self->refcnt, stack?stack->name:""); + + LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + { + /* discover cycles, cycles don't refcount! */ + int cycle = 0; + + for (LumieraInterface 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->acquire) + { + TRACE (interface, "Acquire %s", self->name); + collect_dependencies = self->deps?0:1; + self = self->acquire (self); + } + } + 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) +{ + static LumieraInterface stack = NULL; + + if (!self) + return; + + TRACE (interface, "%s %d (%s)", self->name, self->refcnt, stack?stack->name:""); + + LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + { + REQUIRE (self->refcnt); + + int cycle = 0; + + for (LumieraInterface 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->release) + { + TRACE (interface, "Release %s", self->name); + self->release (self); + } + } + else + { + if (self->deps) + { + TRACE (interface, "Recurse %s %d", self->name, self->refcnt); + + for (LumieraInterface* dep = self->deps; *dep; ++dep) + lumiera_interface_close (*dep); + } + } + + stack = self->lnk; + self->lnk = NULL; + --self->refcnt; + } + } +} + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index 89d26fe60..799f84b70 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -37,7 +37,9 @@ * by their name and major version. */ -NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, backend); +NOBUG_DEFINE_FLAG_PARENT (interface_all, backend); +NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, interface_all); +NOBUG_DEFINE_FLAG_PARENT (interface, interface_all); static PSplay interfaceregistry; lumiera_mutex lumiera_interface_mutex; @@ -57,10 +59,14 @@ key_fn (const PSplaynode node); void lumiera_interfaceregistry_init (void) { + NOBUG_INIT_FLAG (interface_all); NOBUG_INIT_FLAG (interfaceregistry); + NOBUG_INIT_FLAG (interface); TRACE (interfaceregistry); REQUIRE (!interfaceregistry); + TODO ("introduce a registrynode structure, place all dynamic interface stuff there, make interface_struct const"); + interfaceregistry = psplay_new (cmp_fn, key_fn, NULL); if (!interfaceregistry) LUMIERA_DIE (ERRNO); @@ -106,6 +112,7 @@ lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self) { while (*self) { + TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name); psplay_insert (interfaceregistry, &(*self)->node, 100); ++self; } @@ -121,7 +128,10 @@ lumiera_interfaceregistry_remove_interface (LumieraInterface self) LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) { + REQUIRE (self->refcnt == 0); psplay_remove (interfaceregistry, &self->node); + + FIXME ("free deps"); } } @@ -136,8 +146,12 @@ lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self) { while (*self) { + TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name); + REQUIRE ((*self)->refcnt == 0, "but is %d", (*self)->refcnt); + psplay_remove (interfaceregistry, &(*self)->node); ++self; + FIXME ("free deps"); } } } diff --git a/src/backend/interfaceregistry.h b/src/backend/interfaceregistry.h index 20f765c90..c6bf4a2e5 100644 --- a/src/backend/interfaceregistry.h +++ b/src/backend/interfaceregistry.h @@ -34,7 +34,9 @@ * by their name and major version. */ +NOBUG_DECLARE_FLAG (interface_all); NOBUG_DECLARE_FLAG (interfaceregistry); +NOBUG_DECLARE_FLAG (interface); extern lumiera_mutex lumiera_interface_mutex; diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 0b42926ad..2ad293158 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -31,7 +31,6 @@ liblumi_a_SOURCES = \ $(liblumi_a_srcdir)/psplay.c \ $(liblumi_a_srcdir)/mrucache.c \ $(liblumi_a_srcdir)/time.c \ - $(liblumi_a_srcdir)/interface.c \ $(liblumi_a_srcdir)/interfacedescriptor.c \ $(liblumi_a_srcdir)/appconfig.cpp diff --git a/src/lib/interface.c b/src/lib/interface.c deleted file mode 100644 index 0a566534d..000000000 --- a/src/lib/interface.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - interface.c - Lumiera interface api - - Copyright (C) Lumiera.org - 2008, Christian Thaeter - - 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/interface.h" - -/** - * @file - * interface api - */ - - -LumieraInterface -lumiera_interface_acquire (LumieraInterface self, int weak) -{ - if (self && self->acquire) - return self->acquire (self, weak); - - return self; -} - -void -lumiera_interface_release (LumieraInterface self, int weak) -{ - if (self && self->release) - self->release (self, weak); -} - - - -/* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// indent-tabs-mode: nil -// End: -*/ diff --git a/src/lib/interface.h b/src/lib/interface.h index 6713fc428..16319c244 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -123,6 +123,7 @@ */ #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 @@ -132,7 +133,6 @@ #define LUMIERA_INTERFACE_CAST(name, version) (LUMIERA_INTERFACE_TYPE(name, version)*) - /** * Declare an interface. * @param name name of the interface @@ -167,7 +167,6 @@ LUMIERA_INTERFACE_TYPE(name, version) \ Interface definition macros */ - /** * Define a interface instance. * @param iname name of the interface to instance @@ -188,6 +187,10 @@ LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, version, n version, \ #name, \ sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \ + 0, \ + NULL, \ + 0, \ + NULL, \ descriptor, \ acquire, \ release \ @@ -308,9 +311,12 @@ LUMIERA_INTERFACE_DEFINE (lumieraorg_plugin, 0, /** * create a handle for a interface (WIP) */ -#define LUMIERA_INTERFACE_HANDLE(interface, version, reserved, name, handle) \ - LUMIERA_INTERFACE_TYPE(interface, version)* handle = LUMIERA_INTERFACE_CAST(interface, 0) \ - lumiera_interfaceregistry_interface_find (#interface, version, #name); + +#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; @@ -351,6 +357,12 @@ struct lumiera_interface_struct /** size of the whole interface structure (minor version) */ size_t size; + /** reference counters and link used for internal reference management */ + unsigned refcnt; + LumieraInterface lnk; + size_t ndeps; + LumieraInterface* deps; + /** metadata descriptor, itself a interface (or NULL) */ LumieraInterface descriptor; @@ -358,17 +370,15 @@ struct lumiera_interface_struct * Must be called before this interface is used. * might be nested. * @param self pointer to the interface to be acquired - * @param weak indicates a weak aquisition when this is not null. Used to resolve aquisition for cross dependencies * @return pointer to the interface or NULL on error */ - LumieraInterface (*acquire)(LumieraInterface self, int weak); + LumieraInterface (*acquire)(LumieraInterface self); /** * called when finished using this interface * must match the acquire calls * @param self pointer to the interface to be released - * @param weak indicates a weak release, must be the same value as used for the acquire function */ - void (*release)(LumieraInterface self, int weak); + void (*release)(LumieraInterface self); #ifndef __cplusplus /** placeholder array for the following function slots, C++ doesn't support flexible arrays */ @@ -380,11 +390,37 @@ struct lumiera_interface_struct API to handle interfaces */ -LumieraInterface -lumiera_interface_acquire (LumieraInterface self, int weak); +/** + * Open an interface by handle. + * This is faster because it needs no lookup, one must be sure to have a valid handle + * which mets the requirements (version) + * @param self pointer to the interface to be opened + * @return self on success or NULL on error + * @internal This function is mostly for internal purposes + */ +LumieraInterface +lumiera_interface_open_interface (LumieraInterface self); + +/** + * 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_release (LumieraInterface self, int weak); +lumiera_interface_close (LumieraInterface iface); #endif /* LUMIERA_INTERFACE_H */ From f05f6772f12c3cdfa38096da08084a01f986d7b5 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 14 Oct 2008 23:06:43 +0200 Subject: [PATCH 37/46] Interface system refactoring * lumiera_interface are now static structures, never wrritten * introduced a lumiera_interfacenode which manages the dynamic data of interfaces. The interfaceregistry now holds this nodes. --- src/backend/interface.c | 159 +++++++++++++++++--------------- src/backend/interfaceregistry.c | 84 ++++++++++++----- src/backend/interfaceregistry.h | 32 +++++++ src/lib/interface.h | 25 ----- 4 files changed, 177 insertions(+), 123 deletions(-) diff --git a/src/backend/interface.c b/src/backend/interface.c index a93088213..0150e403e 100644 --- a/src/backend/interface.c +++ b/src/backend/interface.c @@ -36,18 +36,22 @@ */ -extern LumieraInterface lumiera_interface_stack; +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) { - LumieraInterface self = NULL; + LumieraInterfacenode self = NULL; TRACE (interface, "%s", name); LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) { - self = lumiera_interfaceregistry_interface_find (interface, version, name); + self = lumiera_interfaceregistry_interfacenode_find (interface, version, name); if (!self) { @@ -56,33 +60,33 @@ lumiera_interface_open (const char* interface, unsigned version, size_t minminor if (self) { - if (minminorversion > self->size) + if (minminorversion > self->interface->size) { UNIMPLEMENTED ("set error"); self = NULL; } else { - self = lumiera_interface_open_interface (self); + self = lumiera_interface_open_interfacenode (self); } } } - return self; + return self->interface; } static void -push_dependency (LumieraInterface parent, LumieraInterface child) +push_dependency (LumieraInterfacenode parent, LumieraInterfacenode child) { /* push a dependency on the dependency array, allcoate or resize it on demand */ - TRACE (interface, "%s %s", parent->name, child->name); + TRACE (interface, "%s %s", parent->interface->name, child->interface->name); /* no dependencies recorded yet, alloc a first block for 4 pointers */ - if (!parent->ndeps) - parent->deps = lumiera_calloc (parent->ndeps = 4, sizeof (LumieraInterface)); + if (!parent->deps_size) + parent->deps = lumiera_calloc (parent->deps_size = 4, sizeof (LumieraInterfacenode)); - size_t sz = parent->ndeps; - LumieraInterface* itr = parent->deps; + size_t sz = parent->deps_size; + LumieraInterfacenode* itr = parent->deps; while (*itr) { @@ -91,33 +95,31 @@ push_dependency (LumieraInterface parent, LumieraInterface child) if (sz == 1) { /* block to small, realloc it with twice its size, we keep the block NULL terminated */ - sz = parent->ndeps + 1; - parent->ndeps *= 2; - parent->deps = lumiera_realloc (parent->deps, parent->ndeps * sizeof (LumieraInterface)); + 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)); } } - TODO ("free the deps when unregistering the interface"); - /* found free element, store self in dependencies */ *itr = child; } static void -depwalk (LumieraInterface self, LumieraInterface* stack) +depwalk (LumieraInterfacenode self, LumieraInterfacenode* stack) { /* increment refcount for all non-cyclic dependencies recursively */ if (self->deps) { - TRACE (interface, "%s %d", self->name, self->refcnt); - for (LumieraInterface* dep = self->deps; *dep; ++dep) + TRACE (interface, "%s %d", self->interface->name, self->refcnt); + for (LumieraInterfacenode* dep = self->deps; *dep; ++dep) { - TRACE (interface, "loop %s", (*dep)->name); + TRACE (interface, "loop %s", (*dep)->interface->name); int cycle = 0; - for (LumieraInterface itr = *stack; itr; itr = itr->lnk) + for (LumieraInterfacenode itr = *stack; itr; itr = itr->lnk) { if (itr == *dep) { @@ -144,11 +146,11 @@ depwalk (LumieraInterface self, LumieraInterface* stack) } -LumieraInterface -lumiera_interface_open_interface (LumieraInterface self) +static LumieraInterfacenode +lumiera_interface_open_interfacenode (LumieraInterfacenode self) { static unsigned collect_dependencies = 0; - static LumieraInterface stack = NULL; + static LumieraInterfacenode stack = NULL; /* Ok, this got little more complicated than it should be, @@ -157,14 +159,14 @@ lumiera_interface_open_interface (LumieraInterface self) if (self) { - TRACE (interface, "%s %d (%s)", self->name, self->refcnt, stack?stack->name:""); + 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 (LumieraInterface itr = stack; itr; itr = itr->lnk) + for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk) { if (itr == self) { @@ -188,11 +190,11 @@ lumiera_interface_open_interface (LumieraInterface self) if (self->refcnt == 1) { /* first opening, run acquire, recursive opening shall record its dependencies here */ - if (self->acquire) + if (self->interface->acquire) { - TRACE (interface, "Acquire %s", self->name); + TRACE (interface, "Acquire %s", self->interface->name); collect_dependencies = self->deps?0:1; - self = self->acquire (self); + self->interface = self->interface->acquire (self->interface); } } else @@ -216,60 +218,69 @@ lumiera_interface_open_interface (LumieraInterface self) void lumiera_interface_close (LumieraInterface self) { - static LumieraInterface stack = NULL; + 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->name, self->refcnt, stack?stack->name:""); + TRACE (interface, "%s %d (%s)", self->interface->name, self->refcnt, stack?stack->interface->name:""); - LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) + REQUIRE (self->refcnt); + + int cycle = 0; + + for (LumieraInterfacenode itr = stack; itr; itr = itr->lnk) { - REQUIRE (self->refcnt); - - int cycle = 0; - - for (LumieraInterface itr = stack; itr; itr = itr->lnk) + if (itr == self) { - if (itr == self) - { - TRACE (interface, "CYCLE"); - cycle = 1; - break; - } - } - - if (!cycle) - { - self->lnk = stack; - stack = self; - - if (self->refcnt == 1) - { - if (self->release) - { - TRACE (interface, "Release %s", self->name); - self->release (self); - } - } - else - { - if (self->deps) - { - TRACE (interface, "Recurse %s %d", self->name, self->refcnt); - - for (LumieraInterface* dep = self->deps; *dep; ++dep) - lumiera_interface_close (*dep); - } - } - - stack = self->lnk; - self->lnk = NULL; - --self->refcnt; + 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; + } +} /* diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index 799f84b70..f31755f35 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -22,6 +22,7 @@ #include "lib/mutex.h" #include "lib/error.h" #include "lib/psplay.h" +#include "lib/safeclib.h" #include @@ -41,10 +42,9 @@ NOBUG_DEFINE_FLAG_PARENT (interface_all, backend); NOBUG_DEFINE_FLAG_PARENT (interfaceregistry, interface_all); NOBUG_DEFINE_FLAG_PARENT (interface, interface_all); -static PSplay interfaceregistry; +PSplay lumiera_interfaceregistry; lumiera_mutex lumiera_interface_mutex; - static int cmp_fn (const void* keya, const void* keyb); @@ -52,6 +52,34 @@ 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 @@ -63,28 +91,27 @@ lumiera_interfaceregistry_init (void) NOBUG_INIT_FLAG (interfaceregistry); NOBUG_INIT_FLAG (interface); TRACE (interfaceregistry); - REQUIRE (!interfaceregistry); + REQUIRE (!lumiera_interfaceregistry); - TODO ("introduce a registrynode structure, place all dynamic interface stuff there, make interface_struct const"); - - interfaceregistry = psplay_new (cmp_fn, key_fn, NULL); - if (!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 (interfaceregistry)); + REQUIRE (!psplay_nelements (lumiera_interfaceregistry)); lumiera_mutex_destroy (&lumiera_interface_mutex, &NOBUG_FLAG(interfaceregistry)); - if (interfaceregistry) - psplay_destroy (interfaceregistry); - interfaceregistry = NULL; + if (lumiera_interfaceregistry) + psplay_destroy (lumiera_interfaceregistry); + lumiera_interfaceregistry = NULL; } @@ -97,7 +124,7 @@ lumiera_interfaceregistry_register_interface (LumieraInterface self) LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) { TRACE (interfaceregistry, "interface %s, version %d, instance %s", self->interface, self->version, self->name); - psplay_insert (interfaceregistry, &self->node, 100); + psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (self)->node, 100); } } @@ -113,7 +140,7 @@ lumiera_interfaceregistry_bulkregister_interfaces (LumieraInterface* self) while (*self) { TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name); - psplay_insert (interfaceregistry, &(*self)->node, 100); + psplay_insert (lumiera_interfaceregistry, &lumiera_interfacenode_new (*self)->node, 100); ++self; } } @@ -128,10 +155,10 @@ lumiera_interfaceregistry_remove_interface (LumieraInterface self) LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) { - REQUIRE (self->refcnt == 0); - psplay_remove (interfaceregistry, &self->node); + LumieraInterfacenode node = (LumieraInterfacenode) psplay_find (lumiera_interfaceregistry, self, 0); + REQUIRE (node->refcnt == 0, "but is %d", node->refcnt); - FIXME ("free deps"); + lumiera_interfacenode_delete ((LumieraInterfacenode)psplay_remove (lumiera_interfaceregistry, &node->node)); } } @@ -147,18 +174,20 @@ lumiera_interfaceregistry_bulkremove_interfaces (LumieraInterface* self) while (*self) { TRACE (interfaceregistry, "interface %s, version %d, instance %s", (*self)->interface, (*self)->version, (*self)->name); - REQUIRE ((*self)->refcnt == 0, "but is %d", (*self)->refcnt); - psplay_remove (interfaceregistry, &(*self)->node); + 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; - FIXME ("free deps"); } } } -LumieraInterface -lumiera_interfaceregistry_interface_find (const char* interface, unsigned version, const char* name) +LumieraInterfacenode +lumiera_interfaceregistry_interfacenode_find (const char* interface, unsigned version, const char* name) { TRACE (interfaceregistry); struct lumiera_interface_struct cmp; @@ -166,17 +195,24 @@ lumiera_interfaceregistry_interface_find (const char* interface, unsigned versio cmp.version = version; cmp.name = name; - LumieraInterface ret = NULL; + LumieraInterfacenode ret = NULL; LUMIERA_RECMUTEX_SECTION (interfaceregistry, &lumiera_interface_mutex) { - ret = (LumieraInterface)psplay_find (interfaceregistry, &cmp, 100); + 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) { @@ -207,7 +243,7 @@ cmp_fn (const void* keya, const void* keyb) static const void* key_fn (const PSplaynode node) { - return node; + return ((LumieraInterfacenode)node)->interface; } diff --git a/src/backend/interfaceregistry.h b/src/backend/interfaceregistry.h index c6bf4a2e5..0af95c9be 100644 --- a/src/backend/interfaceregistry.h +++ b/src/backend/interfaceregistry.h @@ -22,6 +22,7 @@ #define LUMIERA_INTERFACEREGISTRY_H #include "lib/mutex.h" +#include "lib/psplay.h" #include "lib/interface.h" #include @@ -38,9 +39,37 @@ 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; +}; + + /** * Initialize the interface registry */ @@ -63,6 +92,9 @@ 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); diff --git a/src/lib/interface.h b/src/lib/interface.h index 16319c244..ef13e40e1 100644 --- a/src/lib/interface.h +++ b/src/lib/interface.h @@ -182,15 +182,10 @@ PPMPL_FOREACH(_P1_, __VA_ARGS__) LUMIERA_INTERFACE_TYPE(iname, version) LUMIERA_INTERFACE_DNAME(iname, version, name) = \ { \ { \ - PSPLAYNODE_INITIALIZER, \ #iname, \ version, \ #name, \ sizeof (LUMIERA_INTERFACE_TYPE(iname, version)), \ - 0, \ - NULL, \ - 0, \ - NULL, \ descriptor, \ acquire, \ release \ @@ -342,9 +337,6 @@ struct lumiera_interfaceslot_struct */ struct lumiera_interface_struct { - /** all known interfaces are registered in a tree */ - psplaynode node; - /** name of the interface (type) */ const char* interface; @@ -357,12 +349,6 @@ struct lumiera_interface_struct /** size of the whole interface structure (minor version) */ size_t size; - /** reference counters and link used for internal reference management */ - unsigned refcnt; - LumieraInterface lnk; - size_t ndeps; - LumieraInterface* deps; - /** metadata descriptor, itself a interface (or NULL) */ LumieraInterface descriptor; @@ -391,17 +377,6 @@ struct lumiera_interface_struct */ -/** - * Open an interface by handle. - * This is faster because it needs no lookup, one must be sure to have a valid handle - * which mets the requirements (version) - * @param self pointer to the interface to be opened - * @return self on success or NULL on error - * @internal This function is mostly for internal purposes - */ -LumieraInterface -lumiera_interface_open_interface (LumieraInterface self); - /** * Open an interface by version and name. * Looks up the requested interface, possibly loading it from a plugin. From ee7719eadac375116972e9af2f183ba5da857cf3 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 14 Oct 2008 23:07:58 +0200 Subject: [PATCH 38/46] tests and a first definition of a interface descriptor --- src/lib/interfacedescriptor.h | 48 +++++ tests/backend/test-interfaces.c | 345 +++++++++++++++++++++++++++++--- 2 files changed, 370 insertions(+), 23 deletions(-) create mode 100644 src/lib/interfacedescriptor.h diff --git a/src/lib/interfacedescriptor.h b/src/lib/interfacedescriptor.h new file mode 100644 index 000000000..1b6501a7b --- /dev/null +++ b/src/lib/interfacedescriptor.h @@ -0,0 +1,48 @@ +/* + interfacedescriptor.h - Metadata interface for Lumiera interfaces + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + 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 "lib/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: +*/ diff --git a/tests/backend/test-interfaces.c b/tests/backend/test-interfaces.c index fb1c4d30a..214c795c8 100644 --- a/tests/backend/test-interfaces.c +++ b/tests/backend/test-interfaces.c @@ -21,7 +21,7 @@ #include "lib/interface.h" #include "backend/interfaceregistry.h" -//#include "lib/interfacedescriptor.h" +#include "lib/interfacedescriptor.h" #include "tests/test.h" /* @@ -38,6 +38,9 @@ LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_two, 0, LUMIERA_INTERFACE_SLOT (void, bar2, (const char*)), ); +LUMIERA_INTERFACE_DECLARE (lumieraorg_testexample_void, 0 +); + /* now the functions we want to bind to them @@ -51,32 +54,79 @@ testfunc (const char* 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_testexample_one, 0, - lumieraorg_standalone_test, - NULL, - NULL, - NULL, - LUMIERA_INTERFACE_INLINE (foo1, "\066\177\042\305\165\243\236\352\164\250\357\307\211\374\123\066", - void, (const char* msg), +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 ";} + ), + LUMIERA_INTERFACE_INLINE (copyright, "\163\106\344\014\251\125\111\252\236\322\174\120\335\225\333\245", + const char*, (LumieraInterface iface), { - printf ("inline\n"); + return + "Copyright (C) Lumiera.org\n" + " 2008 Christian Thaeter "; } ), - LUMIERA_INTERFACE_MAP (bar1, "\162\335\262\306\101\113\106\055\342\205\300\151\262\073\257\343", - testfunc) + 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, - NULL, - NULL, - NULL, + 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", @@ -84,9 +134,9 @@ LUMIERA_EXPORT (interfaces_defined_here, ), LUMIERA_INTERFACE_DEFINE (lumieraorg_testexample_two, 0, lumieraorg_second_test, - NULL, - NULL, - NULL, + 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", @@ -95,6 +145,131 @@ LUMIERA_EXPORT (interfaces_defined_here, ); +/* + 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") @@ -117,25 +292,149 @@ TEST ("basic") handle2->foo2 ("this is foo2"); - /* higher level, WIP */ + lumiera_interfaceregistry_bulkremove_interfaces (interfaces_defined_here()); + lumiera_interfaceregistry_destroy (); +} - LUMIERA_INTERFACE_HANDLE(lumieraorg_testexample_two, 0, 0, lumieraorg_second_test, handle3); - handle3->bar2 ("this is bar2"); +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 ("basic") +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 ("basic") + +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 ("basic") +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 From 29f5a0f2abbeb32b305228d2fe9dd92d28a377a7 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 15 Oct 2008 00:02:22 +0200 Subject: [PATCH 39/46] moved the remaining interface stuff from lib to backend --- src/backend/Makefile.am | 2 ++ src/backend/interface.c | 3 ++- src/{lib => backend}/interface.h | 0 src/{lib => backend}/interfacedescriptor.h | 2 +- src/backend/interfaceregistry.h | 3 ++- src/lib/Makefile.am | 2 -- tests/backend/test-interfaces.c | 4 ++-- 7 files changed, 9 insertions(+), 7 deletions(-) rename src/{lib => backend}/interface.h (100%) rename src/{lib => backend}/interfacedescriptor.h (98%) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 78ffea592..12110b26f 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -46,7 +46,9 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ $(liblumibackend_a_srcdir)/filehandlecache.h \ + $(liblumibackend_a_srcdir)/interface.c \ $(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 \ diff --git a/src/backend/interface.c b/src/backend/interface.c index 0150e403e..58d0d0c0f 100644 --- a/src/backend/interface.c +++ b/src/backend/interface.c @@ -21,7 +21,8 @@ #include "lib/mutex.h" #include "lib/safeclib.h" -#include "lib/interface.h" + +#include "backend/interface.h" #include "backend/interfaceregistry.h" diff --git a/src/lib/interface.h b/src/backend/interface.h similarity index 100% rename from src/lib/interface.h rename to src/backend/interface.h diff --git a/src/lib/interfacedescriptor.h b/src/backend/interfacedescriptor.h similarity index 98% rename from src/lib/interfacedescriptor.h rename to src/backend/interfacedescriptor.h index 1b6501a7b..468bd2e80 100644 --- a/src/lib/interfacedescriptor.h +++ b/src/backend/interfacedescriptor.h @@ -21,7 +21,7 @@ #ifndef LUMIERA_INTERFACEDESCRIPTOR_H #define LUMIERA_INTERFACEDESCRIPTOR_H -#include "lib/interface.h" +#include "backend/interface.h" /** * WIP: interface descriptor, needs some generic metadata interface diff --git a/src/backend/interfaceregistry.h b/src/backend/interfaceregistry.h index 0af95c9be..11ed91bde 100644 --- a/src/backend/interfaceregistry.h +++ b/src/backend/interfaceregistry.h @@ -23,7 +23,8 @@ #include "lib/mutex.h" #include "lib/psplay.h" -#include "lib/interface.h" + +#include "backend/interface.h" #include diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2ad293158..4dc927b43 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -31,7 +31,6 @@ liblumi_a_SOURCES = \ $(liblumi_a_srcdir)/psplay.c \ $(liblumi_a_srcdir)/mrucache.c \ $(liblumi_a_srcdir)/time.c \ - $(liblumi_a_srcdir)/interfacedescriptor.c \ $(liblumi_a_srcdir)/appconfig.cpp noinst_HEADERS += \ @@ -47,7 +46,6 @@ noinst_HEADERS += \ $(liblumi_a_srcdir)/time.h \ $(liblumi_a_srcdir)/ppmpl.h \ $(liblumi_a_srcdir)/interface.h \ - $(liblumi_a_srcdir)/interfacedescriptor.h \ $(liblumi_a_srcdir)/appconfig.hpp \ $(liblumi_a_srcdir)/lifecycleregistry.hpp diff --git a/tests/backend/test-interfaces.c b/tests/backend/test-interfaces.c index 214c795c8..09fa25afa 100644 --- a/tests/backend/test-interfaces.c +++ b/tests/backend/test-interfaces.c @@ -19,9 +19,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "lib/interface.h" +#include "backend/interface.h" #include "backend/interfaceregistry.h" -#include "lib/interfacedescriptor.h" +#include "backend/interfacedescriptor.h" #include "tests/test.h" /* From 0cf7dec7938811aaf7abf51d3d3d9355cf82c7e0 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 19 Sep 2008 15:45:24 +0200 Subject: [PATCH 40/46] Interfaceregistry for 'active' interfaces All interfaces which are available get registered in a tree. This will be used internal for lookup interfaces. The higher level calls will be an amalgamation of this lookup and the upcoming plugindb and loader. --- src/backend/Makefile.am | 2 +- src/backend/interfaceregistry.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 12110b26f..cf5fe1897 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -46,7 +46,7 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ $(liblumibackend_a_srcdir)/filehandlecache.h \ - $(liblumibackend_a_srcdir)/interface.c \ + $(liblumibackend_a_srcdir)/interface.h \ $(liblumibackend_a_srcdir)/interfaceregistry.h \ $(liblumibackend_a_srcdir)/interfacedescriptor.h \ $(liblumibackend_a_srcdir)/config.h \ diff --git a/src/backend/interfaceregistry.c b/src/backend/interfaceregistry.c index f31755f35..ffa979340 100644 --- a/src/backend/interfaceregistry.c +++ b/src/backend/interfaceregistry.c @@ -80,7 +80,6 @@ lumiera_interfacenode_delete (LumieraInterfacenode self) } - /** * Initialize the interface registry */ From f7fa5769cafa87cfe8b0ad2b258ae10cd76adac3 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 22 Sep 2008 22:38:17 +0200 Subject: [PATCH 41/46] Start of a 'wordlist' type for the config subsystem wordlists are simple not quoted words delimited by semicolon, tab, space or commas. Some special functions will allow to access each of this words by index etc. --- src/backend/config.h | 1 - src/backend/config_wordlist.c | 6 ++++-- tests/22config_highlevel.tests | 22 ++++++++++++++++++++++ tests/backend/test-config.c | 1 - 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/backend/config.h b/src/backend/config.h index 0b50c7da2..4e3acd9a9 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -217,7 +217,6 @@ 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,;". diff --git a/src/backend/config_wordlist.c b/src/backend/config_wordlist.c index 548a4d824..6cd0389a7 100644 --- a/src/backend/config_wordlist.c +++ b/src/backend/config_wordlist.c @@ -33,6 +33,9 @@ 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) { @@ -196,12 +199,11 @@ lumiera_config_wordlist_append (const char* key, const char** value, unsigned nt { } + LumieraConfigitem lumiera_config_wordlist_preprend (const char* key, const char** value, unsigned nth) { } - - #endif diff --git a/tests/22config_highlevel.tests b/tests/22config_highlevel.tests index 3d131da3e..c43baaefe 100644 --- a/tests/22config_highlevel.tests +++ b/tests/22config_highlevel.tests @@ -222,3 +222,25 @@ TEST "wordlist add to empty list, same" wordlist_add 'foo.bar' '' same same << E 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 + diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index deffa7c00..506801454 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -409,5 +409,4 @@ TEST ("wordlist_add") } - TESTS_END From 9943dd76fdfd1921010bb968dcbe0ddf45f51c76 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 28 Sep 2008 03:49:28 +0200 Subject: [PATCH 42/46] use a recursive mutex to lock interface operations locking interfaceregistry operations and later on open/close etc --- src/backend/interfaceregistry.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/interfaceregistry.h b/src/backend/interfaceregistry.h index 11ed91bde..02481072d 100644 --- a/src/backend/interfaceregistry.h +++ b/src/backend/interfaceregistry.h @@ -70,6 +70,8 @@ struct lumiera_interfacenode_struct LumieraInterfacenode* deps; }; +extern lumiera_mutex lumiera_interface_mutex; + /** * Initialize the interface registry From be9d2b189f695cea6518b2fd23b4f322e2a196d6 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 15 Oct 2008 18:01:52 +0200 Subject: [PATCH 43/46] fix lib/Makefile.am, a stale interfaces.h was left here --- src/lib/Makefile.am | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 4dc927b43..55d88e71a 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -45,7 +45,6 @@ noinst_HEADERS += \ $(liblumi_a_srcdir)/mrucache.h \ $(liblumi_a_srcdir)/time.h \ $(liblumi_a_srcdir)/ppmpl.h \ - $(liblumi_a_srcdir)/interface.h \ $(liblumi_a_srcdir)/appconfig.hpp \ $(liblumi_a_srcdir)/lifecycleregistry.hpp From 9752de310229f5f4c2ddb2eecd31c59eb5acd4ec Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 15 Oct 2008 22:05:22 +0200 Subject: [PATCH 44/46] Some prelimary TODO's for filedescriptor.c to be fixed later --- src/backend/filedescriptor.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index 4daa04f3e..5f6bb4f13 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -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", ®istry, 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; From 26c212b2928b52b22d3f00b41025048be3a79fb5 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 15 Oct 2008 22:18:17 +0200 Subject: [PATCH 45/46] make the old plugin stuff barely compileable, disable tests, fix later --- src/backend/plugin.c | 5 +++-- tests/20plugin.tests | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/backend/plugin.c b/src/backend/plugin.c index 44cf6abc5..f6ecd7649 100644 --- a/src/backend/plugin.c +++ b/src/backend/plugin.c @@ -27,8 +27,9 @@ #include #include -#include "plugin.h" -#include "safeclib.h" +#include "lib/safeclib.h" + +#include "backend/plugin.h" /** * @file diff --git a/tests/20plugin.tests b/tests/20plugin.tests index 6e8cd96de..d1d9fba2f 100644 --- a/tests/20plugin.tests +++ b/tests/20plugin.tests @@ -1,6 +1,6 @@ TESTING "test plugin example code" ./test-plugin -TEST "C plugin example" C < Date: Wed, 15 Oct 2008 22:53:55 +0200 Subject: [PATCH 46/46] Fix: old plugin.c|.h must not be compiled and linked --- src/backend/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index cf5fe1897..da39e71c6 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -23,7 +23,6 @@ liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wextra -Wall -Werror liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ $(liblumibackend_a_srcdir)/backend.c \ - $(liblumibackend_a_srcdir)/plugin.c \ $(liblumibackend_a_srcdir)/file.c \ $(liblumibackend_a_srcdir)/filehandle.c \ $(liblumibackend_a_srcdir)/filedescriptor.c \ @@ -41,7 +40,6 @@ liblumibackend_a_SOURCES = \ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ $(liblumibackend_a_srcdir)/backend.h \ - $(liblumibackend_a_srcdir)/plugin.h \ $(liblumibackend_a_srcdir)/file.h \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \