From 9826fd180d052e6e4b4b6d6990817ee782ad6049 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 5 Aug 2008 07:48:27 +0200 Subject: [PATCH 001/102] renamed the uuid to luid uuid's are somewhat standardized, we use our uid's slightly differently, so change the name not to be confused with standards. * Small fix for luid generation * build a 'luidgen' tool which will be used by the interface gen later * add emacs vars * include the luidgen tool in automake --- Makefile.am | 3 + src/lib/Makefile.am | 8 +- src/lib/luid.c | 113 +++++++++++++++++++++ src/lib/luid.h | 81 +++++++++++++++ src/lib/uuid.c | 95 ----------------- src/lib/uuid.h | 67 ------------ src/tool/Makefile.am | 28 +++++ src/tool/luidgen.c | 51 ++++++++++ tests/{15uuid.tests => 15luid.tests} | 0 tests/Makefile.am | 10 +- tests/library/{test-uuid.c => test-luid.c} | 42 ++++---- 11 files changed, 310 insertions(+), 188 deletions(-) create mode 100644 src/lib/luid.c create mode 100644 src/lib/luid.h delete mode 100644 src/lib/uuid.c delete mode 100644 src/lib/uuid.h create mode 100644 src/tool/Makefile.am create mode 100644 src/tool/luidgen.c rename tests/{15uuid.tests => 15luid.tests} (100%) rename tests/library/{test-uuid.c => test-luid.c} (60%) diff --git a/Makefile.am b/Makefile.am index 379d36803..2edbc6e28 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,9 @@ include $(top_srcdir)/src/common/Makefile.am include $(top_srcdir)/src/lib/Makefile.am include $(top_srcdir)/src/backend/Makefile.am +# tools +include $(top_srcdir)/src/tool/Makefile.am + # gui include $(top_srcdir)/src/gui/Makefile.am diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index a4d8b825f..2ae8a9b2d 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -28,11 +28,11 @@ liblumi_a_SOURCES = \ $(liblumi_a_srcdir)/rwlock.c \ $(liblumi_a_srcdir)/condition.c \ $(liblumi_a_srcdir)/references.c \ - $(liblumi_a_srcdir)/uuid.c \ + $(liblumi_a_srcdir)/luid.c \ $(liblumi_a_srcdir)/safeclib.c \ $(liblumi_a_srcdir)/cuckoo.c \ $(liblumi_a_srcdir)/mrucache.c \ - $(liblumi_a_srcdir)/time.c \ + $(liblumi_a_srcdir)/time.c \ $(liblumi_a_srcdir)/appconfig.cpp noinst_HEADERS += \ @@ -43,11 +43,11 @@ noinst_HEADERS += \ $(liblumi_a_srcdir)/rwlock.h \ $(liblumi_a_srcdir)/condition.h \ $(liblumi_a_srcdir)/references.h \ - $(liblumi_a_srcdir)/uuid.h \ + $(liblumi_a_srcdir)/luid.h \ $(liblumi_a_srcdir)/safeclib.h \ $(liblumi_a_srcdir)/cuckoo.h \ $(liblumi_a_srcdir)/mrucache.h \ - $(liblumi_a_srcdir)/time.h \ + $(liblumi_a_srcdir)/time.h \ $(liblumi_a_srcdir)/appconfig.hpp \ $(liblumi_a_srcdir)/appconfig.hpp diff --git a/src/lib/luid.c b/src/lib/luid.c new file mode 100644 index 000000000..c8d766094 --- /dev/null +++ b/src/lib/luid.c @@ -0,0 +1,113 @@ +/* + luid - Lumiera unique identifiers + + 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/luid.h" + +#include +#include +#include +#include +#include +#include +#include + +void +lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr) +{ + memset (luid, 0, 16); + *(void**)luid = ptr; +} + + +void* +lumiera_uid_ptr_get (lumiera_uid* luid) +{ + return *(void**)luid; +} + + +void +lumiera_uid_gen (lumiera_uid* luid) +{ + static int fd = -2; + if (!luid) + return; + + if (fd == -2) + { + fd = open ("/dev/urandom", O_RDONLY); + /* on linux /dev/random would be way to slow for our purpose, so we comment that out for now. + other unixiods offer a /dev/random which has the same semantics as linux /dev/urandom has, + configuration should do this right some day. + if (fd == -1) + fd = open ("/dev/random", O_RDONLY); + */ + if (fd >= 0) + fcntl (fd, F_SETFD, FD_CLOEXEC); + else + srand (getpid () + time (NULL)); + } + + do + { + if (fd < 0) + { + for (int i = 0; i < 16; ++i) + ((unsigned char*)luid)[i] = (unsigned char)(rand()>>7); + } + else + { + if (read (fd, luid, 16) < 16) + abort (); + } + } + /* we identify generic pointers by having some zeros in the luid, + * this happens very unlikely to be in a random luid, just regenerate it then */ + while (!*(((intptr_t*)luid)+1)); +} + + +void +lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src) +{ + memcpy (dest, src, 16); +} + + +int +lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb) +{ + return !memcmp (luida, luidb, 16); +} + +size_t +lumiera_uid_hash (lumiera_uid* luid) +{ + return *(size_t*)luid; +} + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/luid.h b/src/lib/luid.h new file mode 100644 index 000000000..a93d004a3 --- /dev/null +++ b/src/lib/luid.h @@ -0,0 +1,81 @@ +/* + luid - Lumiera unique identifiers + + 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_LUID_H +#define LUMIERA_LUID_H + +#include + +/** + * @file + * Lumiera unique identifiers are 128 byte random value. Unlike standard uuid's we + * don't tag a version within them and we may store generic pointers in the space + * occupied by an luid. + */ + +typedef unsigned char lumiera_uid[16]; + +/** + * Retrieve a generic pointer stored in a luid + */ +void* +lumiera_uid_ptr_get (lumiera_uid* luid); + +/** + * Generate a new luid + */ +void +lumiera_uid_gen (lumiera_uid* luid); + +/** + * Store a generic pointer in a luid + */ +void +lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr); + + +/** + * Copy an luid + */ +void +lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src); + + +/** + * Test 2 luid's for equality + */ +int +lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb); + + +/** + * Generate a hashsum over an luid + */ +size_t +lumiera_uid_hash (lumiera_uid* luid); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/uuid.c b/src/lib/uuid.c deleted file mode 100644 index d4eee69be..000000000 --- a/src/lib/uuid.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - uuid - Universal unique identifiers - - Copyright (C) CinelerraCV - 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/uuid.h" - -#include -#include -#include -#include -#include -#include - -void -lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr) -{ - memset (uuid, 0, 16); - *(void**)uuid = ptr; -} - - -void* -lumiera_uuid_ptr_get (lumiera_uuid* uuid) -{ - return *(void**)uuid; -} - - -void -lumiera_uuid_gen (lumiera_uuid* uuid) -{ - static int fd = -2; - if (!uuid) - return; - - if (fd == -2) - { - fd = open ("/dev/urandom", O_RDONLY); - if (fd == -1) - fd = open ("/dev/random", O_RDONLY); - if (fd >= 0) - fcntl (fd, F_SETFD, FD_CLOEXEC); - else - srand (getpid () + time (NULL)); - } - if (fd < 0) - { - for (int i = 0; i < 16; ++i) - ((unsigned char*)uuid)[i] = (unsigned char)(rand()>>7); - } - else - { - if (read (fd, uuid, 16) < 0) - abort (); - } -} - - -void -lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src) -{ - memcpy (dest, src, 16); -} - - -int -lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb) -{ - return !memcmp (uuida, uuidb, 16); -} - -size_t -lumiera_uuid_hash (lumiera_uuid* uuid) -{ - return *(size_t*)uuid; -} - - diff --git a/src/lib/uuid.h b/src/lib/uuid.h deleted file mode 100644 index d4cf8ce9d..000000000 --- a/src/lib/uuid.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - uuid - Universal unique identifiers - - Copyright (C) CinelerraCV - 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_UUID_H -#define LUMIERA_UUID_H - -#include - -typedef unsigned char lumiera_uuid[16]; - -/** - * Retrieve a generic pointer stored in a uuid - */ -void* -lumiera_uuid_ptr_get (lumiera_uuid* uuid); - -/** - * Generate a new uuid - */ -void -lumiera_uuid_gen (lumiera_uuid* uuid); - -/** - * Store a generic pointer in a uuid - */ -void -lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr); - - -/** - * Copy an uuid - */ -void -lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src); - - -/** - * Test 2 uuid's for equality - */ -int -lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb); - - -/** - * Generate a hashsum over an uuid - */ -size_t -lumiera_uuid_hash (lumiera_uuid* uuid); - -#endif diff --git a/src/tool/Makefile.am b/src/tool/Makefile.am new file mode 100644 index 000000000..69c4a7f25 --- /dev/null +++ b/src/tool/Makefile.am @@ -0,0 +1,28 @@ +# 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. + +lumitool_srcdir = $(top_srcdir)/src/tool + +noinst_PROGRAMS += luidgen + +luidgen_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror +luidgen_CPPFLAGS = -I$(top_srcdir)/src/ +luidgen_SOURCES = \ + $(lumitool_srcdir)/luidgen.c + +luidgen_LDADD = liblumi.a + diff --git a/src/tool/luidgen.c b/src/tool/luidgen.c new file mode 100644 index 000000000..41081ca97 --- /dev/null +++ b/src/tool/luidgen.c @@ -0,0 +1,51 @@ +/* + luidgen.c - generate a lumiera uuid + + 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/luid.h" + +#include + +/** + * @file + * Generate amd print a Lumiera uid as octal escaped string + */ + +int +main (int argc, char** argv) +{ + lumiera_uid luid; + lumiera_uid_gen (&luid); + + printf ("\""); + for (int i = 0; i < 16; ++i) + printf ("\\%.3hho", *(((char*)&luid)+i)); + printf ("\"\n"); + + return 0; +} + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/tests/15uuid.tests b/tests/15luid.tests similarity index 100% rename from tests/15uuid.tests rename to tests/15luid.tests diff --git a/tests/Makefile.am b/tests/Makefile.am index c51133995..74d035034 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,12 +39,12 @@ test_llist_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm check_PROGRAMS += test-safeclib test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_safeclib_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm +test_safeclib_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm -check_PROGRAMS += test-uuid -test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c -test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ -test_uuid_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm +check_PROGRAMS += test-luid +test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c +test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_luid_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm check_PROGRAMS += test-references test_references_SOURCES = $(tests_srcdir)/library/test-references.c diff --git a/tests/library/test-uuid.c b/tests/library/test-luid.c similarity index 60% rename from tests/library/test-uuid.c rename to tests/library/test-luid.c index 4a6050163..1695bbec6 100644 --- a/tests/library/test-uuid.c +++ b/tests/library/test-luid.c @@ -1,8 +1,8 @@ /* - test-uuid.c - test the uuid lib + test-luid.c - test the luid lib - Copyright (C) CinelerraCV - 2007, Christian Thaeter + Copyright (C) Lumiera.org + 2007, 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 @@ -23,7 +23,7 @@ //#include -#include "lib/uuid.h" +#include "lib/luid.h" #include @@ -39,35 +39,43 @@ main (int argc, char** argv) if (!strcmp(argv[1], "uuidgen_2")) { - lumiera_uuid uuid1; - lumiera_uuid uuid2; + lumiera_uid luid1; + lumiera_uid luid2; - lumiera_uuid_gen (&uuid1); - lumiera_uuid_gen (&uuid2); + lumiera_uid_gen (&luid1); + lumiera_uid_gen (&luid2); - printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1)); + printf ("%d\n", lumiera_uid_eq (&luid2, &luid1)); } else if (!strcmp(argv[1], "uuidgen_copy")) { - lumiera_uuid uuid1; - lumiera_uuid uuid2; + lumiera_uid luid1; + lumiera_uid luid2; - lumiera_uuid_gen (&uuid1); + lumiera_uid_gen (&luid1); - lumiera_uuid_copy (&uuid2, &uuid1); + lumiera_uid_copy (&luid2, &luid1); - printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1)); + printf ("%d\n", lumiera_uid_eq (&luid2, &luid1)); } else if (!strcmp(argv[1], "ptrs")) { - lumiera_uuid uuid; + lumiera_uid luid; - lumiera_uuid_set_ptr (&uuid, &uuid); + lumiera_uid_set_ptr (&luid, &luid); - printf ("%d\n", lumiera_uuid_ptr_get (&uuid) == &uuid); + printf ("%d\n", lumiera_uid_ptr_get (&luid) == &luid); } else return 1; return 0; } + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From 93e126f5abb36de3c33655570d2e7ec80ca0eb42 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 6 Aug 2008 09:38:33 +0200 Subject: [PATCH 002/102] add a 'lumiera_err' typedef --- src/lib/error.c | 10 +++++----- src/lib/error.h | 11 ++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib/error.c b/src/lib/error.c index dc9acfa56..1d3fb50c3 100644 --- a/src/lib/error.c +++ b/src/lib/error.c @@ -46,12 +46,12 @@ lumiera_error_tls_init (void) } -const char* -lumiera_error_set (const char * nerr) +lumiera_err +lumiera_error_set (lumiera_err nerr) { pthread_once (&lumiera_error_initialized, lumiera_error_tls_init); - const char* err = pthread_getspecific (lumiera_error_tls); + lumiera_err err = pthread_getspecific (lumiera_error_tls); if (!err) pthread_setspecific (lumiera_error_tls, nerr); @@ -59,12 +59,12 @@ lumiera_error_set (const char * nerr) } -const char* +lumiera_err lumiera_error () { pthread_once (&lumiera_error_initialized, lumiera_error_tls_init); - const char* err = pthread_getspecific (lumiera_error_tls); + lumiera_err err = pthread_getspecific (lumiera_error_tls); if (err) pthread_setspecific (lumiera_error_tls, NULL); return err; diff --git a/src/lib/error.h b/src/lib/error.h index e00e69c6b..5c4a8c145 100644 --- a/src/lib/error.h +++ b/src/lib/error.h @@ -35,6 +35,7 @@ extern "C" { * C Error handling in Lumiera, header. */ +typedef const char* lumiera_err; /** * Abort unconditionally with a 'Fatal Error!' message. @@ -49,7 +50,7 @@ extern "C" { * @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY) */ #define LUMIERA_ERROR_DECLARE(err) \ -extern const char* LUMIERA_ERROR_##err +extern lumiera_err LUMIERA_ERROR_##err /** * Definition and initialization of an error constant. @@ -58,7 +59,7 @@ extern const char* LUMIERA_ERROR_##err * @param msg message describing the error in plain english (example: "memory allocation failed") */ #define LUMIERA_ERROR_DEFINE(err, msg) \ -const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg +lumiera_err LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg /** * Helper macro to raise an error for the current thread. @@ -77,8 +78,8 @@ lumiera_error_set(LUMIERA_ERROR_##err)) * @return old state, that is NULL for success, when the state was cleared and a pointer to a pending * error when the error state was already set */ -const char* -lumiera_error_set (const char * err); +lumiera_err +lumiera_error_set (lumiera_err err); /** * Get and clear current error state. @@ -86,7 +87,7 @@ lumiera_error_set (const char * err); * variable. * @return pointer to any pending error of this thread, NULL if no error is pending */ -const char* +lumiera_err lumiera_error (); /* From f5df65b0a1476cc281c2505455d8c0bde74588c9 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 05:02:08 +0200 Subject: [PATCH 003/102] add a translation function to tmpbuf tmpbuf_tr takes an input string and 2 sets of characters plus a default character. It produces a output string with all characters from the first set translated to the correspondending character in the 2nd set, similar to the shell 'tr' util. --- src/lib/safeclib.c | 35 +++++++++++++++++++++++++++++++++++ src/lib/safeclib.h | 14 ++++++++++++++ tests/15safeclib.tests | 31 +++++++++++++++++++++++++++++-- tests/library/test-safeclib.c | 20 ++++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) diff --git a/src/lib/safeclib.c b/src/lib/safeclib.c index 4a19477c1..c7c4f6e10 100644 --- a/src/lib/safeclib.c +++ b/src/lib/safeclib.c @@ -25,6 +25,7 @@ #include #include #include +#include LUMIERA_ERROR_DEFINE (NO_MEMORY, "Out of Memory!"); @@ -171,3 +172,37 @@ lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...) return buf; } + + +char* +lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def) +{ + REQUIRE (strlen (from) == strlen (to), "from and to character set must have equal length"); + + char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX); + + char* wpos; + char* rpos; + for (wpos = rpos = ret; *rpos; ++rpos, ++wpos) + { + char* found = strchr (from, *rpos); + if (found) + *wpos = to[found-from]; + else if (def) + { + if (*def) + *wpos = *def; + else + { + ++rpos; + if (!*rpos) + break; + } + } + else + return NULL; + } + *wpos = '\0'; + + return ret; +} diff --git a/src/lib/safeclib.h b/src/lib/safeclib.h index 6fc532239..793bd1368 100644 --- a/src/lib/safeclib.h +++ b/src/lib/safeclib.h @@ -123,3 +123,17 @@ lumiera_tmpbuf_strndup (const char* src, size_t size); char* lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...); +/** + * Translates characters in a string, similar to the shell 'tr' utility + * @param in input string to be translated + * @param from source character set + * @param to destination character set + * @param def default destination character when a character is not in the source set, + * when NULL then translation will abort on unknown characters and return NULL, + * when "" then unknown characters will be removed + * when set to a single character string, unknown characters will be replaced with this string + * @return temporary buffer containing the constructed of the string + */ +char* +lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def); + diff --git a/tests/15safeclib.tests b/tests/15safeclib.tests index 7e4039ead..560c0ee0a 100644 --- a/tests/15safeclib.tests +++ b/tests/15safeclib.tests @@ -9,9 +9,10 @@ TEST "Allocating some memory" allocation1024 < Date: Thu, 7 Aug 2008 05:40:26 +0200 Subject: [PATCH 004/102] add 'lumiera_free' as replacement for 'free' lumiera_free() is for now just a static inline wraper around free() Later this makes it easier to hook in some resource managing functions or a Garbage Collector in. Replaced all current uses of free() --- src/backend/file.c | 4 ++-- src/backend/filedescriptor.c | 2 +- src/backend/filehandlecache.c | 2 +- src/lib/mrucache.c | 7 ++++--- src/lib/safeclib.c | 9 +++++---- src/lib/safeclib.h | 12 ++++++++++++ 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/backend/file.c b/src/backend/file.c index 9af608567..2b1929d6c 100644 --- a/src/backend/file.c +++ b/src/backend/file.c @@ -50,7 +50,7 @@ lumiera_file_destroy (LumieraFile self) { TRACE (file); lumiera_filedescriptor_release (self->descriptor); - free ((void*)self->name); + lumiera_free ((void*)self->name); return self; } @@ -67,7 +67,7 @@ void lumiera_file_delete (LumieraFile self) { TRACE (file); - free (lumiera_file_destroy (self)); + lumiera_free (lumiera_file_destroy (self)); } diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index b9608984f..005bc425b 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -234,7 +234,7 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self) TODO ("release filehandle"); lumiera_mutex_destroy (&self->lock); - free (self); + lumiera_free (self); lumiera_mutexacquirer_unlock (®istry_lock); } diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c index 181807661..0a4852879 100644 --- a/src/backend/filehandlecache.c +++ b/src/backend/filehandlecache.c @@ -58,7 +58,7 @@ lumiera_filehandlecache_delete (void) RESOURCE_FORGET (filehandlecache, lumiera_fhcache->rh); lumiera_mrucache_destroy (&lumiera_fhcache->cache); lumiera_mutex_destroy (&lumiera_fhcache->lock); - free (lumiera_fhcache); + lumiera_free (lumiera_fhcache); lumiera_fhcache = NULL; } } diff --git a/src/lib/mrucache.c b/src/lib/mrucache.c index 0f9bb86df..d591d5f56 100644 --- a/src/lib/mrucache.c +++ b/src/lib/mrucache.c @@ -19,6 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "lib/safeclib.h" #include "lib/mrucache.h" @@ -39,9 +40,9 @@ lumiera_mrucache_destroy (LumieraMruCache self) { llist_unlink (node); if (self->destructor_cb) - free (self->destructor_cb (node)); + lumiera_free (self->destructor_cb (node)); else - free (node); + lumiera_free (node); } self->cached = 0; return self; @@ -52,7 +53,7 @@ lumiera_mrucache_age (LumieraMruCache self, int nelem) { REQUIRE (self); while (self->cached && nelem--) - free (lumiera_mrucache_pop (self)); + lumiera_free (lumiera_mrucache_pop (self)); return nelem; } diff --git a/src/lib/safeclib.c b/src/lib/safeclib.c index c7c4f6e10..3d1468627 100644 --- a/src/lib/safeclib.c +++ b/src/lib/safeclib.c @@ -18,7 +18,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "error.h" +#include "lib/error.h" +#include "lib/safeclib.h" #include #include @@ -114,8 +115,8 @@ lumiera_tmpbuf_freeall (void) { pthread_setspecific (lumiera_tmpbuf_tls_key, NULL); for (int idx = 0; idx < 64; ++idx) - free (buf->buffers[idx]); - free (buf); + lumiera_free (buf->buffers[idx]); + lumiera_free (buf); } } @@ -133,7 +134,7 @@ lumiera_tmpbuf_provide (size_t size) if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size) { - free (buf->buffers[buf->idx]); + lumiera_free (buf->buffers[buf->idx]); buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1); buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]); } diff --git a/src/lib/safeclib.h b/src/lib/safeclib.h index 793bd1368..2cd95502d 100644 --- a/src/lib/safeclib.h +++ b/src/lib/safeclib.h @@ -50,6 +50,18 @@ void* lumiera_calloc (size_t n, size_t size); +/** + * Free previously allocated memory. + * @param mem pointer to the memory block obtained by lumiera_malloc or lumiera_calloc + */ +static inline void +lumiera_free (void* mem) +{ + /* for now only a alias, might change in future */ + free (mem); +} + + /** * Duplicate a C string. * always succeeds or dies From 47b5a2667c60348d7447ecb3867f13e31ae73541 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 10:45:09 +0200 Subject: [PATCH 005/102] add LOCKED_SECTION macros to rwlock, fix bug in rwlockacquirer --- src/lib/rwlock.c | 56 ++++++++++++++++++++++-------------------------- src/lib/rwlock.h | 21 +++++++++++++++++- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/src/lib/rwlock.c b/src/lib/rwlock.c index 71e3c9dc8..a12642c01 100644 --- a/src/lib/rwlock.c +++ b/src/lib/rwlock.c @@ -69,36 +69,32 @@ lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, e self->rwlock = rwlock; self->state = state; - switch (state) - { - case LUMIERA_RDLOCKED: - switch (pthread_rwlock_rdlock (&rwlock->rwlock)) - { - case 0: - break; - case EAGAIN: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN); - return NULL; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_RLOCK); - } - case LUMIERA_WRLOCKED: - switch (pthread_rwlock_wrlock (&rwlock->rwlock)) - { - case 0: - break; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_WLOCK); - } - default: - break; - } + if (state == LUMIERA_RDLOCKED) + switch (pthread_rwlock_rdlock (&rwlock->rwlock)) + { + case 0: + break; + case EAGAIN: + lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN); + return NULL; + case EDEADLK: + lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); + return NULL; + default: + LUMIERA_DIE (RWLOCK_RLOCK); + } + else + switch (pthread_rwlock_wrlock (&rwlock->rwlock)) + { + case 0: + break; + case EDEADLK: + lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); + return NULL; + default: + LUMIERA_DIE (RWLOCK_WLOCK); + } + return self; } diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h index c51f78076..3ac7f82ed 100644 --- a/src/lib/rwlock.h +++ b/src/lib/rwlock.h @@ -43,6 +43,25 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK); * Read/write locks, header. */ +#define LUMIERA_RDLOCK_SECTION(flag, handle, rwlock) \ +RESOURCE_HANDLE (rh_##__LINE__##_); \ +lumiera_rwlockacquirer lock_##__LINE__##_; \ +RESOURCE_ENTER (flag, handle, "acquire rwlock (read)", &lock_##__LINE__##_, \ + NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \ +for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_RDLOCKED); \ + lock_##__LINE__##_.state == LUMIERA_RDLOCKED; \ + lumiera_rwlockacquirer_unlock (&lock_##__LINE__##_), \ + ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);})) + +#define LUMIERA_WRLOCK_SECTION(flag, handle, rwlock) \ +RESOURCE_HANDLE (rh_##__LINE__##_); \ +lumiera_rwlockacquirer lock_##__LINE__##_; \ +RESOURCE_ENTER (flag, handle, "acquire rwlock (write)", &lock_##__LINE__##_, \ + NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \ +for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_WRLOCKED); \ + lock_##__LINE__##_.state == LUMIERA_WRLOCKED; \ + lumiera_rwlockacquirer_unlock (&lock_##__LINE__##_), \ + ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);})) /** * RWLock. @@ -89,7 +108,7 @@ typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer; static inline void lumiera_rwlockacquirer_ensureunlocked (LumieraRWLockacquirer self) { - ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the rwlock mutex"); + ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the rwlock"); } /* override with a macro to use the cleanup checker */ From 07f06d0d88a65caae3b2d348f9e2fb1df4bead86 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 09:33:14 +0200 Subject: [PATCH 006/102] big mutex update, dropped old acquirer Acquiring mutexes is now wraped in a easy to use MUTEX_SECTION macro. This scheme will be extended for chained lock propagation soon. Notes: * NoBug resourcemanagement is now part of the lower layer, RESOURCE_ENTER/RESOUCE_LEAVE are maintained automatically * one must still call RESOURCE_ANNOUNCE/RESOURCE_FORGET, because we want to maintain high level information about resources. * MUTEX_SECTIONS must not be left with any kind of jump --- src/backend/file.c | 4 +- src/backend/filedescriptor.c | 140 ++++++++++++++--------------- src/backend/filedescriptor.h | 2 - src/backend/filehandlecache.c | 11 +-- src/backend/filehandlecache.h | 1 - src/lib/mutex.c | 1 + src/lib/mutex.h | 160 +++++++--------------------------- tests/15locking.tests | 10 +++ tests/locking/test-locking.c | 68 ++++++++++++++- 9 files changed, 185 insertions(+), 212 deletions(-) diff --git a/src/backend/file.c b/src/backend/file.c index 2b1929d6c..0cf5b6a3c 100644 --- a/src/backend/file.c +++ b/src/backend/file.c @@ -79,7 +79,7 @@ lumiera_file_handle_acquire (LumieraFile self) REQUIRE (self->descriptor); REQUIRE (lumiera_fhcache); - LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock) + LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock) { if (!self->descriptor->handle) /* no handle yet, get a new one */ @@ -123,7 +123,7 @@ lumiera_file_handle_release (LumieraFile self) { TRACE (file); - LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock) + LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock) { lumiera_filehandlecache_checkin (lumiera_fhcache, self->descriptor->handle); } diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index 005bc425b..2c37a6e5e 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -93,6 +93,9 @@ lumiera_filedescriptor_registry_init (void) 3); if (!registry) LUMIERA_DIE (NO_MEMORY); + + RESOURCE_HANDLE_INIT (registry_mutex.rh); + RESOURCE_ANNOUNCE (filedescriptor, "mutex", "filedescriptor registry", ®istry, registry_mutex.rh); } void @@ -100,6 +103,9 @@ lumiera_filedescriptor_registry_destroy (void) { TRACE (filedescriptor); REQUIRE (!cuckoo_nelements (registry)); + + RESOURCE_FORGET (filedescriptor, registry_mutex.rh); + if (registry) cuckoo_free (registry); registry = NULL; @@ -112,75 +118,72 @@ lumiera_filedescriptor_acquire (const char* name, int flags) TRACE (filedescriptor, "%s", name); REQUIRE (registry, "not initialized"); - lumiera_mutexacquirer registry_lock; - lumiera_mutexacquirer_init_mutex (®istry_lock, ®istry_mutex, LUMIERA_LOCKED); + LumieraFiledescriptor dest = NULL; - lumiera_filedescriptor fdesc; - fdesc.flags = flags; - - if (stat (name, &fdesc.stat) != 0) + LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex) { - if (errno == ENOENT && flags&O_CREAT) + lumiera_filedescriptor fdesc; + fdesc.flags = flags; + + if (stat (name, &fdesc.stat) != 0) { - char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX); - char* slash = dir; - while ((slash = strchr (slash+1, '/'))) + if (errno == ENOENT && flags&O_CREAT) { - *slash = '\0'; - INFO (filedescriptor, "try creating dir: %s", dir); - if (mkdir (dir, 0777) == -1 && errno != EEXIST) + char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX); + char* slash = dir; + while ((slash = strchr (slash+1, '/'))) + { + *slash = '\0'; + INFO (filedescriptor, "try creating dir: %s", dir); + if (mkdir (dir, 0777) == -1 && errno != EEXIST) + { + LUMIERA_ERROR_SET (filedescriptor, ERRNO); + goto error; + } + *slash = '/'; + } + int fd; + INFO (filedescriptor, "try creating file: %s", name); + fd = creat (name, 0777); + if (fd == -1) { LUMIERA_ERROR_SET (filedescriptor, ERRNO); - goto efile; + goto error; + } + close (fd); + if (stat (name, &fdesc.stat) != 0) + { + /* finally, no luck */ + LUMIERA_ERROR_SET (filedescriptor, ERRNO); + goto error; } - *slash = '/'; - } - int fd; - INFO (filedescriptor, "try creating file: %s", name); - fd = creat (name, 0777); - if (fd == -1) - { - LUMIERA_ERROR_SET (filedescriptor, ERRNO); - goto efile; - } - close (fd); - if (stat (name, &fdesc.stat) != 0) - { - /* finally, no luck */ - LUMIERA_ERROR_SET (filedescriptor, ERRNO); - goto efile; } } + + /* lookup/create descriptor */ + dest = &fdesc; + LumieraFiledescriptor* found = cuckoo_find (registry, &dest); + + if (!found) + { + TRACE (filedescriptor, "Descriptor not found"); + + dest = lumiera_filedescriptor_new (&fdesc); + if (!dest) + goto error; + + cuckoo_insert (registry, &dest); + } + else + { + TRACE (filedescriptor, "Descriptor already existing"); + dest = *found; + ++dest->refcount; + } + error: ; } - /* lookup/create descriptor */ - LumieraFiledescriptor dest = &fdesc; - LumieraFiledescriptor* found = cuckoo_find (registry, &dest); - - if (!found) - { - TRACE (filedescriptor, "Descriptor not found"); - - dest = lumiera_filedescriptor_new (&fdesc); - if (!dest) - goto ecreate; - - cuckoo_insert (registry, &dest); - } - else - { - TRACE (filedescriptor, "Descriptor already existing"); - dest = *found; - ++dest->refcount; - } - - lumiera_mutexacquirer_unlock (®istry_lock); return dest; - - efile: - ecreate: - lumiera_mutexacquirer_unlock (®istry_lock); - return NULL; } @@ -209,7 +212,7 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template) const char* type = "mutex"; const char* name = "filedescriptor"; - RESOURCE_ANNOUNCE (filedescriptor, type, name, self, self->rh); + RESOURCE_ANNOUNCE (filedescriptor, type, name, self, self->lock.rh); return self; } @@ -219,22 +222,21 @@ void lumiera_filedescriptor_delete (LumieraFiledescriptor self) { TRACE (filedescriptor, "%p", self); - lumiera_mutexacquirer registry_lock; - lumiera_mutexacquirer_init_mutex (®istry_lock, ®istry_mutex, LUMIERA_LOCKED); - REQUIRE (self->refcount == 0); + LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex) + { + REQUIRE (self->refcount == 0); - RESOURCE_FORGET (filedescriptor, self->rh); + RESOURCE_FORGET (filedescriptor, self->lock.rh); - cuckoo_remove (registry, cuckoo_find (registry, &self)); + cuckoo_remove (registry, cuckoo_find (registry, &self)); - TODO ("destruct other members (WIP)"); + TODO ("destruct other members (WIP)"); - TODO ("release filehandle"); + TODO ("release filehandle"); - lumiera_mutex_destroy (&self->lock); - lumiera_free (self); - - lumiera_mutexacquirer_unlock (®istry_lock); + lumiera_mutex_destroy (&self->lock); + lumiera_free (self); + } } diff --git a/src/backend/filedescriptor.h b/src/backend/filedescriptor.h index 528be41e8..668419b10 100644 --- a/src/backend/filedescriptor.h +++ b/src/backend/filedescriptor.h @@ -55,8 +55,6 @@ struct lumiera_filedescriptor_struct LumieraFilehandle handle; //LumieraFileMap mappings; //LumieraWriteBuffer writebuffer; - - RESOURCE_HANDLE (rh); }; /** diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c index 0a4852879..f3eb48d7e 100644 --- a/src/backend/filehandlecache.c +++ b/src/backend/filehandlecache.c @@ -45,7 +45,7 @@ lumiera_filehandlecache_new (int max_entries) lumiera_fhcache->available = max_entries; lumiera_fhcache->checked_out = 0; lumiera_mutex_init (&lumiera_fhcache->lock); - RESOURCE_ANNOUNCE (filehandlecache, "mutex", "filehandlecache", lumiera_fhcache, lumiera_fhcache->rh); + RESOURCE_ANNOUNCE (filehandlecache, "mutex", "filehandlecache", lumiera_fhcache, lumiera_fhcache->lock.rh); } @@ -55,7 +55,7 @@ lumiera_filehandlecache_delete (void) if (lumiera_fhcache) { REQUIRE (!lumiera_fhcache->checked_out, "Filehandles in use at shutdown"); - RESOURCE_FORGET (filehandlecache, lumiera_fhcache->rh); + RESOURCE_FORGET (filehandlecache, lumiera_fhcache->lock.rh); lumiera_mrucache_destroy (&lumiera_fhcache->cache); lumiera_mutex_destroy (&lumiera_fhcache->lock); lumiera_free (lumiera_fhcache); @@ -69,7 +69,8 @@ lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFile { TRACE (filehandlecache); LumieraFilehandle ret = NULL; - LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock) + + LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock) { if (self->available <= 0 && self->cache.cached) { @@ -106,7 +107,7 @@ lumiera_filehandlecache_checkout (LumieraFilehandlecache self, LumieraFilehandle if (!handle->use_cnt) { /* lock cache and checkout */ - LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock) + LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock) { lumiera_mrucache_checkout (&self->cache, &handle->cachenode); } @@ -128,7 +129,7 @@ lumiera_filehandlecache_checkin (LumieraFilehandlecache self, LumieraFilehandle if (!--handle->use_cnt) { /* lock cache and checin */ - LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock) + LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock) { --self->checked_out; lumiera_mrucache_checkin (&self->cache, &handle->cachenode); diff --git a/src/backend/filehandlecache.h b/src/backend/filehandlecache.h index 37c2a416b..f624caefe 100644 --- a/src/backend/filehandlecache.h +++ b/src/backend/filehandlecache.h @@ -49,7 +49,6 @@ struct lumiera_filehandlecache_struct int available; int checked_out; lumiera_mutex lock; - RESOURCE_HANDLE (rh); }; extern LumieraFilehandlecache lumiera_fhcache; diff --git a/src/lib/mutex.c b/src/lib/mutex.c index 20b0cce70..791ca8287 100644 --- a/src/lib/mutex.c +++ b/src/lib/mutex.c @@ -37,6 +37,7 @@ lumiera_mutex_init (LumieraMutex self) if (self) { pthread_mutex_init (&self->mutex, NULL); + NOBUG_RESOURCE_HANDLE_INIT (self->rh); } return self; } diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 7e67b550a..79424111d 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -28,15 +28,31 @@ * @file * Mutual exclusion locking, header. */ -#define LUMIERA_MUTEX_SECTION(flag, handle, mutex) \ -RESOURCE_HANDLE (rh_##__LINE__##_); \ -lumiera_mutexacquirer lock_##__LINE__##_; \ -RESOURCE_ENTER (flag, handle, "acquire mutex", &lock_##__LINE__##_, \ - NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \ -for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKED); \ - lock_##__LINE__##_.state == LUMIERA_LOCKED; \ - lumiera_mutexacquirer_unlock (&lock_##__LINE__##_), \ - ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);})) + + +/** + * 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); \ + } \ + })) /** @@ -46,6 +62,7 @@ for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKE struct lumiera_mutex_struct { pthread_mutex_t mutex; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_mutex_struct lumiera_mutex; typedef lumiera_mutex* LumieraMutex; @@ -69,14 +86,13 @@ LumieraMutex lumiera_mutex_destroy (LumieraMutex self); - /** - * mutexacquirer used to manage the state of a mutex variable. + * mutexacquirer used to manage the state of a mutex. */ struct lumiera_mutexacquirer_struct { - LumieraMutex mutex; - enum lumiera_lockstate state; + volatile LumieraMutex mutex; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_mutexacquirer_struct lumiera_mutexacquirer; typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer; @@ -85,123 +101,7 @@ typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer; static inline void lumiera_mutexacquirer_ensureunlocked (LumieraMutexacquirer self) { - ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock mutex"); -} - -/* override with a macro to use the cleanup checker */ -#define lumiera_mutexacquirer \ -lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) - - -/** - * initialize a mutexacquirer state without mutex. - * @param self mutexacquirer to be initialized, must be an automatic variable - * @return self as given - * This initialization is used when lumiera_mutexacquirer_try_mutex shall be used later - */ -static inline LumieraMutexacquirer -lumiera_mutexacquirer_init (LumieraMutexacquirer self) -{ - REQUIRE (self); - self->mutex = NULL; - self->state = LUMIERA_UNLOCKED; - - return self; -} - -/** - * initialize a mutexacquirer state - * @param self mutexacquirer to be initialized, must be an automatic variable - * @param mutex associated mutex - * @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED - * @return self as given - * errors are fatal - */ -static inline LumieraMutexacquirer -lumiera_mutexacquirer_init_mutex (LumieraMutexacquirer self, LumieraMutex mutex, enum lumiera_lockstate state) -{ - REQUIRE (self); - REQUIRE (mutex); - self->mutex = mutex; - self->state = state; - if (state == LUMIERA_LOCKED) - if (pthread_mutex_lock (&mutex->mutex)) - LUMIERA_DIE (MUTEX_LOCK); - - return self; -} - - -/** - * lock the mutex. - * must not already be locked - * @param self mutexacquirer associated with a mutex variable - */ -static inline void -lumiera_mutexacquirer_lock (LumieraMutexacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked"); - - if (pthread_mutex_lock (&self->mutex->mutex)) - LUMIERA_DIE (MUTEX_LOCK); - - self->state = LUMIERA_LOCKED; -} - - -/** - * get the state of a lock. - * @param self mutexacquirer associated with a mutex variable - * @return LUMIERA_LOCKED when the mutex is locked by this thead - */ -static inline enum lumiera_lockstate -lumiera_mutexacquirer_state (LumieraMutexacquirer self) -{ - REQUIRE (self); - return self->state; -} - - -/** - * try to lock a mutex. - * must not already be locked - * @param self mutexacquirer associated with a mutex variable - * @param mutex pointer to a mutex which should be tried - * @return LUMIERA_LOCKED when the mutex got locked - */ -static inline enum lumiera_lockstate -lumiera_mutexacquirer_try_mutex (LumieraMutexacquirer self, LumieraMutex mutex) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked"); - - self->mutex=mutex; - switch (pthread_mutex_trylock (&self->mutex->mutex)) - { - case 0: - return self->state = LUMIERA_LOCKED; - case EBUSY: - return LUMIERA_UNLOCKED; - default: - LUMIERA_DIE (MUTEX_LOCK); - } -} - - -/** - * release mutex. - * a mutexacquirer must be unlocked before leaving scope - * @param self mutexacquirer associated with a mutex variable - */ -static inline void -lumiera_mutexacquirer_unlock (LumieraMutexacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked"); - if (pthread_mutex_unlock (&self->mutex->mutex)) - LUMIERA_DIE (MUTEX_UNLOCK); - self->state = LUMIERA_UNLOCKED; + ENSURE (!self->mutex, "forgot to unlock mutex"); } #endif diff --git a/tests/15locking.tests b/tests/15locking.tests index 7bea487d5..80dda1a23 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -9,8 +9,18 @@ END +TEST "mutex section" mutexsection < #include #include "tests/test.h" +#include "lib/mutex.h" int conditionforgotunlock (); -int mutexforgotunlock (); TESTS_BEGIN @@ -33,9 +33,71 @@ TEST ("conditionforgotunlock") return conditionforgotunlock (); } -TEST ("mutexforgotunlock") +TEST ("mutexsection") { - return mutexforgotunlock (); + lumiera_mutex m; + lumiera_mutex_init (&m); + RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "mutexsection", &m, m.rh); + + LUMIERA_MUTEX_SECTION (NOBUG_ON, &m) + { + printf ("mutex locked section 1\n"); + } + + LUMIERA_MUTEX_SECTION (NOBUG_ON, &m) + { + printf ("mutex locked section 2\n"); + } + + RESOURCE_FORGET (NOBUG_ON, m.rh); + lumiera_mutex_destroy (&m); } + +TEST ("mutexforgotunlock") +{ + lumiera_mutex m; + lumiera_mutex_init (&m); + RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "mutexforgotunlock", &m, m.rh); + + LUMIERA_MUTEX_SECTION (NOBUG_ON, &m) + { + break; // MUTEX_SECTIONS must not be left by a jump + } + + RESOURCE_FORGET (NOBUG_ON, m.rh); + lumiera_mutex_destroy (&m); +} + + +TEST ("nestedmutexsection") +{ + lumiera_mutex m; + lumiera_mutex_init (&m); + RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "m_mutexsection", &m, m.rh); + + lumiera_mutex n; + lumiera_mutex_init (&n); + RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "n_mutexsection", &n, n.rh); + + LUMIERA_MUTEX_SECTION (NOBUG_ON, &m) + { + printf ("outer mutex locked section\n"); + + LUMIERA_MUTEX_SECTION (NOBUG_ON, &n) + { + printf ("inner mutex locked section\n"); + } + } + + RESOURCE_FORGET (NOBUG_ON, n.rh); + lumiera_mutex_destroy (&n); + + RESOURCE_FORGET (NOBUG_ON, m.rh); + lumiera_mutex_destroy (&m); +} + + + + TESTS_END From 777458741a29efe28cc8e5593a2c8e8346f4f468 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 10:29:51 +0200 Subject: [PATCH 007/102] moved the locking tests from test/locking/ to test/library/ --- tests/Makefile.am | 5 +-- tests/{locking => library}/test-locking.c | 14 +++++-- tests/locking/condition.c | 49 ----------------------- tests/locking/mutex.c | 32 --------------- 4 files changed, 11 insertions(+), 89 deletions(-) rename tests/{locking => library}/test-locking.c (92%) delete mode 100644 tests/locking/condition.c delete mode 100644 tests/locking/mutex.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 74d035034..c7ec4edae 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,10 +24,7 @@ test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/sr test_error_LDADD = liblumi.a -lnobugmt -lpthread -ldl check_PROGRAMS += test-locking -test_locking_SOURCES = \ - $(tests_srcdir)/locking/test-locking.c \ - $(tests_srcdir)/locking/mutex.c \ - $(tests_srcdir)/locking/condition.c +test_locking_SOURCES = $(tests_srcdir)/library/test-locking.c test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ test_locking_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm diff --git a/tests/locking/test-locking.c b/tests/library/test-locking.c similarity index 92% rename from tests/locking/test-locking.c rename to tests/library/test-locking.c index c95aa652e..79eba76a0 100644 --- a/tests/locking/test-locking.c +++ b/tests/library/test-locking.c @@ -19,20 +19,26 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include "tests/test.h" #include "lib/mutex.h" +#include "lib/condition.h" -int conditionforgotunlock (); +#include +#include TESTS_BEGIN TEST ("conditionforgotunlock") { - return conditionforgotunlock (); + lumiera_condition c; + lumiera_condition_init (&c); + + lumiera_conditionacquirer l; + lumiera_conditionacquirer_init (&l, &c, LUMIERA_LOCKED); + return 0; } + TEST ("mutexsection") { lumiera_mutex m; diff --git a/tests/locking/condition.c b/tests/locking/condition.c deleted file mode 100644 index 7d79e9a7e..000000000 --- a/tests/locking/condition.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - test condition 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. -*/ - -#include "lib/condition.h" - -#if 0 -waiting_thread() -{ - lock; - wait; - unlock; -} - - -signaling_thread() -{ - signal(); -} -#endif - - -int -conditionforgotunlock () -{ - lumiera_condition c; - lumiera_condition_init (&c); - - lumiera_conditionacquirer l; - lumiera_conditionacquirer_init (&l, &c, LUMIERA_LOCKED); - return 0; -} diff --git a/tests/locking/mutex.c b/tests/locking/mutex.c deleted file mode 100644 index f4f8c18f6..000000000 --- a/tests/locking/mutex.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - test mutex 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. -*/ - -#include "lib/mutex.h" - -int mutexforgotunlock() -{ - lumiera_mutex m; - lumiera_mutex_init (&m); - - lumiera_mutexacquirer l; - lumiera_mutexacquirer_init_mutex (&l, &m, LUMIERA_LOCKED); - return 0; -} From b2b205f6db660c3a1d272cf0ed11825af536bb0a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 11:04:10 +0200 Subject: [PATCH 008/102] remove unnecessary volatile (forgotten for a test) --- src/lib/mutex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 79424111d..bb01a822a 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -91,7 +91,7 @@ lumiera_mutex_destroy (LumieraMutex self); */ struct lumiera_mutexacquirer_struct { - volatile LumieraMutex mutex; + LumieraMutex mutex; RESOURCE_HANDLE (rh); }; typedef struct lumiera_mutexacquirer_struct lumiera_mutexacquirer; From d0b6919eea48d981575682c39e7c11e7277b2e9f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 12:51:40 +0200 Subject: [PATCH 009/102] locking.h bites the dust --- src/lib/Makefile.am | 1 - src/lib/locking.h | 54 --------------------------------------------- src/lib/mutex.h | 8 ++++++- 3 files changed, 7 insertions(+), 56 deletions(-) delete mode 100644 src/lib/locking.h diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2ae8a9b2d..f707b72b9 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -38,7 +38,6 @@ liblumi_a_SOURCES = \ noinst_HEADERS += \ $(liblumi_a_srcdir)/plugin.h \ $(liblumi_a_srcdir)/error.h \ - $(liblumi_a_srcdir)/locking.h \ $(liblumi_a_srcdir)/mutex.h \ $(liblumi_a_srcdir)/rwlock.h \ $(liblumi_a_srcdir)/condition.h \ diff --git a/src/lib/locking.h b/src/lib/locking.h deleted file mode 100644 index 3c4d497d8..000000000 --- a/src/lib/locking.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - locking.h - shared declarations for all locking primitives - - 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_LOCKING_H -#define LUMIERA_LOCKING_H - -#include -#include -#include - -#include "lib/error.h" - - -LUMIERA_ERROR_DECLARE (MUTEX_LOCK); -LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK); -LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); - -/** - * @file - * Shared declarations for all locking primitives. - */ - -/** - * used to store the current lock state. - * - * - */ -enum lumiera_lockstate - { - LUMIERA_UNLOCKED, - LUMIERA_LOCKED, - LUMIERA_RDLOCKED, - LUMIERA_WRLOCKED - }; - -#endif diff --git a/src/lib/mutex.h b/src/lib/mutex.h index bb01a822a..54206f7f1 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -22,13 +22,19 @@ #ifndef LUMIERA_MUTEX_H #define LUMIERA_MUTEX_H -#include "lib/locking.h" +#include "lib/error.h" + +#include +#include /** * @file * Mutual exclusion locking, header. */ +LUMIERA_ERROR_DECLARE (MUTEX_LOCK); +LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK); +LUMIERA_ERROR_DECLARE (MUTEX_DESTROY); /** * Mutual exclusive section. From c11915a4c4771949ce249c5df58ba08025f94d0c Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 13:44:34 +0200 Subject: [PATCH 010/102] new locking section macros for RWLocks, old acquirer bites the dust --- src/lib/rwlock.c | 112 ++++------------------------- src/lib/rwlock.h | 134 ++++++++++++++++------------------- tests/15locking.tests | 11 +++ tests/library/test-locking.c | 37 ++++++++++ 4 files changed, 125 insertions(+), 169 deletions(-) diff --git a/src/lib/rwlock.c b/src/lib/rwlock.c index a12642c01..9fad975b3 100644 --- a/src/lib/rwlock.c +++ b/src/lib/rwlock.c @@ -18,28 +18,30 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include + +#include "lib/error.h" #include "lib/rwlock.h" + LUMIERA_ERROR_DEFINE(RWLOCK_AGAIN, "maximum number of readlocks exceed"); LUMIERA_ERROR_DEFINE(RWLOCK_DEADLOCK, "deadlock detected"); -LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroy rwlock"); -LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock"); -LUMIERA_ERROR_DEFINE(RWLOCK_RLOCK, "rlock"); -LUMIERA_ERROR_DEFINE(RWLOCK_WLOCK, "wlock"); +LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroying rwlock"); +LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock rwlock failed"); +LUMIERA_ERROR_DEFINE(RWLOCK_RDLOCK, "locking rwlock for reading failed"); +LUMIERA_ERROR_DEFINE(RWLOCK_WRLOCK, "locking rwlock for writing failed"); /** * @file * Read/write locks. */ - LumieraRWLock lumiera_rwlock_init (LumieraRWLock self) { if (self) { pthread_rwlock_init (&self->rwlock, NULL); + NOBUG_RESOURCE_HANDLE_INIT (self->rh); } return self; } @@ -56,94 +58,10 @@ lumiera_rwlock_destroy (LumieraRWLock self) return self; } - - - - -LumieraRWLockacquirer -lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state) -{ - REQUIRE (self); - REQUIRE (rwlock); - REQUIRE (state != LUMIERA_LOCKED, "illegal state for rwlock"); - self->rwlock = rwlock; - self->state = state; - - if (state == LUMIERA_RDLOCKED) - switch (pthread_rwlock_rdlock (&rwlock->rwlock)) - { - case 0: - break; - case EAGAIN: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN); - return NULL; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_RLOCK); - } - else - switch (pthread_rwlock_wrlock (&rwlock->rwlock)) - { - case 0: - break; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_WLOCK); - } - - return self; -} - - - -LumieraRWLockacquirer -lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked"); - - switch (pthread_rwlock_rdlock (&self->rwlock->rwlock)) - { - case 0: - break; - case EAGAIN: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN); - return NULL; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_RLOCK); - } - - self->state = LUMIERA_RDLOCKED; - return self; -} - - - -LumieraRWLockacquirer -lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked"); - - switch (pthread_rwlock_wrlock (&self->rwlock->rwlock)) - { - case 0: - break; - case EDEADLK: - lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); - return NULL; - default: - LUMIERA_DIE (RWLOCK_WLOCK); - } - - self->state = LUMIERA_WRLOCKED; - return self; -} - +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h index 3ac7f82ed..8d8f69e0c 100644 --- a/src/lib/rwlock.h +++ b/src/lib/rwlock.h @@ -27,41 +27,71 @@ #endif #include +//#include #include -#include "lib/locking.h" - LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN); LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK); LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY); LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK); -LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK); -LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK); +LUMIERA_ERROR_DECLARE(RWLOCK_RDLOCK); +LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK); /** * @file * Read/write locks, header. */ -#define LUMIERA_RDLOCK_SECTION(flag, handle, rwlock) \ -RESOURCE_HANDLE (rh_##__LINE__##_); \ -lumiera_rwlockacquirer lock_##__LINE__##_; \ -RESOURCE_ENTER (flag, handle, "acquire rwlock (read)", &lock_##__LINE__##_, \ - NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \ -for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_RDLOCKED); \ - lock_##__LINE__##_.state == LUMIERA_RDLOCKED; \ - lumiera_rwlockacquirer_unlock (&lock_##__LINE__##_), \ - ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);})) -#define LUMIERA_WRLOCK_SECTION(flag, handle, rwlock) \ -RESOURCE_HANDLE (rh_##__LINE__##_); \ -lumiera_rwlockacquirer lock_##__LINE__##_; \ -RESOURCE_ENTER (flag, handle, "acquire rwlock (write)", &lock_##__LINE__##_, \ - NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \ -for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_WRLOCKED); \ - lock_##__LINE__##_.state == LUMIERA_WRLOCKED; \ - lumiera_rwlockacquirer_unlock (&lock_##__LINE__##_), \ - ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);})) +/** + * Read locked section. + */ +#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \ + for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \ + lumiera_rwlock_section_.rwlock;) \ + for ( \ + ({ \ + lumiera_rwlock_section_.rwlock = (rwlck); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \ + RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \ + NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \ + if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_RDLOCK); \ + }); \ + lumiera_rwlock_section_.rwlock; \ + ({ \ + if (lumiera_rwlock_section_.rwlock) \ + { \ + pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \ + lumiera_rwlock_section_.rwlock = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \ + } \ + })) + + +/** + * Write locked section. + */ +#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \ + for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \ + lumiera_rwlock_section_.rwlock;) \ + for ( \ + ({ \ + lumiera_rwlock_section_.rwlock = (rwlck); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \ + RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \ + NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \ + if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_WRLOCK); \ + }); \ + lumiera_rwlock_section_.rwlock; \ + ({ \ + if (lumiera_rwlock_section_.rwlock) \ + { \ + pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \ + lumiera_rwlock_section_.rwlock = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \ + } \ + })) + /** * RWLock. @@ -70,6 +100,7 @@ for (lumiera_rwlockacquirer_init (&lock_##__LINE__##_, rwlock, LUMIERA_WRLOCKED) struct lumiera_rwlock_struct { pthread_rwlock_t rwlock; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_rwlock_struct lumiera_rwlock; typedef lumiera_rwlock* LumieraRWLock; @@ -99,7 +130,7 @@ lumiera_rwlock_destroy (LumieraRWLock self); struct lumiera_rwlockacquirer_struct { LumieraRWLock rwlock; - enum lumiera_lockstate state; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_rwlockacquirer_struct lumiera_rwlockacquirer; typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer; @@ -108,56 +139,15 @@ typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer; static inline void lumiera_rwlockacquirer_ensureunlocked (LumieraRWLockacquirer self) { - ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the rwlock"); -} - -/* override with a macro to use the cleanup checker */ -#define lumiera_rwlockacquirer \ -lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) - -/** - * initialize a rwlockacquirer state - * @param self rwlockacquirer to be initialized, must be an automatic variable - * @param rwlock associated rwlock - * @param state initial state of the mutex, either LUMIERA_RDLOCKED, LUMIERA_WRLOCKED or LUMIERA_UNLOCKED - * @return self as given or NULL on error - */ -LumieraRWLockacquirer -lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state); - -/** - * readlock the rwlock. - * must not already be locked - * @param self rwlockacquirer associated with a rwlock - * @return self as given or NULL on error - */ -LumieraRWLockacquirer -lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self); - -/** - * writelock the rwlock. - * must not already be locked - * @param self rwlockacquirer associated with a rwlock - * @return self as given or NULL on error - */ -LumieraRWLockacquirer -lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self); - - -/** - * release rwlock. - * a rwlockacquirer must be unlocked before leaving scope - * @param self rwlockacquirer associated with a rwlock variable - */ -static inline void -lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked"); - if (pthread_rwlock_unlock (&self->rwlock->rwlock)) - LUMIERA_DIE (RWLOCK_UNLOCK); - self->state = LUMIERA_UNLOCKED; + ENSURE (!self->rwlock, "forgot to unlock rwlock"); } #endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/tests/15locking.tests b/tests/15locking.tests index 80dda1a23..b994db1b2 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -24,3 +24,14 @@ TEST "nested mutex section" nestedmutexsection < #include @@ -105,5 +106,41 @@ TEST ("nestedmutexsection") +TEST ("rwlocksection") +{ + lumiera_rwlock rwlock; + lumiera_rwlock_init (&rwlock); + RESOURCE_ANNOUNCE (NOBUG_ON, "rwlock", "rwlocksection", &rwlock, rwlock.rh); + + LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock) + { + printf ("write locked section 1\n"); + } + + LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock) + { + printf ("read locked section 2\n"); + } + + RESOURCE_FORGET (NOBUG_ON, rwlock.rh); + lumiera_rwlock_destroy (&rwlock); +} + + +TEST ("rwlockforgotunlock") +{ + lumiera_rwlock rwlock; + lumiera_rwlock_init (&rwlock); + RESOURCE_ANNOUNCE (NOBUG_ON, "rwlock", "rwlockforgotunlock", &rwlock, rwlock.rh); + + LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock) + { + break; // LOCK_SECTIONS must not be left by a jump + } + + RESOURCE_FORGET (NOBUG_ON, rwlock.rh); + lumiera_rwlock_destroy (&rwlock); +} + TESTS_END From d8f59fb72258d9c6867340d2c8cd512f0df190aa Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 16:15:29 +0200 Subject: [PATCH 011/102] Simplyfiy resource management Move the resource announce/forget into the rwlock init/destroy Move resource announcement/forget into the mutex init/destroy --- src/lib/mutex.c | 13 ++++++++++-- src/lib/mutex.h | 11 ++++++++-- src/lib/rwlock.c | 6 ++++-- src/lib/rwlock.h | 6 +++--- tests/library/test-locking.c | 39 +++++++++++------------------------- 5 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/lib/mutex.c b/src/lib/mutex.c index 791ca8287..99ef8897f 100644 --- a/src/lib/mutex.c +++ b/src/lib/mutex.c @@ -32,25 +32,34 @@ LUMIERA_ERROR_DEFINE (MUTEX_DESTROY, "Mutex destroy failed"); LumieraMutex -lumiera_mutex_init (LumieraMutex self) +lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag) { if (self) { pthread_mutex_init (&self->mutex, NULL); NOBUG_RESOURCE_HANDLE_INIT (self->rh); + NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "mutex", purpose, self, self->rh); } return self; } LumieraMutex -lumiera_mutex_destroy (LumieraMutex self) +lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag) { if (self) { + NOBUG_RESOURCE_FORGET_RAW (flag, self->rh); if (pthread_mutex_destroy (&self->mutex)) LUMIERA_DIE (MUTEX_DESTROY); } return self; } +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/mutex.h b/src/lib/mutex.h index 54206f7f1..681d29432 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -80,7 +80,7 @@ typedef lumiera_mutex* LumieraMutex; * @return self as given */ LumieraMutex -lumiera_mutex_init (LumieraMutex self); +lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag); /** @@ -89,7 +89,7 @@ lumiera_mutex_init (LumieraMutex self); * @return self as given */ LumieraMutex -lumiera_mutex_destroy (LumieraMutex self); +lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag); /** @@ -111,3 +111,10 @@ lumiera_mutexacquirer_ensureunlocked (LumieraMutexacquirer self) } #endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/rwlock.c b/src/lib/rwlock.c index 9fad975b3..c5287d535 100644 --- a/src/lib/rwlock.c +++ b/src/lib/rwlock.c @@ -36,22 +36,24 @@ LUMIERA_ERROR_DEFINE(RWLOCK_WRLOCK, "locking rwlock for writing failed"); */ LumieraRWLock -lumiera_rwlock_init (LumieraRWLock self) +lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag) { if (self) { pthread_rwlock_init (&self->rwlock, NULL); NOBUG_RESOURCE_HANDLE_INIT (self->rh); + NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "rwlock", purpose, self, self->rh); } return self; } LumieraRWLock -lumiera_rwlock_destroy (LumieraRWLock self) +lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag) { if (self) { + NOBUG_RESOURCE_FORGET_RAW (flag, self->rh); if (pthread_rwlock_destroy (&self->rwlock)) LUMIERA_DIE (RWLOCK_DESTROY); } diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h index 8d8f69e0c..23376979b 100644 --- a/src/lib/rwlock.h +++ b/src/lib/rwlock.h @@ -27,7 +27,6 @@ #endif #include -//#include #include LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN); @@ -111,7 +110,7 @@ typedef lumiera_rwlock* LumieraRWLock; * @return self as given */ LumieraRWLock -lumiera_rwlock_init (LumieraRWLock self); +lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag); /** * destroy a rwlock @@ -119,7 +118,8 @@ lumiera_rwlock_init (LumieraRWLock self); * @return self on success or NULL at error */ LumieraRWLock -lumiera_rwlock_destroy (LumieraRWLock self); +lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag); + diff --git a/tests/library/test-locking.c b/tests/library/test-locking.c index 30b1b10cc..da42a4f47 100644 --- a/tests/library/test-locking.c +++ b/tests/library/test-locking.c @@ -43,8 +43,7 @@ TEST ("conditionforgotunlock") TEST ("mutexsection") { lumiera_mutex m; - lumiera_mutex_init (&m); - RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "mutexsection", &m, m.rh); + lumiera_mutex_init (&m, "mutexsection", &NOBUG_FLAG(NOBUG_ON)); LUMIERA_MUTEX_SECTION (NOBUG_ON, &m) { @@ -56,36 +55,31 @@ TEST ("mutexsection") printf ("mutex locked section 2\n"); } - RESOURCE_FORGET (NOBUG_ON, m.rh); - lumiera_mutex_destroy (&m); + lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON)); } TEST ("mutexforgotunlock") { lumiera_mutex m; - lumiera_mutex_init (&m); - RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "mutexforgotunlock", &m, m.rh); + lumiera_mutex_init (&m, "mutexforgotunlock", &NOBUG_FLAG(NOBUG_ON)); LUMIERA_MUTEX_SECTION (NOBUG_ON, &m) { break; // MUTEX_SECTIONS must not be left by a jump } - RESOURCE_FORGET (NOBUG_ON, m.rh); - lumiera_mutex_destroy (&m); + lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON)); } TEST ("nestedmutexsection") { lumiera_mutex m; - lumiera_mutex_init (&m); - RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "m_mutexsection", &m, m.rh); + lumiera_mutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON)); lumiera_mutex n; - lumiera_mutex_init (&n); - RESOURCE_ANNOUNCE (NOBUG_ON, "mutex", "n_mutexsection", &n, n.rh); + lumiera_mutex_init (&n, "n_mutexsection", &NOBUG_FLAG(NOBUG_ON)); LUMIERA_MUTEX_SECTION (NOBUG_ON, &m) { @@ -97,11 +91,8 @@ TEST ("nestedmutexsection") } } - RESOURCE_FORGET (NOBUG_ON, n.rh); - lumiera_mutex_destroy (&n); - - RESOURCE_FORGET (NOBUG_ON, m.rh); - lumiera_mutex_destroy (&m); + lumiera_mutex_destroy (&n, &NOBUG_FLAG(NOBUG_ON)); + lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON)); } @@ -109,8 +100,7 @@ TEST ("nestedmutexsection") TEST ("rwlocksection") { lumiera_rwlock rwlock; - lumiera_rwlock_init (&rwlock); - RESOURCE_ANNOUNCE (NOBUG_ON, "rwlock", "rwlocksection", &rwlock, rwlock.rh); + lumiera_rwlock_init (&rwlock, "rwsection", &NOBUG_FLAG(NOBUG_ON)); LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock) { @@ -122,25 +112,20 @@ TEST ("rwlocksection") printf ("read locked section 2\n"); } - RESOURCE_FORGET (NOBUG_ON, rwlock.rh); - lumiera_rwlock_destroy (&rwlock); + lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON)); } - TEST ("rwlockforgotunlock") { lumiera_rwlock rwlock; - lumiera_rwlock_init (&rwlock); - RESOURCE_ANNOUNCE (NOBUG_ON, "rwlock", "rwlockforgotunlock", &rwlock, rwlock.rh); + lumiera_rwlock_init (&rwlock, "rwlockforgotunlock", &NOBUG_FLAG(NOBUG_ON)); LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock) { break; // LOCK_SECTIONS must not be left by a jump } - RESOURCE_FORGET (NOBUG_ON, rwlock.rh); - lumiera_rwlock_destroy (&rwlock); + lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON)); } - TESTS_END From dde54ec7b05bd2e8c8b15e20337eddd2eee9bf80 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 05:54:45 +0200 Subject: [PATCH 012/102] Adapt the condition implementation to the macro SECTION based approach --- src/lib/condition.c | 11 ++- src/lib/condition.h | 166 +++++++++++++---------------------- tests/15locking.tests | 26 ++++-- tests/library/test-locking.c | 45 +++++++--- 4 files changed, 121 insertions(+), 127 deletions(-) diff --git a/src/lib/condition.c b/src/lib/condition.c index ad4ae6b76..a7f17e57b 100644 --- a/src/lib/condition.c +++ b/src/lib/condition.c @@ -30,25 +30,30 @@ LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed"); LumieraCondition -lumiera_condition_init (LumieraCondition self) +lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag) { if (self) { pthread_cond_init (&self->cond, NULL); pthread_mutex_init (&self->mutex, NULL); + NOBUG_RESOURCE_HANDLE_INIT (self->rh); + NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "cond_var", purpose, self, self->rh); } return self; } LumieraCondition -lumiera_condition_destroy (LumieraCondition self) +lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag) { if (self) { + NOBUG_RESOURCE_FORGET_RAW (flag, self->rh); + if (pthread_mutex_destroy (&self->mutex)) LUMIERA_DIE (MUTEX_DESTROY); - else if (pthread_cond_destroy (&self->cond)) + + if (pthread_cond_destroy (&self->cond)) LUMIERA_DIE (CONDITION_DESTROY); } return self; diff --git a/src/lib/condition.h b/src/lib/condition.h index 8aea75100..3bdbcbedc 100644 --- a/src/lib/condition.h +++ b/src/lib/condition.h @@ -22,7 +22,9 @@ #ifndef LUMIERA_CONDITION_H #define LUMIERA_CONDITION_H -#include "lib/locking.h" +#include "lib/error.h" +#include "lib/mutex.h" + /** * @file @@ -31,6 +33,49 @@ LUMIERA_ERROR_DECLARE (CONDITION_DESTROY); + + +/** + * Condition section. + * Locks the condition mutex, one can use LUMIERA_CONDITION_WAIT to wait for signals or + * LUMIERA_CONDITION_SIGNAL or LUMIERA_CONDITION_BROADCAST to wake waiting threads + */ +#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \ + for (lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked) \ + lumiera_condition_section_ = {(LumieraCondition)1}; \ + lumiera_condition_section_.condition;) \ + for ( \ + ({ \ + lumiera_condition_section_.condition = (cnd); \ + NOBUG_IF(NOBUG_MODE_ALPHA, lumiera_condition_section_.flag = &NOBUG_FLAG(nobugflag)); \ + NOBUG_RESOURCE_HANDLE_INIT (lumiera_condition_section_.rh); \ + RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condition", &lumiera_condition_section_, \ + NOBUG_RESOURCE_EXCLUSIVE, lumiera_condition_section_.rh); \ + if (pthread_mutex_lock (&(cnd)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \ + }); \ + lumiera_condition_section_.condition; \ + ({ \ + if (lumiera_condition_section_.condition) \ + { \ + pthread_mutex_unlock (&lumiera_condition_section_.condition->mutex); \ + lumiera_condition_section_.condition = NULL; \ + RESOURCE_LEAVE(nobugflag, lumiera_condition_section_.rh); \ + } \ + })) + +#define LUMIERA_CONDITION_WAIT \ + do { \ + NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCEING); \ + pthread_cond_wait (&lumiera_condition_section_.condition->cond, &lumiera_condition_section_.condition->mutex); \ + NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCE_EXCLUSIVE); \ + while (0) + +#define LUMIERA_CONDITION_SIGNAL (nobugflag) pthread_cond_signal (&lumiera_condition_section_.condition->cond) + +#define LUMIERA_CONDITION_BROADCAST (nobugflag) pthread_cond_broadcast (&lumiera_condition_section_.condition->cond) + + + /** * Condition variables. * @@ -39,6 +84,7 @@ struct lumiera_condition_struct { pthread_cond_t cond; pthread_mutex_t mutex; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_condition_struct lumiera_condition; typedef lumiera_condition* LumieraCondition; @@ -50,7 +96,7 @@ typedef lumiera_condition* LumieraCondition; * @return self as given */ LumieraCondition -lumiera_condition_init (LumieraCondition self); +lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag); /** @@ -59,7 +105,7 @@ lumiera_condition_init (LumieraCondition self); * @return self as given */ LumieraCondition -lumiera_condition_destroy (LumieraCondition self); +lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag); /** @@ -101,8 +147,9 @@ lumiera_condition_broadcast (LumieraCondition self) */ struct lumiera_conditionacquirer_struct { - LumieraCondition cond; - enum lumiera_lockstate state; + LumieraCondition condition; + NOBUG_IF(NOBUG_MODE_ALPHA, struct nobug_flag* flag); + RESOURCE_HANDLE (rh); }; typedef struct lumiera_conditionacquirer_struct lumiera_conditionacquirer; typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer; @@ -111,108 +158,15 @@ typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer; static inline void lumiera_conditionacquirer_ensureunlocked (LumieraConditionacquirer self) { - ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the condition mutex"); -} - -/* override with a macro to use the cleanup checker */ -#define lumiera_conditionacquirer \ -lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked) - - -/** - * initialize a conditionacquirer state - * @param self conditionacquirer to be initialized, must be an automatic variable - * @param cond associated condition variable - * @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED - * @return self as given - * errors are fatal - */ -static inline LumieraConditionacquirer -lumiera_conditionacquirer_init (LumieraConditionacquirer self, LumieraCondition cond, enum lumiera_lockstate state) -{ - REQUIRE (self); - REQUIRE (cond); - self->cond = cond; - self->state = state; - if (state == LUMIERA_LOCKED) - if (pthread_mutex_lock (&cond->mutex)) - LUMIERA_DIE (MUTEX_LOCK); - - return self; -} - -/** - * lock the mutex. - * must not already be locked - * @param self conditionacquirer associated with a condition variable - */ -static inline void -lumiera_conditionacquirer_lock (LumieraConditionacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked"); - - if (pthread_mutex_lock (&self->cond->mutex)) - LUMIERA_DIE (MUTEX_LOCK); - - self->state = LUMIERA_LOCKED; -} - - -/** - * wait on a locked condition. - * Waits until the condition variable gets signaled from another thread. Must already be locked. - * @param self conditionacquirer associated with a condition variable - */ -static inline void -lumiera_conditionacquirer_wait (LumieraConditionacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_LOCKED, "mutex must be locked"); - pthread_cond_wait (&self->cond->cond, &self->cond->mutex); -} - - -/** - * release mutex. - * a conditionacquirer must be unlocked before leaving scope - * @param self conditionacquirer associated with a condition variable - */ -static inline void -lumiera_conditionacquirer_unlock (LumieraConditionacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked"); - if (pthread_mutex_unlock (&self->cond->mutex)) - LUMIERA_DIE (MUTEX_UNLOCK); - self->state = LUMIERA_UNLOCKED; -} - - -/** - * signal a single waiting thread - * @param self conditionacquirer associated with the condition variable to be signaled - */ -static inline void -lumiera_conditionacquirer_signal (LumieraConditionacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked"); - pthread_cond_signal (&self->cond->cond); -} - - -/** - * signal all waiting threads - * @param self conditionacquirer associated with the condition variable to be signaled - */ -static inline void -lumiera_conditionacquirer_broadcast (LumieraConditionacquirer self) -{ - REQUIRE (self); - REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked"); - pthread_cond_broadcast (&self->cond->cond); + ENSURE (!self->condition, "forgot to unlock condition variable"); } #endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/tests/15locking.tests b/tests/15locking.tests index b994db1b2..c7e8340e5 100644 --- a/tests/15locking.tests +++ b/tests/15locking.tests @@ -1,14 +1,6 @@ TESTING "Locking" ./test-locking -TEST "condition not unlocked asserts" conditionforgotunlock < Date: Sun, 10 Aug 2008 06:43:17 +0200 Subject: [PATCH 013/102] throw away the 'references' implementation, we probably don't need it (could be reincarnated someday later when we find out that we need it) --- src/lib/Makefile.am | 2 - src/lib/references.c | 187 -------------------------------- src/lib/references.h | 146 ------------------------- tests/16references.tests | 8 -- tests/Makefile.am | 5 - tests/library/test-references.c | 77 ------------- 6 files changed, 425 deletions(-) delete mode 100644 src/lib/references.c delete mode 100644 src/lib/references.h delete mode 100644 tests/16references.tests delete mode 100644 tests/library/test-references.c diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index f707b72b9..a2dcea8da 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -27,7 +27,6 @@ liblumi_a_SOURCES = \ $(liblumi_a_srcdir)/mutex.c \ $(liblumi_a_srcdir)/rwlock.c \ $(liblumi_a_srcdir)/condition.c \ - $(liblumi_a_srcdir)/references.c \ $(liblumi_a_srcdir)/luid.c \ $(liblumi_a_srcdir)/safeclib.c \ $(liblumi_a_srcdir)/cuckoo.c \ @@ -41,7 +40,6 @@ noinst_HEADERS += \ $(liblumi_a_srcdir)/mutex.h \ $(liblumi_a_srcdir)/rwlock.h \ $(liblumi_a_srcdir)/condition.h \ - $(liblumi_a_srcdir)/references.h \ $(liblumi_a_srcdir)/luid.h \ $(liblumi_a_srcdir)/safeclib.h \ $(liblumi_a_srcdir)/cuckoo.h \ diff --git a/src/lib/references.c b/src/lib/references.c deleted file mode 100644 index 18c01edec..000000000 --- a/src/lib/references.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - references.c - strong and weak references - - 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/references.h" -#include "lib/safeclib.h" - -/** - * @file - * Strong and Weak references - * Strong references keep some object alive while they existing - * Weak references become invalidated when the referenced object gets destroyed - * - * Thread safety: references protect their internal operations with a mutex (optimization using futex may come in future) - * while operations on the reference itself (initialization, destruction, strengthen, weaken) and on the referenced object (get) - * should be protected from elsewhere. - */ - - -LumieraReference -lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*)) -{ - LumieraReftarget target = lumiera_malloc (sizeof(lumiera_reftarget)); - - target->object = obj; - target->dtor = dtor; - target->strong_cnt = 1; - target->weak_cnt = 0; - lumiera_mutex_init (&target->lock); - - self->object = obj; - self->target = target; - return self; -} - - -LumieraReference -lumiera_reference_destroy (LumieraReference self) -{ - LumieraReftarget target = self->target; - - /* defensive, lets detect errors if anything still tries to use this reference */ - self->target = NULL; - - lumiera_mutexacquirer lock; - lumiera_mutexacquirer_init_mutex (&lock, &target->lock, LUMIERA_LOCKED); - - if (self->object) - { - /* strong reference */ - if (!--target->strong_cnt) - { - /* was last strong reference */ - if (target->dtor) - target->dtor (target->object); - target->object = NULL; - if (!target->weak_cnt) - { - /* no weak refs either, destroy it */ - lumiera_mutexacquirer_unlock (&lock); - lumiera_mutex_destroy (&target->lock); - free (target); - return self; - } - } - } - else - { - /* weak reference */ - if (!--target->weak_cnt && !target->strong_cnt) - { - /* was last weak reference, and no strong refs left */ - lumiera_mutexacquirer_unlock (&lock); - lumiera_mutex_destroy (&target->lock); - free (target); - return self; - } - } - lumiera_mutexacquirer_unlock (&lock); - return self; -} - - -LumieraReference -lumiera_reference_strong_init (LumieraReference self, LumieraReference source) -{ - lumiera_mutexacquirer lock; - lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED); - - self->object = source->target->object; - self->target = source->target; - - if (self->object) - { - ++self->target->strong_cnt; - } - else - { - ++self->target->weak_cnt; - self = NULL; - } - lumiera_mutexacquirer_unlock (&lock); - return self; -} - - -LumieraReference -lumiera_reference_weak_init (LumieraReference self, LumieraReference source) -{ - lumiera_mutexacquirer lock; - lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED); - - self->object = NULL; - self->target = source->target; - - ++self->target->weak_cnt; - if (!self->target->object) - /* already invalidated */ - self = NULL; - - lumiera_mutexacquirer_unlock (&lock); - return self; -} - - -LumieraReference -lumiera_reference_weaken (restrict LumieraReference self) -{ - /* is this a strong reference? */ - if (self->object) - { - lumiera_mutexacquirer lock; - lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED); - - self->object = NULL; - ++self->target->weak_cnt; - if (!--self->target->strong_cnt) - { - if (self->target->dtor) - self->target->dtor (self->target->object); - self->target->object = NULL; - self = NULL; - } - lumiera_mutexacquirer_unlock (&lock); - } - return self; -} - - -LumieraReference -lumiera_reference_strengthen (LumieraReference self) -{ - /* is this a weak reference? */ - if (!self->object) - { - lumiera_mutexacquirer lock; - lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED); - - if (self->target->object) - { - self->object = self->target->object; - --self->target->weak_cnt; - ++self->target->strong_cnt; - } - else - self = NULL; - lumiera_mutexacquirer_unlock (&lock); - } - return self; -} - diff --git a/src/lib/references.h b/src/lib/references.h deleted file mode 100644 index 3e9bf01fe..000000000 --- a/src/lib/references.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - references.h - strong and weak references - - 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_REFERENCES_H -#define LUMIERA_REFERENCES_H - -#include - -/** - * @file - * Strong and Weak references, header. - */ - - -typedef struct lumiera_reference_struct lumiera_reference; -typedef lumiera_reference* LumieraReference; - -#include "lib/error.h" -#include "lib/mutex.h" - -/* Implementation detail */ -struct lumiera_reftarget_struct -{ - void* object; - void (*dtor)(void*); - unsigned strong_cnt; /*when strong becomes 0 obj is destroyed, if weak is 0 destroy target too*/ - unsigned weak_cnt; /*when weak becomes 0 and !obj and lock strong is 0, destroy target */ - lumiera_mutex lock; -}; -typedef struct lumiera_reftarget_struct lumiera_reftarget; -typedef lumiera_reftarget* LumieraReftarget; - - -/** - * A reference pointing to some other object - */ -struct lumiera_reference_struct -{ - void* object; /*set for strong, NULL for weak*/ - LumieraReftarget target; -}; - -#define lumiera_reference \ -lumiera_reference NOBUG_CLEANUP(lumiera_reference_ensuredestroyed) - -/* helper function for nobug */ -static inline void -lumiera_reference_ensuredestroyed (LumieraReference self) -{ - ENSURE (!self->target, "forgot to destroy reference"); -} - - -/** - * Construct an initial strong reference from an object. - * For every object which should be managed with references you need to construct an initial strong reference - * which then will be used to initialize all further references. - * @param self pointer to the reference to be initialized - * @param obj pointer to the object being referenced - * @param dtor destructor function which will be called on obj when the last strong reference gets deleted - * @return self as given - */ -LumieraReference -lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*)); - - -/** - * Destroy a reference. - * All references need to be destroyed when not used any more. - * When the last strong reference gets destroyed, the object's destructor is called. - * Remaining weak references stay invalidated then until they get destroyed too. - * @param self reference to be destroyed - * @return self as given - * destroying a reference is not thread safe as far as 2 threads try to concurrently destroy it! - */ -LumieraReference -lumiera_reference_destroy (LumieraReference self); - -/** - * Get object from a strong reference. - * @return pointer to object, NULL if applied to a weak reference - */ -static inline void* -lumiera_reference_get (LumieraReference self) -{ - ENSURE (self->target, "illegal reference (not initialized or already destroyed?)"); - return self->object; -} - - -/** - * Copy construct a reference as strong reference - * @param source reference to copy - * @return self as strong reference (always for strong references) or NULL if source is an invalidated weak reference, - * in the later case the reference is constructed as weak reference barely to allow it be destroyed - */ -LumieraReference -lumiera_reference_strong_init (LumieraReference self, LumieraReference source); - - -/** - * Copy construct a reference as weak reference - * @param source reference to copy - * @return self (always for strong references) or NULL if self is an invalidated weak reference - */ -LumieraReference -lumiera_reference_weak_init (LumieraReference self, LumieraReference source); - - -/** - * turn a (strong) reference into a weak reference - * Weaken a reference may remove its last strong reference and thus destroy the object - * do nothing if the referene is already weak - * @return self or NULL if the final strong reference got removed, - */ -LumieraReference -lumiera_reference_weaken (restrict LumieraReference self); - - -/** - * turn a (weak) reference into a strong reference - * only references of object which are not already destroyed can be strengthened - * @return self when successful, NULL when the object was already destroyed, 'self' stays a dead weak reference in that case - */ -LumieraReference -lumiera_reference_strengthen (LumieraReference self); - -#endif diff --git a/tests/16references.tests b/tests/16references.tests deleted file mode 100644 index 9be462fc4..000000000 --- a/tests/16references.tests +++ /dev/null @@ -1,8 +0,0 @@ -TESTING "Strong and Weak references" ./test-references - -TEST "references basic functionality" basic < - - 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 -//#include - -#include "lib/references.h" - - -LUMIERA_ERROR_DEFINE(TEST, "test error"); - - -struct example -{ - int foo; -}; - -void -example_dtor(void* o) -{ - printf ("destruct: %d\n", ((struct example*)o)->foo); - ((struct example*)o)->foo = 0; - - // free(o) -} - -int -main (int argc, char** argv) -{ - NOBUG_INIT; - - if (argc == 1) - return 0; - - if (!strcmp(argv[1], "basic")) - { - struct example test; - test.foo = 123; - - lumiera_reference hold; - - lumiera_reference_strong_init_once (&hold, &test, example_dtor); - - - struct example* r = lumiera_reference_get (&hold); - - printf ("got: %d\n", r->foo); - - lumiera_reference_destroy (&hold); - } - else if (!strcmp(argv[1], "nodeinsert")) - { - - } - else - return 1; - - return 0; -} From 85e789742ff0dbba7e5fd0ce0c76404160c79865 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 6 Aug 2008 09:39:48 +0200 Subject: [PATCH 014/102] first skeleton for the config loader --- src/backend/Makefile.am | 6 +- src/backend/config.c | 123 +++++++++++++++++++++++++++++++ src/backend/config.h | 155 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 src/backend/config.c create mode 100644 src/backend/config.h diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 8b33df06a..9293d9415 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -27,7 +27,8 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/file.c \ $(liblumibackend_a_srcdir)/filehandle.c \ $(liblumibackend_a_srcdir)/filedescriptor.c \ - $(liblumibackend_a_srcdir)/filehandlecache.c + $(liblumibackend_a_srcdir)/filehandlecache.c \ + $(liblumibackend_a_srcdir)/config.c noinst_HEADERS += \ @@ -36,5 +37,6 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/file.h \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ - $(liblumibackend_a_srcdir)/filehandlecache.h + $(liblumibackend_a_srcdir)/filehandlecache.h \ + $(liblumibackend_a_srcdir)/config.h diff --git a/src/backend/config.c b/src/backend/config.c new file mode 100644 index 000000000..047cb9f4d --- /dev/null +++ b/src/backend/config.c @@ -0,0 +1,123 @@ +/* + config.c - Lumiera configuration system + + 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// + + +//TODO: Lumiera header includes// +#include "backend/config.h" + +//TODO: internal/static forward declarations// + + +//TODO: System includes// + + +/** + * @file + * + */ + +NOBUG_DEFINE_FLAG_PARENT (config_all, backend); +NOBUG_DEFINE_FLAG_PARENT (config, config_all); + +LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "Syntax error in configfile"); + + + +lumiera_err +lumiera_config_init (const char* path) +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_destroy() +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_load (const char* file) +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_save () +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_purge (const char* filename) +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_get (const char* key, const char** value) +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_set (const char* key, const char* value) +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_reset(const char* key) +{ + UNIMPLEMENTED(); + return NULL; +} + + +lumiera_err +lumiera_config_info (const char* key, const char** filename, unsigned* line) +{ + UNIMPLEMENTED(); + return NULL; +} + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/config.h b/src/backend/config.h new file mode 100644 index 000000000..c797b73db --- /dev/null +++ b/src/backend/config.h @@ -0,0 +1,155 @@ +/* + config.h - Lumiera configuration system + + 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_CONFIG_H +#define LUMIERA_CONFIG_H + +//TODO: Support library includes// +#include "lib/error.h" + +//TODO: Forward declarations// +struct lumiera_config_struct; + +NOBUG_DECLARE_FLAG (config_all); +NOBUG_DECLARE_FLAG (config); + +LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); + +//TODO: Lumiera header includes// + + +//TODO: System includes// +#include + + +/** + * @file + * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader + */ + + +/** + * Supported high level types: TODO documenting + */ +/* TODO: add here as 'LUMIERA_CONFIG_TYPE(name, ctype)' the _get/_set prototypes are declared automatically below, you still have to implement them in config.c */ +#define LUMIERA_CONFIG_TYPES \ + LUMIERA_CONFIG_TYPE(number, signed long long) \ + LUMIERA_CONFIG_TYPE(real, long double) \ + LUMIERA_CONFIG_TYPE(string, const char*) \ + LUMIERA_CONFIG_TYPE(word, const char*) \ + LUMIERA_CONFIG_TYPE(bool, int) + + +// * does only initialize the variables, so that they get valid values, but does not allocate them as they will be allocated before as they are singleton. +// * lumiera_config_init (const char* searchpath) searchpath is a buildin-default, can be changed via configure and can be appended and overridden by using a flag, e.g. {{{ --config-path-append="" }}} or {{{ --config-path="" }}} +lumiera_err +lumiera_config_init (const char* path); + + +// * frees all space allocated by the ConfigLoader. +lumiera_err +lumiera_config_destroy(); + + +// * reads '''one''' single configuration file that will include all settings from other files. +// * does not read itself but give delegates reading. The actual reading and parsing will be done in configfile object. s.later. +lumiera_err +lumiera_config_load (const char* file); + + +//{{{ lumiera_config_save () { LLIST_FOREACH(config_singleton.files, f) { LumieraFile file = (LumieraFile) f; if(lumiera_configfile_isdirty (file)) lumiera_configfile_save(file); } } }}} +// * saves all the changed settings to user's configuration files, but recognizes where settings came from and will write them to an appropriate named file. Example: '''changed''' values from ''/usr/local/share/lumiera/plugins/blur.conf'' will be saved into ''~/.lumiera/plugins/blur.conf'' +// * finds out which files are dirty and which settings have to be written to user's config files. +// * does initiate the actual saving procedure by delegating the save to the actual configfile objects, see below. +// * empty user configuration files in RAM will be deleted from disk on write. +// * checks whether the file has changed since last read, and will print out an error if necessary instead of overriding it without notification. +lumiera_err +lumiera_config_save (); + + +// * `lumiera_config_purge(const char* filename)` removes all configs loaded from filename +lumiera_err +lumiera_config_purge (const char* filename); + + +// * {{{ lumiera_config_get(...) }}} +// * get a value by key +// * handles internally everything as string:string key:value pair. +// * lowlevel function +// * lumiera_config_integer_get (const char* key, int *value) will return integers instead of strings and return 0 if succeeded and -1 if it failed. +lumiera_err +lumiera_config_get (const char* key, const char** value); + + +// * {{{ lumiera_config_set(...) }}} +// * set a value by key +// * handles internally everything as string:string key:value pair. +// * lowlevel function +// * tag file as dirty +// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called. +lumiera_err +lumiera_config_set (const char* key, const char* value); + + + +// * {{{int lumiera_config_TYPE_get(const char* key, TYPE* value, const char* default) }}} +// High level config interface for different types. +// if default is given (!NULL) then value is set to default in case key was not found or any other error occured. +// error code is still set and -1 (fail) is returned in case of an error, but it might be cleared with no ill effects. +// NOTE: errors are persistent in our error handler, they must still be cleared, even when ignored. +// if default is given then 'KEY_NOT_FOUND' is not a error here, if default is NULL then it is +// NOTE2: default values are given as strings, the config loader remembers a given default value and checks if it got changed +// when it is _set(). Thus a default value can be supressed when set/written +#define LUMIERA_CONFIG_TYPE(name, type) \ + lumiera_err \ + lumiera_config_##name##_get (const char* key, type* value, const char* def); +LUMIERA_CONFIG_TYPES +#undef LUMIERA_CONFIG_TYPE + + + +// * {{{ 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. +#define LUMIERA_CONFIG_TYPE(name, type) \ + lumiera_err \ + lumiera_config_##name##_set (const char* key, type* value, const char* fmt); +LUMIERA_CONFIG_TYPES +#undef LUMIERA_CONFIG_TYPE + + +// * {{{ lumiera_config_reset(...) }}} +// * reset a value by key to the system default values, thus removes a user's configuration line. +lumiera_err +lumiera_config_reset(const char* key); + + +// * Find exact place of a setting. +lumiera_err +lumiera_config_info (const char* key, const char** filename, unsigned* line); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From 9444fb02674571d2d67c10cea50d93d4139bfe3f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 6 Aug 2008 10:11:04 +0200 Subject: [PATCH 015/102] use 'int' as return values rather than lumiera_err --- src/backend/config.c | 38 ++++++++++++++++++++------------------ src/backend/config.h | 22 +++++++++++----------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 047cb9f4d..c85586192 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -43,75 +43,77 @@ LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "Syntax error in configfile"); -lumiera_err +int lumiera_config_init (const char* path) { UNIMPLEMENTED(); - return NULL; + return -1; } -lumiera_err +int lumiera_config_destroy() { UNIMPLEMENTED(); - return NULL; + return -1; } -lumiera_err +int lumiera_config_load (const char* file) { UNIMPLEMENTED(); - return NULL; + return -1; } -lumiera_err +int lumiera_config_save () { UNIMPLEMENTED(); - return NULL; + return -1; } -lumiera_err +int lumiera_config_purge (const char* filename) { UNIMPLEMENTED(); - return NULL; + return -1; } -lumiera_err +int lumiera_config_get (const char* key, const char** value) { UNIMPLEMENTED(); - return NULL; + // env var override + + return -1; } -lumiera_err +int lumiera_config_set (const char* key, const char* value) { UNIMPLEMENTED(); - return NULL; + return -1; } -lumiera_err +int lumiera_config_reset(const char* key) { UNIMPLEMENTED(); - return NULL; + return -1; } -lumiera_err +int lumiera_config_info (const char* key, const char** filename, unsigned* line) { UNIMPLEMENTED(); - return NULL; + return -1; } /* diff --git a/src/backend/config.h b/src/backend/config.h index c797b73db..858436f84 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -60,18 +60,18 @@ LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); // * does only initialize the variables, so that they get valid values, but does not allocate them as they will be allocated before as they are singleton. // * lumiera_config_init (const char* searchpath) searchpath is a buildin-default, can be changed via configure and can be appended and overridden by using a flag, e.g. {{{ --config-path-append="" }}} or {{{ --config-path="" }}} -lumiera_err +int lumiera_config_init (const char* path); // * frees all space allocated by the ConfigLoader. -lumiera_err +int lumiera_config_destroy(); // * reads '''one''' single configuration file that will include all settings from other files. // * does not read itself but give delegates reading. The actual reading and parsing will be done in configfile object. s.later. -lumiera_err +int lumiera_config_load (const char* file); @@ -81,12 +81,12 @@ lumiera_config_load (const char* file); // * does initiate the actual saving procedure by delegating the save to the actual configfile objects, see below. // * empty user configuration files in RAM will be deleted from disk on write. // * checks whether the file has changed since last read, and will print out an error if necessary instead of overriding it without notification. -lumiera_err +int lumiera_config_save (); // * `lumiera_config_purge(const char* filename)` removes all configs loaded from filename -lumiera_err +int lumiera_config_purge (const char* filename); @@ -95,7 +95,7 @@ lumiera_config_purge (const char* filename); // * handles internally everything as string:string key:value pair. // * lowlevel function // * lumiera_config_integer_get (const char* key, int *value) will return integers instead of strings and return 0 if succeeded and -1 if it failed. -lumiera_err +int lumiera_config_get (const char* key, const char** value); @@ -105,7 +105,7 @@ lumiera_config_get (const char* key, const char** value); // * lowlevel function // * tag file as dirty // * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called. -lumiera_err +int lumiera_config_set (const char* key, const char* value); @@ -119,7 +119,7 @@ lumiera_config_set (const char* key, const char* value); // NOTE2: default values are given as strings, the config loader remembers a given default value and checks if it got changed // when it is _set(). Thus a default value can be supressed when set/written #define LUMIERA_CONFIG_TYPE(name, type) \ - lumiera_err \ + int \ lumiera_config_##name##_get (const char* key, type* value, const char* def); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE @@ -129,7 +129,7 @@ LUMIERA_CONFIG_TYPES // * {{{ 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. #define LUMIERA_CONFIG_TYPE(name, type) \ - lumiera_err \ + int \ lumiera_config_##name##_set (const char* key, type* value, const char* fmt); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE @@ -137,12 +137,12 @@ LUMIERA_CONFIG_TYPES // * {{{ lumiera_config_reset(...) }}} // * reset a value by key to the system default values, thus removes a user's configuration line. -lumiera_err +int lumiera_config_reset(const char* key); // * Find exact place of a setting. -lumiera_err +int lumiera_config_info (const char* key, const char** filename, unsigned* line); #endif From c8210708fa67d2ce25a9a65886bad18531b061b3 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 6 Aug 2008 10:11:43 +0200 Subject: [PATCH 016/102] skeleton for the config struct --- src/backend/config.c | 3 +++ src/backend/config.h | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/backend/config.c b/src/backend/config.c index c85586192..630a656f2 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -42,6 +42,9 @@ NOBUG_DEFINE_FLAG_PARENT (config, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "Syntax error in configfile"); +/* singleton config */ +static lumiera_config; + int lumiera_config_init (const char* path) diff --git a/src/backend/config.h b/src/backend/config.h index 858436f84..d4f3ef6ce 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -46,6 +46,15 @@ LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); */ +struct lumiera_config_struct +{ + // cuckoo hash + // configfile list +}; + +typedef struct lumiera_config_struct lumiera_config; +typedef lumiera_config* LumieraConfig; + /** * Supported high level types: TODO documenting */ From b691a9d7bb925c692f619cc992b6dce71c649aa6 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 06:09:50 +0200 Subject: [PATCH 017/102] Simple config init/destroy, beginning of a config-testsuite --- src/backend/config.c | 27 +++++++++++++++------- src/backend/config.h | 45 +++++++++++++++++++++++++++++++++++-- tests/20config.tests | 43 +++++++++++++++++++++++++++++++++++ tests/Makefile.am | 5 +++++ tests/backend/test-config.c | 37 ++++++++++++++++++++++++++++++ 5 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 tests/20config.tests create mode 100644 tests/backend/test-config.c diff --git a/src/backend/config.c b/src/backend/config.c index 630a656f2..60311af72 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -20,6 +20,7 @@ */ //TODO: Support library includes// +#include "lib/safeclib.h" //TODO: Lumiera header includes// @@ -29,7 +30,7 @@ //TODO: System includes// - +#include /** * @file @@ -40,25 +41,35 @@ NOBUG_DEFINE_FLAG_PARENT (config_all, backend); NOBUG_DEFINE_FLAG_PARENT (config, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "Syntax error in configfile"); +LUMIERA_ERROR_DEFINE (CONFIG_TYPE, "Config value has wrong type"); /* singleton config */ -static lumiera_config; +static LumieraConfig the_config = NULL; int lumiera_config_init (const char* path) { - UNIMPLEMENTED(); - return -1; + REQUIRE (!the_config, "Configuration subsystem already initialized"); + + the_config = malloc (sizeof (*the_config)); + the_config->path = lumiera_strndup (path, SIZE_MAX); + return 0; } -int -lumiera_config_destroy() +void +lumiera_config_destroy () { - UNIMPLEMENTED(); - return -1; + if (the_config) + { + lumiera_free (the_config->path); + lumiera_free (the_config); + the_config = NULL; + } + else + WARN (config, "Tried to destroy non initialized config subsystem"); } diff --git a/src/backend/config.h b/src/backend/config.h index d4f3ef6ce..89ce0caab 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -28,10 +28,12 @@ //TODO: Forward declarations// struct lumiera_config_struct; + NOBUG_DECLARE_FLAG (config_all); NOBUG_DECLARE_FLAG (config); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); +LUMIERA_ERROR_DECLARE (CONFIG_TYPE); //TODO: Lumiera header includes// @@ -50,6 +52,7 @@ struct lumiera_config_struct { // cuckoo hash // configfile list + char* path; }; typedef struct lumiera_config_struct lumiera_config; @@ -69,17 +72,31 @@ typedef lumiera_config* LumieraConfig; // * does only initialize the variables, so that they get valid values, but does not allocate them as they will be allocated before as they are singleton. // * lumiera_config_init (const char* searchpath) searchpath is a buildin-default, can be changed via configure and can be appended and overridden by using a flag, e.g. {{{ --config-path-append="" }}} or {{{ --config-path="" }}} + +/** + * Initialize the configuration subsystem. + * @param path search path for config files. + * Must be called only once + */ int lumiera_config_init (const char* path); // * frees all space allocated by the ConfigLoader. -int -lumiera_config_destroy(); + +/** + * Destroys the configuration subsystem. + * Subsequent calls are no-ops. + */ +void +lumiera_config_destroy (); // * reads '''one''' single configuration file that will include all settings from other files. // * does not read itself but give delegates reading. The actual reading and parsing will be done in configfile object. s.later. +/** + * + */ int lumiera_config_load (const char* file); @@ -90,11 +107,17 @@ lumiera_config_load (const char* file); // * does initiate the actual saving procedure by delegating the save to the actual configfile objects, see below. // * empty user configuration files in RAM will be deleted from disk on write. // * checks whether the file has changed since last read, and will print out an error if necessary instead of overriding it without notification. +/** + * + */ int lumiera_config_save (); // * `lumiera_config_purge(const char* filename)` removes all configs loaded from filename +/** + * + */ int lumiera_config_purge (const char* filename); @@ -104,6 +127,9 @@ lumiera_config_purge (const char* filename); // * handles internally everything as string:string key:value pair. // * lowlevel function // * lumiera_config_integer_get (const char* key, int *value) will return integers instead of strings and return 0 if succeeded and -1 if it failed. +/** + * + */ int lumiera_config_get (const char* key, const char** value); @@ -114,6 +140,9 @@ lumiera_config_get (const char* key, const char** value); // * lowlevel function // * tag file as dirty // * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called. +/** + * + */ int lumiera_config_set (const char* key, const char* value); @@ -127,6 +156,9 @@ lumiera_config_set (const char* key, const char* value); // if default is given then 'KEY_NOT_FOUND' is not a error here, if default is NULL then it is // NOTE2: default values are given as strings, the config loader remembers a given default value and checks if it got changed // when it is _set(). Thus a default value can be supressed when set/written +/** + * + */ #define LUMIERA_CONFIG_TYPE(name, type) \ int \ lumiera_config_##name##_get (const char* key, type* value, const char* def); @@ -137,6 +169,9 @@ LUMIERA_CONFIG_TYPES // * {{{ 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. +/** + * + */ #define LUMIERA_CONFIG_TYPE(name, type) \ int \ lumiera_config_##name##_set (const char* key, type* value, const char* fmt); @@ -146,11 +181,17 @@ LUMIERA_CONFIG_TYPES // * {{{ lumiera_config_reset(...) }}} // * reset a value by key to the system default values, thus removes a user's configuration line. +/** + * + */ int lumiera_config_reset(const char* key); // * Find exact place of a setting. +/** + * + */ int lumiera_config_info (const char* key, const char** filename, unsigned* line); diff --git a/tests/20config.tests b/tests/20config.tests new file mode 100644 index 000000000..060334900 --- /dev/null +++ b/tests/20config.tests @@ -0,0 +1,43 @@ +TESTING "test configuration system" ./test-config + +TEST "initializing config system" init < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "lib/safeclib.h" + +#include "backend/config.h" + +#include "tests/test.h" + +TESTS_BEGIN + +TEST ("init") +{ + lumiera_config_init ("./"); + printf ("initialized\n"); + lumiera_config_destroy (); + printf ("destroyed\n"); +} + +TESTS_END From 1ff0583e4cdb4628fe62a7607a02b2a4352cfb7a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 06:10:29 +0200 Subject: [PATCH 018/102] add 'config_typed.c' for the typed high level config interface --- src/backend/Makefile.am | 7 +- src/backend/config_typed.c | 145 +++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 src/backend/config_typed.c diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 9293d9415..34d48c9ed 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -27,8 +27,9 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/file.c \ $(liblumibackend_a_srcdir)/filehandle.c \ $(liblumibackend_a_srcdir)/filedescriptor.c \ - $(liblumibackend_a_srcdir)/filehandlecache.c \ - $(liblumibackend_a_srcdir)/config.c + $(liblumibackend_a_srcdir)/filehandlecache.c \ + $(liblumibackend_a_srcdir)/config.c \ + $(liblumibackend_a_srcdir)/config_typed.c noinst_HEADERS += \ @@ -37,6 +38,6 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/file.h \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ - $(liblumibackend_a_srcdir)/filehandlecache.h \ + $(liblumibackend_a_srcdir)/filehandlecache.h \ $(liblumibackend_a_srcdir)/config.h diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c new file mode 100644 index 000000000..ed7ae21f0 --- /dev/null +++ b/src/backend/config_typed.c @@ -0,0 +1,145 @@ +/* + config_typed.c - Lumiera configuration highlevel interface + + 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/safeclib.h" + + +//TODO: Lumiera header includes// +#include "backend/config.h" + +//TODO: internal/static forward declarations// + + +//TODO: System includes// + +/** + * @file + * Here are the high level typed configuration interfaces defined + */ + +/** + * Number + * signed integer numbers, in different formats (decimal, hex, oct, binary(for masks)) + */ +int +lumiera_config_number_get (const char* key, long long* value, const char* def) +{ + UNIMPLEMENTED(); + return -1; +} + +int +lumiera_config_number_set (const char* key, long long* value, const char* fmt) +{ + UNIMPLEMENTED(); + return -1; +} + + +/** + * Real + * floating point number in standard formats (see printf/scanf) + */ +int +lumiera_config_real_get (const char* key, long double* value, const char* def) +{ + UNIMPLEMENTED(); + return -1; +} + +int +lumiera_config_real_set (const char* key, long double* value, const char* fmt) +{ + UNIMPLEMENTED(); + return -1; +} + + +/** + * String + * either a string which covers the whole line + * or a quoted string until the ending quote + * suggestion: + * "doublequotes" allow normal C backslash escapes + * 'singlequotes' dont allow escapes except a double '' is the ' itself + */ +int +lumiera_config_string_get (const char* key, const char** value, const char* def) +{ + UNIMPLEMENTED(); + return -1; +} + +int +lumiera_config_string_set (const char* key, const char** value, const char* fmt) +{ + UNIMPLEMENTED(); + return -1; +} + + + +/** + * Word + * A single word, no quotes, nothing + */ +int +lumiera_config_word_get (const char* key, const char** value, const char* def) +{ + UNIMPLEMENTED(); + return -1; +} + +int +lumiera_config_word_set (const char* key, const char** value, const char* fmt) +{ + UNIMPLEMENTED(); + return -1; +} + + +/** + * Bool + * Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear, localized) + */ +int +lumiera_config_bool_get (const char* key, int* value, const char* def) +{ + UNIMPLEMENTED(); + return -1; +} + +int +lumiera_config_bool_set (const char* key, int* value, const char* fmt) +{ + UNIMPLEMENTED(); + return -1; +} + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From 116c0e812593b14013611b5f49dae0312bd6c824 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 08:10:23 +0200 Subject: [PATCH 019/102] more nobug flags for config, add a rwlock for the config, init/destroy --- src/backend/config.c | 30 ++++++++++++++++++++++-------- src/backend/config.h | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 60311af72..7bc097687 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -39,22 +39,34 @@ NOBUG_DEFINE_FLAG_PARENT (config_all, backend); NOBUG_DEFINE_FLAG_PARENT (config, config_all); +NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); +NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "Syntax error in configfile"); LUMIERA_ERROR_DEFINE (CONFIG_TYPE, "Config value has wrong type"); /* singleton config */ -static LumieraConfig the_config = NULL; +static LumieraConfig lumiera_global_config = NULL; int lumiera_config_init (const char* path) { - REQUIRE (!the_config, "Configuration subsystem already initialized"); + TRACE (config); + REQUIRE (!lumiera_global_config, "Configuration subsystem already initialized"); + REQUIRE (path); + + NOBUG_INIT_FLAG (config_all); + NOBUG_INIT_FLAG (config); + NOBUG_INIT_FLAG (config_typed); + NOBUG_INIT_FLAG (config_file); + + lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); + lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); + lumiera_rwlock_init (&lumiera_global_config->lock); + RESOURCE_ANNOUNCE (config, "rwlock", "config", lumiera_global_config, lumiera_global_config->rh); - the_config = malloc (sizeof (*the_config)); - the_config->path = lumiera_strndup (path, SIZE_MAX); return 0; } @@ -62,11 +74,13 @@ lumiera_config_init (const char* path) void lumiera_config_destroy () { - if (the_config) + TRACE (config); + if (lumiera_global_config) { - lumiera_free (the_config->path); - lumiera_free (the_config); - the_config = NULL; + RESOURCE_FORGET (config, lumiera_global_config->rh); + lumiera_free (lumiera_global_config->path); + lumiera_free (lumiera_global_config); + lumiera_global_config = NULL; } else WARN (config, "Tried to destroy non initialized config subsystem"); diff --git a/src/backend/config.h b/src/backend/config.h index 89ce0caab..e41d83cf0 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -24,13 +24,22 @@ //TODO: Support library includes// #include "lib/error.h" +#include "lib/rwlock.h" //TODO: Forward declarations// struct lumiera_config_struct; +/* master config subsystem debug flag */ NOBUG_DECLARE_FLAG (config_all); +/* config subsystem internals */ NOBUG_DECLARE_FLAG (config); +/* high level typed interface operations */ +NOBUG_DECLARE_FLAG (config_typed); +/* file operations */ +NOBUG_DECLARE_FLAG (config_file); + + LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); LUMIERA_ERROR_DECLARE (CONFIG_TYPE); @@ -53,6 +62,15 @@ struct lumiera_config_struct // cuckoo hash // configfile list char* path; + /* + 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 transaction al yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair + */ + lumiera_rwlock lock; + RESOURCE_HANDLE (rh); }; typedef struct lumiera_config_struct lumiera_config; From 9a329e0340a55ef40bf1da2f47899f213120ad7b Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 11:15:23 +0200 Subject: [PATCH 020/102] basic config value retrieval, just env override, no configfiles yet --- src/backend/config.c | 41 +++++++++++++++++++++++++++++++++++++---- src/backend/config.h | 2 ++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 7bc097687..4b15c5e26 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -31,6 +31,7 @@ //TODO: System includes// #include +#include /** * @file @@ -43,11 +44,13 @@ NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "Syntax error in configfile"); +LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "Syntax error in key"); LUMIERA_ERROR_DEFINE (CONFIG_TYPE, "Config value has wrong type"); +LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "No configuration found for key"); /* singleton config */ -static LumieraConfig lumiera_global_config = NULL; +LumieraConfig lumiera_global_config = NULL; int @@ -78,6 +81,7 @@ lumiera_config_destroy () if (lumiera_global_config) { RESOURCE_FORGET (config, lumiera_global_config->rh); + lumiera_rwlock_destroy (&lumiera_global_config->lock); lumiera_free (lumiera_global_config->path); lumiera_free (lumiera_global_config); lumiera_global_config = NULL; @@ -114,10 +118,39 @@ lumiera_config_purge (const char* filename) int lumiera_config_get (const char* key, const char** value) { - UNIMPLEMENTED(); - // env var override + TRACE (config); + REQUIRE (key); + REQUIRE (value); - return -1; + int ret = -1; + + /* we translate the key for the env var override by making it uppercase and replace . and - with _, + as side effect, this also checks the key syntax */ + char* tr_key = lumiera_tmpbuf_tr (key, + "abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVQXYZ01234567_.-", + "ABCDEFGHIJKLMNOPQRSTUVQXYZABCDEFGHIJKLMNOPQRSTUVQXYZ01234567___", + NULL); + if (!tr_key) + { + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY); + } + else + { + char* env = lumiera_tmpbuf_snprintf (2048, "LUMIERA_%s", tr_key); + + *value = getenv(env); + if (*value) + { + ret = 0; + NOTICE (config, "envvar override for config %s = %s", env, *value); + } + else + { + TODO ("lookup key"); + } + } + + return ret; } diff --git a/src/backend/config.h b/src/backend/config.h index e41d83cf0..2a2b01dc7 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -42,7 +42,9 @@ NOBUG_DECLARE_FLAG (config_file); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); +LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_KEY); LUMIERA_ERROR_DECLARE (CONFIG_TYPE); +LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY); //TODO: Lumiera header includes// From 418231219a4ced7d3632066e2f1303b3e4a47dda Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 11:16:42 +0200 Subject: [PATCH 021/102] cosmetics --- src/backend/config.c | 9 ++++++++- src/backend/config_typed.c | 31 ++++++++++++++++++++----------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 4b15c5e26..0cd0e8042 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -94,6 +94,7 @@ lumiera_config_destroy () int lumiera_config_load (const char* file) { + TRACE (config); UNIMPLEMENTED(); return -1; } @@ -102,6 +103,7 @@ lumiera_config_load (const char* file) int lumiera_config_save () { + TRACE (config); UNIMPLEMENTED(); return -1; } @@ -110,6 +112,8 @@ lumiera_config_save () int lumiera_config_purge (const char* filename) { + TRACE (config); + UNIMPLEMENTED(); return -1; } @@ -157,14 +161,16 @@ lumiera_config_get (const char* key, const char** value) int lumiera_config_set (const char* key, const char* value) { + TRACE (config); UNIMPLEMENTED(); return -1; } int -lumiera_config_reset(const char* key) +lumiera_config_reset (const char* key) { + TRACE (config); UNIMPLEMENTED(); return -1; } @@ -173,6 +179,7 @@ lumiera_config_reset(const char* key) int lumiera_config_info (const char* key, const char** filename, unsigned* line) { + TRACE (config); UNIMPLEMENTED(); return -1; } diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index ed7ae21f0..4fbc0c1c4 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -33,7 +33,7 @@ /** * @file - * Here are the high level typed configuration interfaces defined + * Here are the high level typed configuration interfaces defined. */ /** @@ -50,8 +50,9 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) int lumiera_config_number_set (const char* key, long long* value, const char* fmt) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } @@ -62,15 +63,17 @@ lumiera_config_number_set (const char* key, long long* value, const char* fmt) int lumiera_config_real_get (const char* key, long double* value, const char* def) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } int lumiera_config_real_set (const char* key, long double* value, const char* fmt) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } @@ -85,15 +88,17 @@ lumiera_config_real_set (const char* key, long double* value, const char* fmt) int lumiera_config_string_get (const char* key, const char** value, const char* def) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } int lumiera_config_string_set (const char* key, const char** value, const char* fmt) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } @@ -105,34 +110,38 @@ lumiera_config_string_set (const char* key, const char** value, const char* fmt) int lumiera_config_word_get (const char* key, const char** value, const char* def) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } int lumiera_config_word_set (const char* key, const char** value, const char* fmt) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } /** * Bool - * Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear, localized) + * Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear) */ int lumiera_config_bool_get (const char* key, int* value, const char* def) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } int lumiera_config_bool_set (const char* key, int* value, const char* fmt) { + TRACE (config_typed); UNIMPLEMENTED(); - return -1; + return 0; } From 962bceec724aad50a58de396a9f8995066ce6bb4 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 11:43:06 +0200 Subject: [PATCH 022/102] high level getter for 'number' type WIP: doesn't register the default yet, no configfiles yet just returning env overrides or defaults --- src/backend/config.c | 9 +++--- src/backend/config.h | 1 + src/backend/config_typed.c | 41 +++++++++++++++++++++++-- tests/20config.tests | 60 +++++++++++++++++++++++++++++++++++-- tests/backend/test-config.c | 30 +++++++++++++++++++ 5 files changed, 133 insertions(+), 8 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 0cd0e8042..a1df1fbf7 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -43,10 +43,11 @@ NOBUG_DEFINE_FLAG_PARENT (config, config_all); NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); -LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "Syntax error in configfile"); -LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "Syntax error in key"); -LUMIERA_ERROR_DEFINE (CONFIG_TYPE, "Config value has wrong type"); -LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "No configuration found for key"); +LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile"); +LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key"); +LUMIERA_ERROR_DEFINE (CONFIG_TYPE, "value has wrong type"); +LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "no configuration entry"); +LUMIERA_ERROR_DEFINE (CONFIG_DEFAULT, "illegal default value"); /* singleton config */ diff --git a/src/backend/config.h b/src/backend/config.h index 2a2b01dc7..307601ee5 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -45,6 +45,7 @@ LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_KEY); LUMIERA_ERROR_DECLARE (CONFIG_TYPE); LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY); +LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); //TODO: Lumiera header includes// diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 4fbc0c1c4..bc5342e53 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -27,6 +27,7 @@ #include "backend/config.h" //TODO: internal/static forward declarations// +extern LumieraConfig lumiera_global_config; //TODO: System includes// @@ -43,8 +44,44 @@ int lumiera_config_number_get (const char* key, long long* value, const char* def) { - UNIMPLEMENTED(); - return -1; + TRACE (config_typed); + + int ret = -1; + + const char* raw_value = NULL; + + LUMIERA_RDLOCK_SECTION (config_typed, lumiera_global_config->rh, &lumiera_global_config->lock) + { + if (lumiera_config_get (key, &raw_value)) + { + /* not found, fall back to default */ + raw_value = def; + TODO ("register default, if given (writelock or mutex!)"); + } + + if (raw_value) + { + if (sscanf (raw_value, "%Li", value) == 1) + ret = 0; /* all ok */ + else + { + if (def && raw_value != def) + { + /* we have a 2nd chance, using the default */ + if (sscanf (def, "%Li", value) == 1) + ret = 0; /* all ok */ + else + LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); + } + else + LUMIERA_ERROR_SET (config_typed, CONFIG_TYPE); + } + } + else + LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); + } + + return ret; } int diff --git a/tests/20config.tests b/tests/20config.tests index 060334900..341c7d3ba 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -34,10 +34,66 @@ PLANNED "complex saving user file" < Date: Thu, 7 Aug 2008 13:23:07 +0200 Subject: [PATCH 023/102] fixed code to do whats specified, but needs refactoring even in case of an configuration error the returned value is primed with the default. The error condition needs still be cleared! Broken defaults would be unnoticed in case of a double error! --- src/backend/config.c | 1 + src/backend/config_typed.c | 50 +++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index a1df1fbf7..5e393e449 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -152,6 +152,7 @@ lumiera_config_get (const char* key, const char** value) else { TODO ("lookup key"); + ret = 0; /* assume that the lockup worked for now, value is still NULL, just no error set */ } } diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index bc5342e53..08db10f19 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -52,33 +52,43 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) LUMIERA_RDLOCK_SECTION (config_typed, lumiera_global_config->rh, &lumiera_global_config->lock) { - if (lumiera_config_get (key, &raw_value)) + if (!lumiera_config_get (key, &raw_value)) { - /* not found, fall back to default */ - raw_value = def; - TODO ("register default, if given (writelock or mutex!)"); - } - - if (raw_value) - { - if (sscanf (raw_value, "%Li", value) == 1) - ret = 0; /* all ok */ - else + if (raw_value) { - if (def && raw_value != def) + /* got it, scan it */ + if (sscanf (raw_value, "%Li", value) == 1) + ret = 0; /* all ok */ + else { - /* we have a 2nd chance, using the default */ - if (sscanf (def, "%Li", value) == 1) - ret = 0; /* all ok */ - else - LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); + LUMIERA_ERROR_SET (config_typed, CONFIG_TYPE); + if (def) + /* even when we return an error code we still try to initialize value with our default while in error state */ + goto try_default; + } + } + else if (def) + { + /* not found, fall back to default */ + ret = 0; /* we presume that the default is ok */ + try_default: + + if (sscanf (def, "%Li", value) == 1) + { + TODO ("register default (writelock or mutex!)"); } else - LUMIERA_ERROR_SET (config_typed, CONFIG_TYPE); + { + /* default value is broken!! */ + /* note that this error gets ignored when we had a type error above */ + ret = -1; + LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); + } } + else + /* finally, no config, no default, give up */ + LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); } - else - LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); } return ret; From eb60e711368a808c88bee7420b4454924a8b1cda Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Thu, 7 Aug 2008 14:55:17 +0200 Subject: [PATCH 024/102] few more tests for the config subsystem --- tests/20config.tests | 16 +++++++--------- tests/backend/test-config.c | 9 +++++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/20config.tests b/tests/20config.tests index 341c7d3ba..ef3d8da7d 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -34,31 +34,29 @@ PLANNED "complex saving user file" < Date: Fri, 8 Aug 2008 04:52:43 +0200 Subject: [PATCH 025/102] allow only lowercase characters, digits, '_' and '.' in keys --- src/backend/config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 5e393e449..2cc36e8e1 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -132,8 +132,8 @@ lumiera_config_get (const char* key, const char** value) /* we translate the key for the env var override by making it uppercase and replace . and - with _, as side effect, this also checks the key syntax */ char* tr_key = lumiera_tmpbuf_tr (key, - "abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVQXYZ01234567_.-", - "ABCDEFGHIJKLMNOPQRSTUVQXYZABCDEFGHIJKLMNOPQRSTUVQXYZ01234567___", + "abcdefghijklmnopqrstuvqxyz0123456789_.", + "ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789__", NULL); if (!tr_key) { From 3be0d38d73beeadcd5a9b22d0c3fd397ca782aa9 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 8 Aug 2008 08:21:38 +0200 Subject: [PATCH 026/102] report syntax error in value instead type error --- src/backend/config.c | 2 +- src/backend/config.h | 3 +-- src/backend/config_typed.c | 4 ++-- tests/20config.tests | 11 +++++++++-- tests/backend/test-config.c | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 2cc36e8e1..0331e0ec7 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -45,7 +45,7 @@ NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile"); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key"); -LUMIERA_ERROR_DEFINE (CONFIG_TYPE, "value has wrong type"); +LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_VALUE, "syntax error in value"); LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "no configuration entry"); LUMIERA_ERROR_DEFINE (CONFIG_DEFAULT, "illegal default value"); diff --git a/src/backend/config.h b/src/backend/config.h index 307601ee5..8a6aa5198 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -40,10 +40,9 @@ NOBUG_DECLARE_FLAG (config_typed); NOBUG_DECLARE_FLAG (config_file); - LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_KEY); -LUMIERA_ERROR_DECLARE (CONFIG_TYPE); +LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_VALUE); LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY); LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 08db10f19..259d2e225 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -61,7 +61,7 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) ret = 0; /* all ok */ else { - LUMIERA_ERROR_SET (config_typed, CONFIG_TYPE); + LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE); if (def) /* even when we return an error code we still try to initialize value with our default while in error state */ goto try_default; @@ -80,7 +80,7 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) else { /* default value is broken!! */ - /* note that this error gets ignored when we had a type error above */ + /* note that this error gets ignored by the application when we had a type error above, but will still be logged with nobug */ ret = -1; LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); } diff --git a/tests/20config.tests b/tests/20config.tests index ef3d8da7d..d4eebff47 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -39,18 +39,25 @@ out: 1234567890 END export LUMIERA_TEST_NUMBER_1=987654321 + TEST "number get, env override" number_get test.number.1 '1234567890 # comment' < Date: Fri, 8 Aug 2008 08:28:07 +0200 Subject: [PATCH 027/102] getting strings from the config a string can be either quoted (single or doublequoted), then the text between this quotes is returned, quotes are escaped by doubling themself, no chopping at either end is done, or not quoted then the the tabs and spaces are chopped from the value at either end. --- src/backend/config.h | 4 +- src/backend/config_typed.c | 113 ++++++++++++++++++++++++++++++++---- tests/20config.tests | 27 ++++++++- tests/backend/test-config.c | 19 ++++++ 4 files changed, 150 insertions(+), 13 deletions(-) diff --git a/src/backend/config.h b/src/backend/config.h index 8a6aa5198..29456ac02 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -85,8 +85,8 @@ typedef lumiera_config* LumieraConfig; #define LUMIERA_CONFIG_TYPES \ LUMIERA_CONFIG_TYPE(number, signed long long) \ LUMIERA_CONFIG_TYPE(real, long double) \ - LUMIERA_CONFIG_TYPE(string, const char*) \ - LUMIERA_CONFIG_TYPE(word, const char*) \ + LUMIERA_CONFIG_TYPE(string, char*) \ + LUMIERA_CONFIG_TYPE(word, char*) \ LUMIERA_CONFIG_TYPE(bool, int) diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 259d2e225..34d46f109 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -31,6 +31,7 @@ extern LumieraConfig lumiera_global_config; //TODO: System includes// +#include /** * @file @@ -124,24 +125,116 @@ lumiera_config_real_set (const char* key, long double* value, const char* fmt) } + +/** + * helper function, takes a raw input string and give a tmpbuf with the string parsed back. + */ +static char* +scan_string (const char* in) +{ + /* chop leading blanks */ + in += strspn(in, " \t"); + + char quote = *in; + char* end; + char* ret = NULL; + + if (quote == '"' || quote == '\'') + { + /* quoted string */ + ++in; + end = strchr (in, quote); + while (end && end[1] == quote) + end = strchr (end + 2, quote); + + if (end) + { + ret = lumiera_tmpbuf_strndup (in, end-in); + + /* replace double quote chars with single one */ + char* wpos; + char* rpos; + for (wpos = rpos = ret; *rpos; ++rpos, ++wpos) + { + if (*rpos == quote) + ++rpos; + *wpos = *rpos; + } + *wpos = '\0'; + } + else + /* quotes doesnt match */ + LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE); + } + else + { + /* unquoted string */ + ret = lumiera_tmpbuf_strndup (in, SIZE_MAX); + + /* chop trailing blanks */ + end = ret + strlen (ret) - 1; + while (end > ret && (*end == ' ' || *end == '\t')) + *end-- = '\0'; + } + + return ret; +} + /** * String * either a string which covers the whole line - * or a quoted string until the ending quote - * suggestion: - * "doublequotes" allow normal C backslash escapes - * 'singlequotes' dont allow escapes except a double '' is the ' itself */ int -lumiera_config_string_get (const char* key, const char** value, const char* def) +lumiera_config_string_get (const char* key, char** value, const char* def) { TRACE (config_typed); - UNIMPLEMENTED(); - return 0; + + int ret = -1; + + const char* raw_value = NULL; + + LUMIERA_RDLOCK_SECTION (config_typed, lumiera_global_config->rh, &lumiera_global_config->lock) + { + if (!lumiera_config_get (key, &raw_value)) + { + if (raw_value) + { + *value = scan_string (raw_value); + + TRACE (config_typed, "RAW_VALUE %s, scanned .%s.", raw_value, *value); + + if (*value) + ret = 0; /* all ok */ + else if (def) + goto try_default; + } + else if (def) + { + ret = 0; + try_default: + + *value = scan_string (def); + TRACE (config_typed, "DEFAULT %s, scanned .%s.", def, *value); + if (*value) + { + TODO ("register default (writelock or mutex!)"); + } + else + { + ret = -1; + LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); + } + } + else + LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); + } + } + + return ret; } int -lumiera_config_string_set (const char* key, const char** value, const char* fmt) +lumiera_config_string_set (const char* key, char** value, const char* fmt) { TRACE (config_typed); UNIMPLEMENTED(); @@ -155,7 +248,7 @@ lumiera_config_string_set (const char* key, const char** value, const char* fmt) * A single word, no quotes, nothing */ int -lumiera_config_word_get (const char* key, const char** value, const char* def) +lumiera_config_word_get (const char* key, char** value, const char* def) { TRACE (config_typed); UNIMPLEMENTED(); @@ -163,7 +256,7 @@ lumiera_config_word_get (const char* key, const char** value, const char* def) } int -lumiera_config_word_set (const char* key, const char** value, const char* fmt) +lumiera_config_word_set (const char* key, char** value, const char* fmt) { TRACE (config_typed); UNIMPLEMENTED(); diff --git a/tests/20config.tests b/tests/20config.tests index d4eebff47..c51cd6015 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -79,7 +79,32 @@ PLANNED "real set" < Date: Sat, 9 Aug 2008 16:15:29 +0200 Subject: [PATCH 028/102] Move the resource announce/forget into the rwlock init/destroy --- tests/library/test-locking.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/library/test-locking.c b/tests/library/test-locking.c index 7cceea1cc..55ea91cdb 100644 --- a/tests/library/test-locking.c +++ b/tests/library/test-locking.c @@ -151,6 +151,4 @@ TEST ("conditionforgotunlock") lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON)); } - - TESTS_END From c3c5a3b65c1ae5b9371daea9b910cac5379c9621 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 06:38:23 +0200 Subject: [PATCH 029/102] Fixup filedescriptors and filehandlecache for the new mutex handling --- src/backend/filedescriptor.c | 11 +++-------- src/backend/filehandlecache.c | 6 ++---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index 2c37a6e5e..fee877dfd 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -32,6 +32,7 @@ #include #include #include +#include NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all); @@ -205,14 +206,10 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template) self->stat = template->stat; self->flags = template->flags; - lumiera_mutex_init (&self->lock); self->refcount = 1; self->handle = 0; - const char* type = "mutex"; - const char* name = "filedescriptor"; - - RESOURCE_ANNOUNCE (filedescriptor, type, name, self, self->lock.rh); + lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (filedescriptor)); return self; } @@ -227,8 +224,6 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self) { REQUIRE (self->refcount == 0); - RESOURCE_FORGET (filedescriptor, self->lock.rh); - cuckoo_remove (registry, cuckoo_find (registry, &self)); TODO ("destruct other members (WIP)"); @@ -236,7 +231,7 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self) TODO ("release filehandle"); - lumiera_mutex_destroy (&self->lock); + lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (filedescriptor)); lumiera_free (self); } } diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c index f3eb48d7e..cf8d0a0e5 100644 --- a/src/backend/filehandlecache.c +++ b/src/backend/filehandlecache.c @@ -44,8 +44,7 @@ lumiera_filehandlecache_new (int max_entries) lumiera_mrucache_init (&lumiera_fhcache->cache, lumiera_filehandle_destroy_node); lumiera_fhcache->available = max_entries; lumiera_fhcache->checked_out = 0; - lumiera_mutex_init (&lumiera_fhcache->lock); - RESOURCE_ANNOUNCE (filehandlecache, "mutex", "filehandlecache", lumiera_fhcache, lumiera_fhcache->lock.rh); + lumiera_mutex_init (&lumiera_fhcache->lock, "filehandlecache", &NOBUG_FLAG (filehandlecache)); } @@ -55,9 +54,8 @@ lumiera_filehandlecache_delete (void) if (lumiera_fhcache) { REQUIRE (!lumiera_fhcache->checked_out, "Filehandles in use at shutdown"); - RESOURCE_FORGET (filehandlecache, lumiera_fhcache->lock.rh); lumiera_mrucache_destroy (&lumiera_fhcache->cache); - lumiera_mutex_destroy (&lumiera_fhcache->lock); + lumiera_mutex_destroy (&lumiera_fhcache->lock, &NOBUG_FLAG (filehandlecache)); lumiera_free (lumiera_fhcache); lumiera_fhcache = NULL; } From ff357349914cdaa3bfc3285a4aa54ab5cf38a780 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 06:46:31 +0200 Subject: [PATCH 030/102] Fixup config to new rwlock SECTION macros --- src/backend/config.c | 6 ++---- src/backend/config.h | 1 - src/backend/config_typed.c | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 0331e0ec7..c791b34aa 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -68,8 +68,7 @@ lumiera_config_init (const char* path) lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); - lumiera_rwlock_init (&lumiera_global_config->lock); - RESOURCE_ANNOUNCE (config, "rwlock", "config", lumiera_global_config, lumiera_global_config->rh); + lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config)); return 0; } @@ -81,8 +80,7 @@ lumiera_config_destroy () TRACE (config); if (lumiera_global_config) { - RESOURCE_FORGET (config, lumiera_global_config->rh); - lumiera_rwlock_destroy (&lumiera_global_config->lock); + lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config)); lumiera_free (lumiera_global_config->path); lumiera_free (lumiera_global_config); lumiera_global_config = NULL; diff --git a/src/backend/config.h b/src/backend/config.h index 29456ac02..38ffce9e2 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -72,7 +72,6 @@ struct lumiera_config_struct config access is not planned to be transaction al yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair */ lumiera_rwlock lock; - RESOURCE_HANDLE (rh); }; typedef struct lumiera_config_struct lumiera_config; diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 34d46f109..6ade95236 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -51,7 +51,7 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) const char* raw_value = NULL; - LUMIERA_RDLOCK_SECTION (config_typed, lumiera_global_config->rh, &lumiera_global_config->lock) + LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock) { if (!lumiera_config_get (key, &raw_value)) { @@ -193,7 +193,7 @@ lumiera_config_string_get (const char* key, char** value, const char* def) const char* raw_value = NULL; - LUMIERA_RDLOCK_SECTION (config_typed, lumiera_global_config->rh, &lumiera_global_config->lock) + LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock) { if (!lumiera_config_get (key, &raw_value)) { From 830482c46d220e1a15ce8ecd1214d4227b10c09a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 09:37:47 +0200 Subject: [PATCH 031/102] ooops, typo in the character list for config keys, missed 'wW' --- src/backend/config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index c791b34aa..1bf30b245 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -130,8 +130,8 @@ lumiera_config_get (const char* key, const char** value) /* we translate the key for the env var override by making it uppercase and replace . and - with _, as side effect, this also checks the key syntax */ char* tr_key = lumiera_tmpbuf_tr (key, - "abcdefghijklmnopqrstuvqxyz0123456789_.", - "ABCDEFGHIJKLMNOPQRSTUVQXYZ0123456789__", + "abcdefghijklmnopqrstuvwxyz0123456789_.", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__", NULL); if (!tr_key) { From cd8b523550e8c97ffcd7211cccfc84faee8e7707 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 11:51:36 +0200 Subject: [PATCH 032/102] cosmetics, remove some traces in string config parsing, little doc --- src/backend/config_typed.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 6ade95236..f6a8802f5 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -126,6 +126,14 @@ lumiera_config_real_set (const char* key, long double* value, const char* fmt) +/** + * String + * unquoted string which covers the whole value area and gets chopped or + * quoted string which preserves leading/trailing spaces + * either single or double quotes are allowed, doubling the quote in a string escapes it + */ + + /** * helper function, takes a raw input string and give a tmpbuf with the string parsed back. */ @@ -180,10 +188,6 @@ scan_string (const char* in) return ret; } -/** - * String - * either a string which covers the whole line - */ int lumiera_config_string_get (const char* key, char** value, const char* def) { @@ -201,8 +205,6 @@ lumiera_config_string_get (const char* key, char** value, const char* def) { *value = scan_string (raw_value); - TRACE (config_typed, "RAW_VALUE %s, scanned .%s.", raw_value, *value); - if (*value) ret = 0; /* all ok */ else if (def) @@ -214,7 +216,6 @@ lumiera_config_string_get (const char* key, char** value, const char* def) try_default: *value = scan_string (def); - TRACE (config_typed, "DEFAULT %s, scanned .%s.", def, *value); if (*value) { TODO ("register default (writelock or mutex!)"); From cf3c601a7779d0bd7f1f4d10ef51d16cbf55b12e Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 11:52:24 +0200 Subject: [PATCH 033/102] Config type for 'words' and some tests --- src/backend/config_typed.c | 71 ++++++++++++++++++++++++++++++++++--- tests/20config.tests | 12 +++++-- tests/backend/test-config.c | 38 ++++++++++++++++++++ 3 files changed, 115 insertions(+), 6 deletions(-) diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index f6a8802f5..a8c18ad15 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -246,14 +246,77 @@ lumiera_config_string_set (const char* key, char** value, const char* fmt) /** * Word - * A single word, no quotes, nothing + * A single word, no quotes, chopped */ + +/** + * helper function, takes a raw input string and give a tmpbuf with the word parsed back. + */ +static char* +scan_word (const char* in) +{ + /* chop leading blanks */ + in += strspn(in, " \t"); + + char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX); + char* end = ret; + + /* chop trailing blanks */ + while (*end != ' ' && *end != '\t') + ++end; + + *end++ = '\0'; + + return ret; +} + int lumiera_config_word_get (const char* key, char** value, const char* def) { - TRACE (config_typed); - UNIMPLEMENTED(); - return 0; + TRACE (config_typed, "KEY %s", key); + + int ret = -1; + + const char* raw_value = NULL; + + LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock) + { + if (!lumiera_config_get (key, &raw_value)) + { + if (raw_value) + { + *value = scan_word (raw_value); + + TRACE (config_typed, "RAW_VALUE %s, scanned .%s.", raw_value, *value); + + if (*value) + ret = 0; /* all ok */ + else if (def) + goto try_default; + } + else if (def) + { + ret = 0; + try_default: + + *value = scan_word (def); + TRACE (config_typed, "DEFAULT %s, scanned .%s.", def, *value); + if (*value) + { + TODO ("register default (writelock or mutex!)"); + } + else + { + ret = -1; + LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); + } + } + else + LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); + } + } + + return ret; } int diff --git a/tests/20config.tests b/tests/20config.tests index c51cd6015..bbcd4debd 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -106,20 +106,28 @@ LUMIERA_TEST_STRING=' "quoted string "" not ignored" #comment' TEST "string get, quoted, escaped" string_get test.string default < Date: Sun, 10 Aug 2008 17:23:52 +0200 Subject: [PATCH 034/102] remove const from the filename in struct file, some gcc version barfs on it --- src/backend/file.c | 2 +- src/backend/file.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/file.c b/src/backend/file.c index 0cf5b6a3c..9739e3a58 100644 --- a/src/backend/file.c +++ b/src/backend/file.c @@ -50,7 +50,7 @@ lumiera_file_destroy (LumieraFile self) { TRACE (file); lumiera_filedescriptor_release (self->descriptor); - lumiera_free ((void*)self->name); + lumiera_free (self->name); return self; } diff --git a/src/backend/file.h b/src/backend/file.h index bba12a167..bf5f11181 100644 --- a/src/backend/file.h +++ b/src/backend/file.h @@ -60,7 +60,7 @@ typedef lumiera_file* LumieraFile; struct lumiera_file_struct { - const char* name; + char* name; LumieraFiledescriptor descriptor; }; From 7b3fcfdcb3b54e3ba05769575152764c2cedcfef Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 19:38:31 +0200 Subject: [PATCH 035/102] Configitem brainstorm --- src/backend/configitem.h | 107 +++++++++++++++++++++++++++++++++++++++ src/backend/configline.h | 56 ++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/backend/configitem.h create mode 100644 src/backend/configline.h diff --git a/src/backend/configitem.h b/src/backend/configitem.h new file mode 100644 index 000000000..a84013060 --- /dev/null +++ b/src/backend/configitem.h @@ -0,0 +1,107 @@ +/* + configitem.h - generalized hierachy of configuration items + + 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_CONFIGITEM_H +#define LUMIERA_CONFIGITEM_H + +//TODO: Support library includes// + + +//TODO: Forward declarations// +typedef struct lumiera_configitem_struct lumiera_configitem; +typedef struct lumiera_configitem* LumieraConfigitem; + + +//TODO: Lumiera header includes// + + +//TODO: System includes// +#include + + +/** + * @file + * configitems build a 3 level hierachy: + * + * 1. file: + * contain sections + * + * 2. section: + * [prefix suffix] + * contain lines + * + * 3. lines are + * comment: + * empty line or line only containing spaces and tabs + * line starting with spaces and tabs followed by a # + * directive: + * '@include name' or '@readonly' + * directives are only valid at the toplevel section [] + * configurationentry: + * 'key = value' or 'key < redirect' + */ + +//TODO: declarations go here// +struct lumiera_configitem_struct +{ + llist link; // all lines on the same hierachy level are linked here (see childs) + LumieraConfigitem parent; // parent section + llist childs; // root node for all lines below this hierachy + + llist lookup; // all lines with the same key are stacked up on the loockup + + char* line; // raw line as read in allocated here trailing \n will be replaced with \0 + char* key; // pointer into line to start of key + size_t key_size; + char* delim; // delimiter, value starts at delim+1 +}; + +/* +brainstorm: + +identify the type of a configitem: + +file: + parent == NULL + line = filename (might be NULL for virtual files) + delim = NULL +section: + *delim == ' ' or ']' + *key != '@' +comment: + *key == NULL +directive: + *key == '@' + *delim == ' ' +configurationentry: + *delim == '=' + +*/ + + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/configline.h b/src/backend/configline.h new file mode 100644 index 000000000..91ad5f764 --- /dev/null +++ b/src/backend/configline.h @@ -0,0 +1,56 @@ +/* + configline.h - single lines from configfiles + + 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_CONFIGLINE_H +#define LUMIERA_CONFIGLINE_H + +//TODO: Support library includes// + + +//TODO: Forward declarations// + + +//TODO: Lumiera header includes// +#include "backend/configitem.h" + +//TODO: System includes// +#include + + +/** + * @file + */ + +//TODO: declarations go here// +struct lumiera_configline_struct +{ + lumiera_configitem line; +} + + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From f0cf49d7531311c0c762e77fa1c7c943cbd8b599 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 11 Aug 2008 09:20:49 +0200 Subject: [PATCH 036/102] WIP configitem brainstorming --- src/backend/{configline.h => configentry.h} | 27 ++++++++++--- src/backend/configitem.h | 44 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) rename src/backend/{configline.h => configentry.h} (67%) diff --git a/src/backend/configline.h b/src/backend/configentry.h similarity index 67% rename from src/backend/configline.h rename to src/backend/configentry.h index 91ad5f764..9af84a025 100644 --- a/src/backend/configline.h +++ b/src/backend/configentry.h @@ -1,5 +1,5 @@ /* - configline.h - single lines from configfiles + configentry.h - single entries from configfiles Copyright (C) Lumiera.org 2008, Christian Thaeter @@ -19,13 +19,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef LUMIERA_CONFIGLINE_H -#define LUMIERA_CONFIGLINE_H +#ifndef LUMIERA_CONFIGENTRY_H +#define LUMIERA_CONFIGENTRY_H //TODO: Support library includes// //TODO: Forward declarations// +typedef struct lumiera_configentry_struct lumiera_configentry; +typedef lumiera_configentry* LumieraConfigentry; //TODO: Lumiera header includes// @@ -40,10 +42,23 @@ */ //TODO: declarations go here// -struct lumiera_configline_struct +struct lumiera_configentry_struct { - lumiera_configitem line; -} + lumiera_configitem entry; +}; + +LumieraConfigentry +lumiera_configentry_init (const char* entry); + +LumieraConfigentry +lumiera_configentry_destroy (LumieraConfigentry self); + + +LumieraConfigentry +lumiera_configentry_new (const char* data); + +void +lumiera_configentry_delete (); #endif diff --git a/src/backend/configitem.h b/src/backend/configitem.h index a84013060..db87680f5 100644 --- a/src/backend/configitem.h +++ b/src/backend/configitem.h @@ -59,7 +59,45 @@ typedef struct lumiera_configitem* LumieraConfigitem; * 'key = value' or 'key < redirect' */ + //TODO: declarations go here// + +enum lumiera_configitem_type + { + LUMIERA_CONFIGFILE, + LUMIERA_CONFISECTION, + LUMIERA_CONFIGCOMMENT, + LUMIERA_CONFIGDIRECTIVE, + LUMIERA_CONFIGENTRY, + LUMIERA_CONFIGERRONEOUS + }; + +/** + * @file + * configitems build a 3 level hierachy: + * + * 1. file: + * contain sections + * + * 2. section: + * [prefix suffix] + * contain lines + * + * 3. lines are + * comment: + * empty line or line only containing spaces and tabs + * line starting with spaces and tabs followed by a # + * directive: + * '@include name' or '@readonly' + * directives are only valid at the toplevel section [] + * configurationentry: + * 'key = value' or 'key < redirect' + * errorneous: + * any line which cant be parsed + */ + + + struct lumiera_configitem_struct { llist link; // all lines on the same hierachy level are linked here (see childs) @@ -74,6 +112,12 @@ struct lumiera_configitem_struct char* delim; // delimiter, value starts at delim+1 }; +struct lumiera_configitem_vtable +{ + +}; + + /* brainstorm: From ea97119fa675911e4e54058a1eb3eece14eb848a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 11 Aug 2008 10:12:05 +0200 Subject: [PATCH 037/102] add a function to move llist nodes around --- src/lib/llist.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib/llist.h b/src/lib/llist.h index 128a3e826..3cb70f8ea 100644 --- a/src/lib/llist.h +++ b/src/lib/llist.h @@ -306,6 +306,18 @@ LLIST_FUNC (LList llist_relocate (LList self), return self->next->prev = self->prev->next = self; ); +/** + * Move a node from one memory location to another. + * @param self target of the move, must be uninitialized or empty before this move + * @param source source of the move, will be initialized to a empty list after this call + * @return self + */ +LLIST_FUNC (LList llist_move (LList self, LList source), + *self = *source; + llist_init (source); + return llist_relocate (self); +); + /** * Insert a node after another. * @param self node after which we want to insert From c7af270e4250ebb278a9d2e8ae538e161decc563 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 11 Aug 2008 12:17:03 +0200 Subject: [PATCH 038/102] config item bootstraping Mockup for review --- src/backend/configentry.h | 10 -- src/backend/configitem.c | 219 ++++++++++++++++++++++++++++++++++++++ src/backend/configitem.h | 56 +++++----- 3 files changed, 243 insertions(+), 42 deletions(-) create mode 100644 src/backend/configitem.c diff --git a/src/backend/configentry.h b/src/backend/configentry.h index 9af84a025..01d06dcb2 100644 --- a/src/backend/configentry.h +++ b/src/backend/configentry.h @@ -47,16 +47,6 @@ struct lumiera_configentry_struct lumiera_configitem entry; }; -LumieraConfigentry -lumiera_configentry_init (const char* entry); - -LumieraConfigentry -lumiera_configentry_destroy (LumieraConfigentry self); - - -LumieraConfigentry -lumiera_configentry_new (const char* data); - void lumiera_configentry_delete (); diff --git a/src/backend/configitem.c b/src/backend/configitem.c new file mode 100644 index 000000000..18e4f5a56 --- /dev/null +++ b/src/backend/configitem.c @@ -0,0 +1,219 @@ +/* + configitem.c - generalized hierachy of configuration items + + 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/llist.h" +#include "lib/safeclib.h" + + +//TODO: Lumiera header includes// +#include "backend/config.h" +#include "backend/configitem.h" +#include "backend/configentry.h" + +//TODO: internal/static forward declarations// + + +//TODO: System includes// + + +/** + * @file + * + */ + + +//code goes here// + +LumieraConfigitem +lumiera_configitem_init (LumieraConfigitem self) +{ + TRACE (config_item); + REQUIRE (self); + + llist_init (&self->link); + self->parent = NULL; + llist_init (&self->childs); + + llist_init (&self->lookup); + + self->line = NULL; + + self->key = NULL; + self->key_size = 0; + self->delim = NULL; + self->type = LUMIERA_CONFIGERRONEOUS; + + return self; +} + +LumieraConfigitem +lumiera_configitem_destroy (LumieraConfigitem self) +{ + TRACE (config_item); + REQUIRE (self); + +#if 0 + if (!llist_is_empty (&self->lookup)) + TODO ("remove from the lookup hash"); + + ENSURE (llist_is_empty (&self->childs), "TODO recursively remove childs (needs some kind of typed destructor)"); + llist_unlink (&self->link); + lumiera_free (self->line); +#endif + return self; +} + + +LumieraConfigitem +lumiera_configitem_new (const char* line) +{ + TRACE (config_item); + + /* MOCKUP */ + + // create a temporary configitem for parsing + + + lumiera_configitem tmp; + lumiera_configitem_init (&tmp); + + lumiera_configitem_parse (&tmp, line); + + FIXME ("MOCKUP only"); + + LumieraConfigitem self = NULL; + + switch (tmp.type) + { + case LUMIERA_CONFIGFILE: + + break; + + case LUMIERA_CONFIGSECTION: + break; + + case LUMIERA_CONFIGCOMMENT: + break; + + case LUMIERA_CONFIGDIRECTIVE: + break; + + case LUMIERA_CONFIGENTRY: + self = lumiera_malloc (sizeof (lumiera_configentry)); + + TODO ("call lumiera_configentry ctor"); + break; + + case LUMIERA_CONFIGERRONEOUS: + break; + } + + lumiera_configitem_move (self, &tmp); + + return self; +} + + +void +lumiera_configitem_delete (LumieraConfigitem self) +{ + TRACE (config_item); + + UNIMPLEMENTED (); +} + + + +LumieraConfigitem +lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) +{ + TRACE (config_item); + REQUIRE (self); + REQUIRE (source); + + llist_move (&self->link, &source->link); + + self->parent = source->parent; + + llist_move (&self->childs, &source->childs); + llist_move (&self->lookup, &source->lookup); + + self->line = source->line; + source->line = NULL; + + self->key = source->key; + self->key_size = source->key_size; + self->delim = source->delim; + self->type = source->type; + return self; +} + + +LumieraConfigitem +lumiera_configitem_parse (LumieraConfigitem self, const char* line) +{ + TRACE (config_item); + + FIXME ("MOCKUP only"); + + self->line = lumiera_strndup (line, SIZE_MAX); + TODO ("parsing here"); + + // MOCKUP pretrend this is an entry + self->type = LUMIERA_CONFIGENTRY; + + return self; +} + + +/* +brainstorm: + +identify the type of a configitem: + +file: + parent == NULL + line = filename (might be NULL for virtual files) + delim = NULL +section: + *delim == ' ' or ']' + *key != '@' +comment: + *key == NULL +directive: + *key == '@' + *delim == ' ' +configurationentry: + *delim == '=' + +*/ + + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/configitem.h b/src/backend/configitem.h index db87680f5..21842c22b 100644 --- a/src/backend/configitem.h +++ b/src/backend/configitem.h @@ -23,11 +23,12 @@ #define LUMIERA_CONFIGITEM_H //TODO: Support library includes// +#include "lib/llist.h" //TODO: Forward declarations// typedef struct lumiera_configitem_struct lumiera_configitem; -typedef struct lumiera_configitem* LumieraConfigitem; +typedef lumiera_configitem* LumieraConfigitem; //TODO: Lumiera header includes// @@ -65,7 +66,7 @@ typedef struct lumiera_configitem* LumieraConfigitem; enum lumiera_configitem_type { LUMIERA_CONFIGFILE, - LUMIERA_CONFISECTION, + LUMIERA_CONFIGSECTION, LUMIERA_CONFIGCOMMENT, LUMIERA_CONFIGDIRECTIVE, LUMIERA_CONFIGENTRY, @@ -100,46 +101,37 @@ enum lumiera_configitem_type struct lumiera_configitem_struct { - llist link; // all lines on the same hierachy level are linked here (see childs) - LumieraConfigitem parent; // parent section - llist childs; // root node for all lines below this hierachy + llist link; // all lines on the same hierachy level are linked here (see childs) + LumieraConfigitem parent; // parent section + llist childs; // root node for all lines below this hierachy - llist lookup; // all lines with the same key are stacked up on the loockup + llist lookup; // all lines with the same key are stacked up on the loockup - char* line; // raw line as read in allocated here trailing \n will be replaced with \0 - char* key; // pointer into line to start of key + char* line; // raw line as read in allocated here trailing \n will be replaced with \0 + char* key; // pointer into line to start of key size_t key_size; - char* delim; // delimiter, value starts at delim+1 -}; - -struct lumiera_configitem_vtable -{ - + char* delim; // delimiter, value starts at delim+1 + enum lumiera_configitem_type type; /* TODO tag by dtor instead enum */ }; -/* -brainstorm: +LumieraConfigitem +lumiera_configitem_init (LumieraConfigitem self); -identify the type of a configitem: +LumieraConfigitem +lumiera_configitem_destroy (LumieraConfigitem self); -file: - parent == NULL - line = filename (might be NULL for virtual files) - delim = NULL -section: - *delim == ' ' or ']' - *key != '@' -comment: - *key == NULL -directive: - *key == '@' - *delim == ' ' -configurationentry: - *delim == '=' +LumieraConfigitem +lumiera_configitem_new (const char* line); -*/ +void +lumiera_configitem_delete (LumieraConfigitem self); +LumieraConfigitem +lumiera_configitem_parse (LumieraConfigitem self, const char* line); + +LumieraConfigitem +lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem dest); #endif /* From c958aa29fbbd1dd061f5718f0d3bc69c49f6a73d Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 11 Aug 2008 17:22:15 +0200 Subject: [PATCH 039/102] more functional mockup of the configitem bootstrap includes some comments for simav about how to write parsers --- src/backend/configentry.c | 74 +++++++++++++++++++++ src/backend/configentry.h | 10 ++- src/backend/configitem.c | 131 ++++++++++++++++---------------------- src/backend/configitem.h | 35 ++++------ 4 files changed, 150 insertions(+), 100 deletions(-) create mode 100644 src/backend/configentry.c diff --git a/src/backend/configentry.c b/src/backend/configentry.c new file mode 100644 index 000000000..e2c846b12 --- /dev/null +++ b/src/backend/configentry.c @@ -0,0 +1,74 @@ +/* + configentry.c - single entries from configfiles + + 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/safeclib.h" + +//TODO: Lumiera header includes// +#include "backend/configentry.h" + +//TODO: internal/static forward declarations// + + +//TODO: System includes// + + +/** + * @file + * + */ + +//code goes here// +LumieraConfigitem +lumiera_configentry_new (LumieraConfigitem tmp) +{ + LumieraConfigentry self = lumiera_malloc (sizeof (*self)); + lumiera_configitem_move ((LumieraConfigitem)self, tmp); + + TODO ("initialize other stuff here (lookup, parent, ...)"); + + return (LumieraConfigitem)self; +} + + +LumieraConfigitem +lumiera_configentry_destroy (LumieraConfigitem self) +{ + TODO ("cleanup other stuff here (lookup, parent, ...)"); + + return self; +} + +struct lumiera_configitem_vtable lumiera_configentry_funcs = + { + .new = lumiera_configentry_new, + .destroy = lumiera_configentry_destroy + }; + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/configentry.h b/src/backend/configentry.h index 01d06dcb2..61f5f5f73 100644 --- a/src/backend/configentry.h +++ b/src/backend/configentry.h @@ -47,10 +47,16 @@ struct lumiera_configentry_struct lumiera_configitem entry; }; -void -lumiera_configentry_delete (); +extern struct lumiera_configitem_vtable lumiera_configentry_funcs; +LumieraConfigitem +lumiera_configentry_new (LumieraConfigitem tmp); + + +LumieraConfigitem +lumiera_configentry_destroy (LumieraConfigitem self); + #endif /* // Local Variables: diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 18e4f5a56..70c397e82 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -60,7 +60,7 @@ lumiera_configitem_init (LumieraConfigitem self) self->key = NULL; self->key_size = 0; self->delim = NULL; - self->type = LUMIERA_CONFIGERRONEOUS; + self->vtable = NULL; return self; } @@ -69,16 +69,19 @@ LumieraConfigitem lumiera_configitem_destroy (LumieraConfigitem self) { TRACE (config_item); - REQUIRE (self); -#if 0 - if (!llist_is_empty (&self->lookup)) - TODO ("remove from the lookup hash"); + if (self) + { + if (self->vtable && self->vtable->destroy) + self->vtable->destroy (self); + + ENSURE (!llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); + ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); + + llist_unlink (&self->link); + lumiera_free (self->line); + } - ENSURE (llist_is_empty (&self->childs), "TODO recursively remove childs (needs some kind of typed destructor)"); - llist_unlink (&self->link); - lumiera_free (self->line); -#endif return self; } @@ -88,46 +91,14 @@ lumiera_configitem_new (const char* line) { TRACE (config_item); - /* MOCKUP */ - - // create a temporary configitem for parsing - - lumiera_configitem tmp; lumiera_configitem_init (&tmp); lumiera_configitem_parse (&tmp, line); - FIXME ("MOCKUP only"); - - LumieraConfigitem self = NULL; - - switch (tmp.type) - { - case LUMIERA_CONFIGFILE: - - break; - - case LUMIERA_CONFIGSECTION: - break; - - case LUMIERA_CONFIGCOMMENT: - break; - - case LUMIERA_CONFIGDIRECTIVE: - break; - - case LUMIERA_CONFIGENTRY: - self = lumiera_malloc (sizeof (lumiera_configentry)); - - TODO ("call lumiera_configentry ctor"); - break; - - case LUMIERA_CONFIGERRONEOUS: - break; - } - - lumiera_configitem_move (self, &tmp); + LumieraConfigitem self = tmp.vtable && tmp.vtable->new + ? tmp.vtable->new (&tmp) + : lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp); return self; } @@ -137,8 +108,7 @@ void lumiera_configitem_delete (LumieraConfigitem self) { TRACE (config_item); - - UNIMPLEMENTED (); + lumiera_free (lumiera_configitem_destroy (self)); } @@ -163,7 +133,7 @@ lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) self->key = source->key; self->key_size = source->key_size; self->delim = source->delim; - self->type = source->type; + self->vtable = source->vtable; return self; } @@ -173,43 +143,50 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) { TRACE (config_item); - FIXME ("MOCKUP only"); - self->line = lumiera_strndup (line, SIZE_MAX); - TODO ("parsing here"); - // MOCKUP pretrend this is an entry - self->type = LUMIERA_CONFIGENTRY; + FIXME ("MOCKUP START"); + + TODO ("parsing here"); + /* + HOWTO parse (for simav) + in self->line liegt jetzt der 'rohe' string + + parsen setzt folgende werte in self: .key, .key_size, .delim und vtable. den rest macht dann die 'new' funktion aus der vtable + + es geht jetzt da drum rauszufinden ob diese zeile einses der folgenden sachen ist: + (ich zeig hier nur die grundsyntax, das parsen sollte auch entartete situationen behandeln, insbesondere leerzeichen/tabulatoren an allen moeglichen stellen) + auserdem sollt hier alles soweit wie moeglich validiert werden z.b. keys auf erlaubte zeichen gescheckt (siehe die _tr function) + + section: + '[prefix suffix]' + .key == prefix + .delim == das leerzeichen (oder tab) vor suffix oder aufs abschliessende ] wenn kein suffix + + kommentar: + leere zeile, zeile nur aus leerzeichen und tabulatoren, leerzeichen und tabulatoren gefolgt von # bis zum zeilenende + alles ausser vtable auf NULL + + direktive: + '@direktive argumente' + .key == @ + .delim == leerzeichen oder tab vor argumente, NULL wenn keine argumente + + configentry: + 'key = value' + .key == key begin + .delim == '=' + 'key < redirect' + .key == key begin + .delim == '=' + + */ + self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry return self; } -/* -brainstorm: - -identify the type of a configitem: - -file: - parent == NULL - line = filename (might be NULL for virtual files) - delim = NULL -section: - *delim == ' ' or ']' - *key != '@' -comment: - *key == NULL -directive: - *key == '@' - *delim == ' ' -configurationentry: - *delim == '=' - -*/ - - - - /* // Local Variables: // mode: C diff --git a/src/backend/configitem.h b/src/backend/configitem.h index 21842c22b..c2b0bea92 100644 --- a/src/backend/configitem.h +++ b/src/backend/configitem.h @@ -30,6 +30,7 @@ typedef struct lumiera_configitem_struct lumiera_configitem; typedef lumiera_configitem* LumieraConfigitem; +struct lumiera_configitem_vtable; //TODO: Lumiera header includes// @@ -62,17 +63,6 @@ typedef lumiera_configitem* LumieraConfigitem; //TODO: declarations go here// - -enum lumiera_configitem_type - { - LUMIERA_CONFIGFILE, - LUMIERA_CONFIGSECTION, - LUMIERA_CONFIGCOMMENT, - LUMIERA_CONFIGDIRECTIVE, - LUMIERA_CONFIGENTRY, - LUMIERA_CONFIGERRONEOUS - }; - /** * @file * configitems build a 3 level hierachy: @@ -97,24 +87,27 @@ enum lumiera_configitem_type * any line which cant be parsed */ - +struct lumiera_configitem_vtable +{ + LumieraConfigitem (*new)(LumieraConfigitem); + LumieraConfigitem (*destroy)(LumieraConfigitem); +}; struct lumiera_configitem_struct { - llist link; // all lines on the same hierachy level are linked here (see childs) - LumieraConfigitem parent; // parent section - llist childs; // root node for all lines below this hierachy + llist link; // all lines on the same hierachy level are linked here (see childs) + LumieraConfigitem parent; // parent section + llist childs; // root node for all lines below this hierachy - llist lookup; // all lines with the same key are stacked up on the loockup + llist lookup; // all lines with the same key are stacked up on the loockup - char* line; // raw line as read in allocated here trailing \n will be replaced with \0 - char* key; // pointer into line to start of key + char* line; // raw line as read in allocated here trailing \n will be replaced with \0 + char* key; // pointer into line to start of key size_t key_size; - char* delim; // delimiter, value starts at delim+1 - enum lumiera_configitem_type type; /* TODO tag by dtor instead enum */ + char* delim; // delimiter, value starts at delim+1 + struct lumiera_configitem_vtable* vtable; // functiontable for subclassing }; - LumieraConfigitem lumiera_configitem_init (LumieraConfigitem self); From fd563a02848477f6b939723a14ff6ceea9655164 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Mon, 11 Aug 2008 22:08:17 +0200 Subject: [PATCH 040/102] WIP: started low-level parser --- src/backend/configitem.c | 79 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 70c397e82..0907c63e9 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -3,6 +3,7 @@ Copyright (C) Lumiera.org 2008, Christian Thaeter + Simeon Voelkel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -178,9 +179,85 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) .delim == '=' 'key < redirect' .key == key begin - .delim == '=' + .delim == '>' */ + /* + * What should be working (for cehteh) or not yet.. + * + * die Elemente sollten bereits richtig unterschieden werden, die {} sind noch zu füllen. + * + * TODO: include für verwendete Funkionen wie strlen und isspace + * + * */ + + int linelength = strlen(self->line); + int pos = 0; + + char* tmp1 = self->line; + + /*skip leading whitespaces*/ + while ( isspace(tmp1[0]) && pos < linelength ) + { + tmp1++; + pos++: + } + + /*decide what this line represents*/ + if ( tmp1[0] == '\0' || pos == linelenght ) + { + /*this was an empty line*/ + } + else + if ( tmp1[0] == '#' ) + { + /*this was a comment*/ + } + else + if ( tmp1[0] == '@' ) + { + /*this was a directive*/ + } + else + if ( tmp1[0] == '[' ) + { + /*this was a section*/ + } + else + { + /*this was a configentry*/ + + /*tmp1 points now to the first not-whitespace-character*/ + self->key = tmp1; + + /*now look for the end of the key and set the keysize*/ + self->keysize = 0; + + while ( ! isspace(tmp1[0]) && pos < linelength ) + { + tmp1++; + self->keysize++; + pos++; + } + + if ( tmp1[0] == '\0' || pos == linelength ) + { + /*error: line ended with end of the key*/ + } + else + { + /*skip the following whitespaces until we reach the delimeter*/ + while ( isspace(tmp1[0]) && pos < linelength ) + { + tmp1++; + pos++; + } + /*TODO: keep on parsing... ;^)*/ + } + + } + + self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry return self; From 9c7cedbf75bd0f916d1abf4a5c095e03e7ce131d Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 07:13:45 +0200 Subject: [PATCH 041/102] fix to make parser mockup compileable, little simplified --- src/backend/configitem.c | 75 ++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 0907c63e9..8462cfc4d 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -34,7 +34,7 @@ //TODO: System includes// - +#include /** * @file @@ -191,74 +191,59 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) * * */ - int linelength = strlen(self->line); - int pos = 0; - - char* tmp1 = self->line; + char* itr = self->line; /*skip leading whitespaces*/ - while ( isspace(tmp1[0]) && pos < linelength ) - { - tmp1++; - pos++: - } + while (*itr && isspace (*itr)) + itr++; /*decide what this line represents*/ - if ( tmp1[0] == '\0' || pos == linelenght ) + if (!*itr || *itr == '#' ) { - /*this was an empty line*/ + /*this is an empty line or a a comment*/ } - else - if ( tmp1[0] == '#' ) + else if (*itr == '@' ) { - /*this was a comment*/ + /*this is a directive*/ } - else - if ( tmp1[0] == '@' ) + else if (*itr == '[' ) { - /*this was a directive*/ - } - else - if ( tmp1[0] == '[' ) - { - /*this was a section*/ + /*this is a section*/ } else { - /*this was a configentry*/ - - /*tmp1 points now to the first not-whitespace-character*/ - self->key = tmp1; + /*this is a probably configentry*/ + + /*itr points now to the first not-whitespace-character*/ + self->key = itr; /*now look for the end of the key and set the keysize*/ - self->keysize = 0; + self->key_size = strspn (itr, "abcdefghijklmnopqrstuvwxyz0123456789_."); - while ( ! isspace(tmp1[0]) && pos < linelength ) - { - tmp1++; - self->keysize++; - pos++; - } + TODO ("if(self->keysize==0) then key_syntax_error"); - if ( tmp1[0] == '\0' || pos == linelength ) + /* skip blanks */ + itr += self->key_size; + while (*itr && isspace(*itr)) + itr++; + + if (*itr == '=') { - /*error: line ended with end of the key*/ + self->delim = itr; } - else + else if (*itr == '<') { - /*skip the following whitespaces until we reach the delimeter*/ - while ( isspace(tmp1[0]) && pos < linelength ) - { - tmp1++; - pos++; - } - /*TODO: keep on parsing... ;^)*/ + self->delim = itr; } + else + TODO ("syntax error"); + + /* TODO only if still everything ok */ + self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry } - self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry return self; } From 20d38b0b5ce909411566ac9372650f8907273c60 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 08:12:08 +0200 Subject: [PATCH 042/102] give the charsets for config keys some constants --- src/backend/config.c | 6 +++--- src/backend/config.h | 2 ++ src/backend/configitem.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 1bf30b245..db8d929a7 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -127,11 +127,11 @@ lumiera_config_get (const char* key, const char** value) int ret = -1; - /* we translate the key for the env var override by making it uppercase and replace . and - with _, + /* we translate the key for the env var override by making it uppercase and replace . with _, as side effect, this also checks the key syntax */ char* tr_key = lumiera_tmpbuf_tr (key, - "abcdefghijklmnopqrstuvwxyz0123456789_.", - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__", + LUMIERA_CONFIG_KEY_CHARS, + LUMIERA_CONFIG_ENV_CHARS, NULL); if (!tr_key) { diff --git a/src/backend/config.h b/src/backend/config.h index 38ffce9e2..27d14980b 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -58,6 +58,8 @@ LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader */ +#define LUMIERA_CONFIG_KEY_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_." +#define LUMIERA_CONFIG_ENV_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__" struct lumiera_config_struct { diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 8462cfc4d..a715ca99b 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -218,7 +218,7 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) self->key = itr; /*now look for the end of the key and set the keysize*/ - self->key_size = strspn (itr, "abcdefghijklmnopqrstuvwxyz0123456789_."); + self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); TODO ("if(self->keysize==0) then key_syntax_error"); From 8e5b734f0392e1adec5b76692bb56160a41133da Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 08:13:15 +0200 Subject: [PATCH 043/102] add configitem and configentry to the build system --- src/backend/Makefile.am | 8 ++++++-- src/backend/config.c | 2 ++ src/backend/config.h | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 34d48c9ed..afe7cc1f3 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -29,7 +29,9 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/filedescriptor.c \ $(liblumibackend_a_srcdir)/filehandlecache.c \ $(liblumibackend_a_srcdir)/config.c \ - $(liblumibackend_a_srcdir)/config_typed.c + $(liblumibackend_a_srcdir)/config_typed.c \ + $(liblumibackend_a_srcdir)/configentry.c \ + $(liblumibackend_a_srcdir)/configitem.c noinst_HEADERS += \ @@ -39,5 +41,7 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ $(liblumibackend_a_srcdir)/filehandlecache.h \ - $(liblumibackend_a_srcdir)/config.h + $(liblumibackend_a_srcdir)/config.h \ + $(liblumibackend_a_srcdir)/configentry.h \ + $(liblumibackend_a_srcdir)/configitem.h diff --git a/src/backend/config.c b/src/backend/config.c index db8d929a7..deec72697 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -42,6 +42,7 @@ NOBUG_DEFINE_FLAG_PARENT (config_all, backend); NOBUG_DEFINE_FLAG_PARENT (config, config_all); NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); +NOBUG_DEFINE_FLAG_PARENT (config_item, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile"); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key"); @@ -65,6 +66,7 @@ lumiera_config_init (const char* path) NOBUG_INIT_FLAG (config); NOBUG_INIT_FLAG (config_typed); NOBUG_INIT_FLAG (config_file); + NOBUG_INIT_FLAG (config_item); lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); diff --git a/src/backend/config.h b/src/backend/config.h index 27d14980b..1daf54087 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -38,6 +38,8 @@ NOBUG_DECLARE_FLAG (config); NOBUG_DECLARE_FLAG (config_typed); /* file operations */ NOBUG_DECLARE_FLAG (config_file); +/* single config items */ +NOBUG_DECLARE_FLAG (config_item); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); From 0f5c5e218a19d344e4ead842e3a68bf2668d7609 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Tue, 12 Aug 2008 10:03:38 +0200 Subject: [PATCH 044/102] typo fix and redundant comment removal --- src/backend/config_typed.c | 2 +- src/backend/configitem.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index a8c18ad15..78f2e8cd7 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -157,7 +157,7 @@ scan_string (const char* in) if (end) { - ret = lumiera_tmpbuf_strndup (in, end-in); + ret = lumiera_tmpbuf_strndup (in, end - in); /* replace double quote chars with single one */ char* wpos; diff --git a/src/backend/configitem.c b/src/backend/configitem.c index a715ca99b..bf413e7e5 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -187,8 +187,6 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) * * die Elemente sollten bereits richtig unterschieden werden, die {} sind noch zu füllen. * - * TODO: include für verwendete Funkionen wie strlen und isspace - * * */ char* itr = self->line; @@ -212,7 +210,7 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) } else { - /*this is a probably configentry*/ + /*this is probably a configentry*/ /*itr points now to the first not-whitespace-character*/ self->key = itr; From ca58edf39cc8370c7df358d423813fa55688f913 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Tue, 12 Aug 2008 10:29:05 +0200 Subject: [PATCH 045/102] added CONFIG_SYNTAX errors --- src/backend/configitem.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index bf413e7e5..075304c37 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -190,6 +190,7 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) * */ char* itr = self->line; + bool faultless = true; /*skip leading whitespaces*/ while (*itr && isspace (*itr)) @@ -199,6 +200,9 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) if (!*itr || *itr == '#' ) { /*this is an empty line or a a comment*/ + self->key = NULL; + self->keysize = 0; + self->delim = NULL; } else if (*itr == '@' ) { @@ -218,7 +222,17 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) /*now look for the end of the key and set the keysize*/ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); - TODO ("if(self->keysize==0) then key_syntax_error"); + if ( self->keysize==0 ) + { + /*Obviously a malformed "key"; treat this line like a comment*/ + self->key = NULL; + self->keysize = 0; + self->delim = NULL; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + + faultless = false; + } /* skip blanks */ itr += self->key_size; @@ -234,10 +248,21 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) self->delim = itr; } else - TODO ("syntax error"); + { + /*this is not a valid configentry; treat this line like a comment*/ + self->key = NULL; + self->keysize = 0; + self->delim = NULL; - /* TODO only if still everything ok */ - self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + faultless = false; + } + + /*just set vtable if we are sure we had no syntax-error*/ + if (faultless) + { + self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry + } } From e86ef0ba751283125e7080ced3cad0d2f2568ff3 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Tue, 12 Aug 2008 10:57:46 +0200 Subject: [PATCH 046/102] parser improvements, compiles now --- src/backend/configitem.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 075304c37..1148b3486 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -35,6 +35,7 @@ //TODO: System includes// #include +#include /** * @file @@ -190,7 +191,6 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) * */ char* itr = self->line; - bool faultless = true; /*skip leading whitespaces*/ while (*itr && isspace (*itr)) @@ -200,9 +200,6 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) if (!*itr || *itr == '#' ) { /*this is an empty line or a a comment*/ - self->key = NULL; - self->keysize = 0; - self->delim = NULL; } else if (*itr == '@' ) { @@ -222,47 +219,32 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) /*now look for the end of the key and set the keysize*/ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); - if ( self->keysize==0 ) - { - /*Obviously a malformed "key"; treat this line like a comment*/ - self->key = NULL; - self->keysize = 0; - self->delim = NULL; - - LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); - - faultless = false; - } - /* skip blanks */ itr += self->key_size; while (*itr && isspace(*itr)) itr++; - if (*itr == '=') + if (self->key_size && *itr == '=') { + /*this configentry assigns a value to a key*/ self->delim = itr; + self->vtable = &lumiera_configentry_funcs; } - else if (*itr == '<') + else if (self->key_size && *itr == '<') { + /*this configentry is a redirect*/ self->delim = itr; + self->vtable = &lumiera_configentry_funcs; } else { /*this is not a valid configentry; treat this line like a comment*/ self->key = NULL; - self->keysize = 0; - self->delim = NULL; + self->key_size = 0; LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); - faultless = false; } - /*just set vtable if we are sure we had no syntax-error*/ - if (faultless) - { - self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry - } } From 19c2af0c6928b97a2b9f88958ff846e2a087cd84 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Tue, 12 Aug 2008 12:39:48 +0200 Subject: [PATCH 047/102] added section part to parser --- src/backend/configitem.c | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 1148b3486..a64995aeb 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -208,6 +208,70 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) else if (*itr == '[' ) { /*this is a section*/ + + /*skip blanks before prefix*/ + while (*itr && isspace(*itr)) + itr++; + + /*itr points now to the begin of the key*/ + self->key = itr; + + /*now look for the end of the key and set the keysize*/ + self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); + + itr += self->key_size; + + /*if the line ends ends with prefix] delim points to ] + * and not the last (blank) character before the final square bracket*/ + if (self->key_size && *itr && *itr == ']') + { + self->delim = itr; + TODO("self->vtable = &lumiera_configsection_funcs;"); + } + else if (self->key_size && *itr && isspace(*itr)) + { + /* skip blanks until we reach the suffix or the final square bracket*/ + while (*itr && isspace(*itr)) + itr++; + + if (*itr && *itr == ']') + { + /*final square bracket reached, so place delim one char before the + * actual position which must be a whitespace: no extra check necessary*/ + self->delim = itr - 1; + TODO("self->vtable = &lumiera_configsection_funcs;"); + } + else if (*itr) + { + TODO("check wheter suffix is made of legal characters"); + + /*delim points to the last whitespace before the actual position; + * no extra check needed*/ + self->delim = itr - 1; + TODO("self->vtable = &lumiera_configsection_funcs;"); + } + else + { + /*malformed section line, treat this line like a comment*/ + self->key = NULL; + self->key_size = 0; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + + } + } + else + { + /*error: either *itr is false, points neither to a blank nor to a closed square + * bracket or the key_size is zero*/ + + /*treat this line like a comment*/ + self->key = NULL; + self->key_size = 0; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + + } } else { From b5dafbcd53465707b5e9d347dcf3ceb3907f21d7 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Wed, 13 Aug 2008 08:33:49 +0200 Subject: [PATCH 048/102] Fix for section-parser --- src/backend/configitem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index a64995aeb..7e52f269e 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -210,6 +210,7 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) /*this is a section*/ /*skip blanks before prefix*/ + itr++; while (*itr && isspace(*itr)) itr++; From bd2cc4a026359b1999ef3e651e69ed7f9b81a4f0 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Wed, 13 Aug 2008 08:34:44 +0200 Subject: [PATCH 049/102] Typo fix --- tests/library/test-llist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/library/test-llist.c b/tests/library/test-llist.c index 66bfa614d..c352edbf2 100644 --- a/tests/library/test-llist.c +++ b/tests/library/test-llist.c @@ -1,5 +1,5 @@ /* - test-llist.c - test the linked lis lib + test-llist.c - test the linked list lib Copyright (C) Lumiera.org 2008, Christian Thaeter From a8a186bb936c69d47e477ad2b41b6e4f05edd30b Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Wed, 13 Aug 2008 08:35:31 +0200 Subject: [PATCH 050/102] Added two very simple tests for configitem --- tests/20config.tests | 5 +++++ tests/backend/test-config.c | 24 +++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/20config.tests b/tests/20config.tests index bbcd4debd..65dfb5404 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -135,3 +135,8 @@ END PLANNED "bool set" < + Simeon Voelkel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -21,6 +22,7 @@ #include "lib/safeclib.h" #include "backend/config.h" +#include "backend/configitem.h" #include "tests/test.h" @@ -125,5 +127,25 @@ TEST ("word_get") lumiera_config_destroy (); } +TEST ("empty_line_configitem") +{ + LumieraConfigitem item; + + item = lumiera_configitem_new ( "" ); + + lumiera_configitem_delete(item); + item = NULL; +} + +TEST ("blank_line_configitem") +{ + LumieraConfigitem item; + + item = lumiera_configitem_new ( " " ); + + lumiera_configitem_delete(item); + item = NULL; +} + TESTS_END From 975150fe0afb481e5f991f32b45ecebe2d9cffff Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 11:38:56 +0200 Subject: [PATCH 051/102] Cuckoo hash update * add a destructor function for elements * rename cuckoo_free to cuckoo_delete to be consistent with the rest --- src/lib/cuckoo.c | 29 +++++++++++++++++++++++++---- src/lib/cuckoo.h | 18 +++++++++++++++--- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/lib/cuckoo.c b/src/lib/cuckoo.c index bbcb0e71a..04bf4a31c 100644 --- a/src/lib/cuckoo.c +++ b/src/lib/cuckoo.c @@ -52,6 +52,8 @@ struct cuckoo_struct enum compact_state autocompact; size_t elements; + + cuckoo_dtorfunc dtor; }; @@ -68,7 +70,8 @@ cuckoo_init (Cuckoo self, cuckoo_hashfunc h3, cuckoo_cmpfunc cmp, size_t itemsize, - unsigned startsize) + unsigned startsize, + cuckoo_dtorfunc dtor) { if (!self) return NULL; @@ -101,6 +104,8 @@ cuckoo_init (Cuckoo self, self->autocompact = COMPACTING_AUTO; self->elements = 0; + + self->dtor = dtor; return self; } @@ -110,10 +115,11 @@ cuckoo_new (cuckoo_hashfunc h1, cuckoo_hashfunc h3, cuckoo_cmpfunc cmp, size_t itemsize, - unsigned startsize) + unsigned startsize, + cuckoo_dtorfunc dtor) { Cuckoo self = malloc (sizeof (struct cuckoo_struct)); - if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize)) + if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize, dtor)) { free (self); return NULL; @@ -126,6 +132,18 @@ cuckoo_destroy (Cuckoo self) { if (self) { + + if (self->dtor) + { + void* elem; + for (elem = self->t1; elem < self->t1 + self->size * 4; elem += self->size) + self->dtor (elem); + for (elem = self->t2; elem < self->t1 + self->size * 2; elem += self->size) + self->dtor (elem); + for (elem = self->t3; elem < self->t1 + self->size; elem += self->size) + self->dtor (elem); + } + free (self->t1); free (self->t2); free (self->t3); @@ -135,7 +153,7 @@ cuckoo_destroy (Cuckoo self) void -cuckoo_free (Cuckoo self) +cuckoo_delete (Cuckoo self) { free (cuckoo_destroy (self)); } @@ -486,6 +504,9 @@ cuckoo_remove (Cuckoo self, void* item) { if (item) { + if (self->dtor) + self->dtor (item); + memset (item, 0, self->itemsize); --self->elements; diff --git a/src/lib/cuckoo.h b/src/lib/cuckoo.h index 323b5cc75..ed14f6cc8 100644 --- a/src/lib/cuckoo.h +++ b/src/lib/cuckoo.h @@ -54,6 +54,14 @@ typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r); */ typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2); +/** + * Item destructor function. + * User supplied destructor function. This function is called when items are removed + * from the hash or at hash detroy/delete time. Must be safe to be called on a zeroed element. + * @param item address of the item to be destroyed + */ +typedef void (*cuckoo_dtorfunc)(void* item); + /** * Initialize a cuckoo hash. * @param self pointer to a uninitialized cuckoo datastructure @@ -62,6 +70,7 @@ typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2); * @param h3 hash function for the third table * @param cmp function which compares two keys * @param startsize initial size of table t3, as 2's exponent + * @param dtor a function used to clean up hash entries, might be NULL if nothing required * @return The initialized hashtable or NULL at allocation failure */ Cuckoo @@ -71,7 +80,8 @@ cuckoo_init (Cuckoo self, cuckoo_hashfunc h3, cuckoo_cmpfunc cmp, size_t itemsize, - unsigned startsize); + unsigned startsize, + cuckoo_dtorfunc dtor); /** * Allocate a new cuckoo hash. @@ -80,6 +90,7 @@ cuckoo_init (Cuckoo self, * @param h3 hash function for the third table * @param cmp function which compares two keys * @param startsize initial size of table t3, as 2's exponent + * @param dtor a function used to clean up hash entries, might be NULL if nothing required * @return The initialized hashtable or NULL at allocation failure */ Cuckoo @@ -88,7 +99,8 @@ cuckoo_new (cuckoo_hashfunc h1, cuckoo_hashfunc h3, cuckoo_cmpfunc cmp, size_t itemsize, - unsigned startsize); + unsigned startsize, + cuckoo_dtorfunc dtor); /** * Destroy a cuckoo hash. @@ -104,7 +116,7 @@ cuckoo_destroy (Cuckoo self); * @param self handle of the hash table to be freed */ void -cuckoo_free (Cuckoo self); +cuckoo_delete (Cuckoo self); /** * Get the number of elements stored in a hash. From e78908bc7d276c5757b0dfb87d0a91631bb95abf Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 11:39:35 +0200 Subject: [PATCH 052/102] fixes after the cuckoo update in filedescriptor.c --- src/backend/filedescriptor.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index fee877dfd..a4165b58b 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -89,9 +89,7 @@ lumiera_filedescriptor_registry_init (void) TRACE (filedescriptor); REQUIRE (!registry); - registry = cuckoo_new (h1, h2, h3, cmp, - sizeof (LumieraFiledescriptor), - 3); + registry = cuckoo_new (h1, h2, h3, cmp, sizeof (LumieraFiledescriptor), 3, NULL); if (!registry) LUMIERA_DIE (NO_MEMORY); @@ -108,7 +106,7 @@ lumiera_filedescriptor_registry_destroy (void) RESOURCE_FORGET (filedescriptor, registry_mutex.rh); if (registry) - cuckoo_free (registry); + cuckoo_delete (registry); registry = NULL; } From 76a72a6b68043a409361b58afb286ae6bdaef7a0 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 20:57:08 +0200 Subject: [PATCH 053/102] add a custom copy function to the cuckoo hash --- src/lib/cuckoo.c | 95 ++++++++++++++++++++++++++---------------------- src/lib/cuckoo.h | 19 ++++++++-- 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/lib/cuckoo.c b/src/lib/cuckoo.c index 04bf4a31c..3b03ec0ef 100644 --- a/src/lib/cuckoo.c +++ b/src/lib/cuckoo.c @@ -23,6 +23,8 @@ #include +#define CUCKOO_GRANULARITY int + enum compact_state { COMPACTING_OFF, @@ -54,6 +56,7 @@ struct cuckoo_struct size_t elements; cuckoo_dtorfunc dtor; + cuckoo_cpyfunc cpy; }; @@ -63,6 +66,28 @@ static inline uint32_t cuckoo_fast_prng () return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1); } +static inline int +iszero (void* mem, size_t size) +{ + while (size && !*(CUCKOO_GRANULARITY*)mem) + { + size -= sizeof (CUCKOO_GRANULARITY); + mem += sizeof (CUCKOO_GRANULARITY); + } + return !size; +} + +static inline void +xmemcpy (void* dst, const void* src, size_t size) +{ + while (size) + { + size -= sizeof (CUCKOO_GRANULARITY); + *(CUCKOO_GRANULARITY*)(dst + size) = *(CUCKOO_GRANULARITY*)(src + size); + } +} + + Cuckoo cuckoo_init (Cuckoo self, cuckoo_hashfunc h1, @@ -71,13 +96,15 @@ cuckoo_init (Cuckoo self, cuckoo_cmpfunc cmp, size_t itemsize, unsigned startsize, - cuckoo_dtorfunc dtor) + cuckoo_dtorfunc dtor, + cuckoo_cpyfunc cpy) { if (!self) return NULL; self->size = 1<itemsize = itemsize; + self->itemsize = (itemsize * sizeof (CUCKOO_GRANULARITY) + + sizeof (CUCKOO_GRANULARITY) - 1) / sizeof (CUCKOO_GRANULARITY); /* round up to next CUCKOO_GRANULARITY boundary */ self->h1 = h1; self->r1 = cuckoo_fast_prng (); self->h2 = h2; @@ -106,6 +133,7 @@ cuckoo_init (Cuckoo self, self->elements = 0; self->dtor = dtor; + self->cpy = cpy ? cpy : xmemcpy; return self; } @@ -116,10 +144,11 @@ cuckoo_new (cuckoo_hashfunc h1, cuckoo_cmpfunc cmp, size_t itemsize, unsigned startsize, - cuckoo_dtorfunc dtor) + cuckoo_dtorfunc dtor, + cuckoo_cpyfunc cpy) { Cuckoo self = malloc (sizeof (struct cuckoo_struct)); - if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize, dtor)) + if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize, dtor, cpy)) { free (self); return NULL; @@ -159,28 +188,6 @@ cuckoo_delete (Cuckoo self) } -static inline int -iszero (void* mem, size_t size) -{ - while (size && !*(int*)mem) - { - size -= sizeof (int); - mem += sizeof (int); - } - return !size; -} - -static inline void -xmemcpy (void* dst, void* src, size_t size) -{ - while (size) - { - size -= sizeof (int); - *(int*)(dst + size) = *(int*)(src + size); - } -} - - static int cuckoo_insert_internal_ (Cuckoo self, void* item) { @@ -192,9 +199,9 @@ cuckoo_insert_internal_ (Cuckoo self, void* item) /* find nest */ pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size)); /* kick old egg out */ - xmemcpy (tmp, pos, self->itemsize); + self->cpy (tmp, pos, self->itemsize); /* lay egg */ - xmemcpy (pos, item, self->itemsize); + self->cpy (pos, item, self->itemsize); if (iszero (tmp, self->itemsize)) return 1; @@ -202,9 +209,9 @@ cuckoo_insert_internal_ (Cuckoo self, void* item) /* find nest */ pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size)); /* kick old egg out */ - xmemcpy (item, pos, self->itemsize); + self->cpy (item, pos, self->itemsize); /* lay egg */ - xmemcpy (pos, tmp, self->itemsize); + self->cpy (pos, tmp, self->itemsize); if (iszero (item, self->itemsize)) return 1; @@ -212,15 +219,15 @@ cuckoo_insert_internal_ (Cuckoo self, void* item) /* find nest */ pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size); /* kick old egg out */ - xmemcpy (tmp, pos, self->itemsize); + self->cpy (tmp, pos, self->itemsize); /* lay egg */ - xmemcpy (pos, item, self->itemsize); + self->cpy (pos, item, self->itemsize); if (iszero (tmp, self->itemsize)) return 1; /* copy tmp to item, which will be reinserted on next interation / after rehashing */ - xmemcpy (item, tmp, self->itemsize); + self->cpy (item, tmp, self->itemsize); } return 0; } @@ -253,9 +260,9 @@ cuckoo_rehash (Cuckoo self) { char t[self->itemsize]; void* hpos = self->t1 + self->itemsize * hash; - xmemcpy (t, hpos, self->itemsize); - xmemcpy (hpos, pos, self->itemsize); - xmemcpy (pos, t, self->itemsize); + self->cpy (t, hpos, self->itemsize); + self->cpy (hpos, pos, self->itemsize); + self->cpy (pos, t, self->itemsize); if (iszero (t, self->itemsize)) break; } @@ -283,9 +290,9 @@ cuckoo_rehash (Cuckoo self) { char t[self->itemsize]; void* hpos = self->t2 + self->itemsize * hash; - xmemcpy (t, hpos, self->itemsize); - xmemcpy (hpos, pos, self->itemsize); - xmemcpy (pos, t, self->itemsize); + self->cpy (t, hpos, self->itemsize); + self->cpy (hpos, pos, self->itemsize); + self->cpy (pos, t, self->itemsize); if (iszero (t, self->itemsize)) break; } @@ -313,9 +320,9 @@ cuckoo_rehash (Cuckoo self) { char t[self->itemsize]; void* hpos = self->t3 + self->itemsize * hash; - xmemcpy (t, hpos, self->itemsize); - xmemcpy (hpos, pos, self->itemsize); - xmemcpy (pos, t, self->itemsize); + self->cpy (t, hpos, self->itemsize); + self->cpy (hpos, pos, self->itemsize); + self->cpy (pos, t, self->itemsize); if (iszero (t, self->itemsize)) break; } @@ -451,11 +458,11 @@ cuckoo_insert (Cuckoo self, void* item) void* found; if ((found = cuckoo_find (self, item))) { - xmemcpy (found, item, self->itemsize); + self->cpy (found, item, self->itemsize); return 1; } - xmemcpy (tmp, item, self->itemsize); + self->cpy (tmp, item, self->itemsize); for (unsigned n = 6; n; --n) /* rehash/grow loop */ { diff --git a/src/lib/cuckoo.h b/src/lib/cuckoo.h index ed14f6cc8..1576c8e41 100644 --- a/src/lib/cuckoo.h +++ b/src/lib/cuckoo.h @@ -62,6 +62,15 @@ typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2); */ typedef void (*cuckoo_dtorfunc)(void* item); +/** + * Copy function. + * User supplied item copy function + * @param dest target address for the copy operation + * @param src source for the copy operation + * @param size size of a item (requested size rounded up to the next CUCKOO_GRANULARITY) + */ +typedef void (*cuckoo_cpyfunc)(void* dest, const void* src, size_t size); + /** * Initialize a cuckoo hash. * @param self pointer to a uninitialized cuckoo datastructure @@ -70,7 +79,8 @@ typedef void (*cuckoo_dtorfunc)(void* item); * @param h3 hash function for the third table * @param cmp function which compares two keys * @param startsize initial size of table t3, as 2's exponent - * @param dtor a function used to clean up hash entries, might be NULL if nothing required + * @param dtor function used to clean up hash entries, might be NULL if nothing required + * @param cpy function used to copy hash entries, when NULL is given memcpy wil be used * @return The initialized hashtable or NULL at allocation failure */ Cuckoo @@ -81,7 +91,8 @@ cuckoo_init (Cuckoo self, cuckoo_cmpfunc cmp, size_t itemsize, unsigned startsize, - cuckoo_dtorfunc dtor); + cuckoo_dtorfunc dtor, + cuckoo_cpyfunc cpy); /** * Allocate a new cuckoo hash. @@ -100,7 +111,9 @@ cuckoo_new (cuckoo_hashfunc h1, cuckoo_cmpfunc cmp, size_t itemsize, unsigned startsize, - cuckoo_dtorfunc dtor); + cuckoo_dtorfunc dtor, + cuckoo_cpyfunc cpy); + /** * Destroy a cuckoo hash. From 0fe3d6a059e78822245fd3f84b0457b2cf8206d4 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 20:57:59 +0200 Subject: [PATCH 054/102] filedescriptor fixup for new copy func in cuckoo --- src/backend/filedescriptor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index a4165b58b..6c398dd6c 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -89,7 +89,7 @@ lumiera_filedescriptor_registry_init (void) TRACE (filedescriptor); REQUIRE (!registry); - registry = cuckoo_new (h1, h2, h3, cmp, sizeof (LumieraFiledescriptor), 3, NULL); + registry = cuckoo_new (h1, h2, h3, cmp, sizeof (LumieraFiledescriptor), 3, NULL, NULL); if (!registry) LUMIERA_DIE (NO_MEMORY); From 238218f7766995663cafcc7638e623b96b69d144 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 21:24:41 +0200 Subject: [PATCH 055/102] WIP: add config_lookup skeleton --- src/backend/Makefile.am | 6 +- src/backend/config.c | 5 ++ src/backend/config.h | 7 +- src/backend/config_lookup.c | 151 ++++++++++++++++++++++++++++++++++++ src/backend/config_lookup.h | 102 ++++++++++++++++++++++++ 5 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 src/backend/config_lookup.c create mode 100644 src/backend/config_lookup.h diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index afe7cc1f3..f9d19d5e1 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -31,7 +31,8 @@ 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 += \ @@ -43,5 +44,6 @@ noinst_HEADERS += \ $(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/backend/config.c b/src/backend/config.c index deec72697..b68d30168 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -43,6 +43,7 @@ NOBUG_DEFINE_FLAG_PARENT (config, config_all); NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); NOBUG_DEFINE_FLAG_PARENT (config_item, config_all); +NOBUG_DEFINE_FLAG_PARENT (config_lookup, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile"); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key"); @@ -67,9 +68,12 @@ lumiera_config_init (const char* path) NOBUG_INIT_FLAG (config_typed); NOBUG_INIT_FLAG (config_file); NOBUG_INIT_FLAG (config_item); + NOBUG_INIT_FLAG (config_lookup); lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); + lumiera_config_lookup_init (&lumiera_global_config->keys); + lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config)); return 0; @@ -83,6 +87,7 @@ lumiera_config_destroy () if (lumiera_global_config) { lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config)); + lumiera_config_lookup_destroy (&lumiera_global_config->keys); lumiera_free (lumiera_global_config->path); lumiera_free (lumiera_global_config); lumiera_global_config = NULL; diff --git a/src/backend/config.h b/src/backend/config.h index 1daf54087..80a3f787f 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -40,6 +40,8 @@ NOBUG_DECLARE_FLAG (config_typed); NOBUG_DECLARE_FLAG (config_file); /* single config items */ NOBUG_DECLARE_FLAG (config_item); +/* lookup config keys */ +NOBUG_DECLARE_FLAG (config_lookup); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); @@ -49,7 +51,7 @@ LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY); LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); //TODO: Lumiera header includes// - +#include "backend/config_lookup.h" //TODO: System includes// #include @@ -65,7 +67,8 @@ LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); struct lumiera_config_struct { - // cuckoo hash + lumiera_config_lookup keys; + // configfile list char* path; /* diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c new file mode 100644 index 000000000..b0b6caeaa --- /dev/null +++ b/src/backend/config_lookup.c @@ -0,0 +1,151 @@ +/* + config_lookup.c - Lookup functions for the config subsystem + + 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/safeclib.h" + + +//TODO: Lumiera header includes// +#include "backend/config_lookup.h" +#include "backend/config.h" + +//TODO: System includes// +//#include +//#include + +//TODO: internal/static forward declarations// +static size_t +h1 (const void* item, const uint32_t r); + +static size_t +h2 (const void* item, const uint32_t r); + +static size_t +h3 (const void* item, const uint32_t r); + +static int +cmp (const void* keya, const void* keyb); + +static int +cmp (const void* keya, const void* keyb); + +/** + * @file + * + */ + + +//code goes here// + + + +LumieraConfigLookup +lumiera_config_lookup_init (LumieraConfigLookup self) +{ + self->hash = cuckoo_new (h1, h2, h3, cmp, sizeof (lumiera_config_lookupentry), 3, NULL, NULL); // TODO copy func, dtor + return self; +} + + +LumieraConfigLookup +lumiera_config_lookup_destroy (LumieraConfigLookup self) +{ + cuckoo_delete (self->hash); + return self; +} + + + + + + +LumieraConfigLookupentry +lumiera_config_lookupentry_new (const char* prefix, const char* name, const char* suffix) +{ + char* tmpstr = lumiera_tmpbuf_snprintf (LUMIERA_CONFIG_KEY_MAX, "%s%s%s%s%s", + prefix?prefix:"", prefix?".":"", + name?name:"", + suffix?".":"", suffix?suffix:""); + + TRACE (config_lookup, "new key %s", tmpstr); + + LumieraConfigLookupentry self = lumiera_malloc (sizeof (*self)); + + self->full_key = lumiera_strndup (tmpstr, LUMIERA_CONFIG_KEY_MAX); + llist_init (&self->configitems); + + return self; +} + +void +lumiera_config_lookupentry_delete (LumieraConfigLookupentry self) +{ + TRACE (config_lookup); + + lumiera_free (self->full_key); + ENSURE (llist_is_empty (&self->configitems)); + lumiera_free (self); +} + + + + +/* + Support functions for the cuckoo hash +*/ + +static size_t +h1 (const void* item, const uint32_t r) +{ + (void) item; + return r; +} + +static size_t +h2 (const void* item, const uint32_t r) +{ + (void) item; + return r; +} + +static size_t +h3 (const void* item, const uint32_t r) +{ + (void) item; + return r; +} + +static int +cmp (const void* keya, const void* keyb) +{ + (void) keya; + (void) keyb; + + return 0; +} + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h new file mode 100644 index 000000000..cb653dab8 --- /dev/null +++ b/src/backend/config_lookup.h @@ -0,0 +1,102 @@ +/* + config_lookup.h - Lookup functions for the config subsystem + + 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_CONFIG_LOOKUP_H +#define LUMIERA_CONFIG_LOOKUP_H + +//TODO: Support library includes// +#include "lib/cuckoo.h" +#include "lib/llist.h" + + +//TODO: Forward declarations// + + +//TODO: Lumiera header includes// + + +//TODO: System includes// +#include + + +/** + * @file + * + */ + +#define LUMIERA_CONFIG_KEY_MAX 1023 + + + +//TODO: declarations go here// + +/* + Lookup uses a cuckoo hash for now +*/ + +struct lumiera_config_lookup_struct +{ + Cuckoo hash; +}; +typedef struct lumiera_config_lookup_struct lumiera_config_lookup; +typedef lumiera_config_lookup* LumieraConfigLookup; + +LumieraConfigLookup +lumiera_config_lookup_init (LumieraConfigLookup self); + +LumieraConfigLookup +lumiera_config_lookup_destroy (LumieraConfigLookup self); + + + +/* + Lookup hash entries for the cuckoo hash +*/ + +struct lumiera_config_lookupentry_struct +{ + /* + we store a copy of the full key here + configentry keys are complete as expected + section keys are the prefix stored with a trailing dot + */ + char* full_key; + /* stack of all configitems stored under this key */ + llist configitems; +}; +typedef struct lumiera_config_lookupentry_struct lumiera_config_lookupentry; +typedef lumiera_config_lookupentry* LumieraConfigLookupentry; + +LumieraConfigLookupentry +lumiera_config_lookupentry_init (const char* prefix, const char* name, const char* suffix); + +void +lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self); + + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From 2f776858eeba6f3241b6cbc829d5a7ff916f4eb6 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 13 Aug 2008 09:20:08 +0200 Subject: [PATCH 056/102] FIX: Remove llist_move again and put a note to list_relocate, add test There was a fatal thinko, llist_relocate NUST NOT be called on a empty list, the pointers will just point to invaildated memory. This cant be handled by the llist code. The programmer is responsible to take proper actions. --- src/lib/llist.h | 14 +++----------- tests/15list.tests | 4 +++- tests/library/test-llist.c | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/lib/llist.h b/src/lib/llist.h index 3cb70f8ea..353fe4320 100644 --- a/src/lib/llist.h +++ b/src/lib/llist.h @@ -299,6 +299,9 @@ LLIST_FUNC (LList llist_unlink (LList self), /** * Fix a node which got relocated in memory. * It is supported to realloc/move list nodes in memory but one must call 'list_relocate' after doing so. + * IMPORTANT: it is not possible to relocate nodes which are empty this way, nor can this be determined + * after the relocation, so either llist_init them afterwards or insert a bogus node before moving the node + * and relocating it and remove it afterwards. * @param self node which got relocated * @return self */ @@ -306,17 +309,6 @@ LLIST_FUNC (LList llist_relocate (LList self), return self->next->prev = self->prev->next = self; ); -/** - * Move a node from one memory location to another. - * @param self target of the move, must be uninitialized or empty before this move - * @param source source of the move, will be initialized to a empty list after this call - * @return self - */ -LLIST_FUNC (LList llist_move (LList self, LList source), - *self = *source; - llist_init (source); - return llist_relocate (self); -); /** * Insert a node after another. diff --git a/tests/15list.tests b/tests/15list.tests index 88aef3c49..e04044f27 100644 --- a/tests/15list.tests +++ b/tests/15list.tests @@ -44,9 +44,11 @@ out: . out: . END +TEST "llist_relocate" relocate < Date: Wed, 13 Aug 2008 10:50:27 +0200 Subject: [PATCH 057/102] Fixed configitem_move, first parsing tests pass now --- src/backend/configitem.c | 12 ++++++++---- tests/20config.tests | 4 ++-- tests/backend/test-config.c | 20 +++++++------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 7e52f269e..a49694280 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -77,7 +77,7 @@ lumiera_configitem_destroy (LumieraConfigitem self) if (self->vtable && self->vtable->destroy) self->vtable->destroy (self); - ENSURE (!llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); + ENSURE (llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); llist_unlink (&self->link); @@ -122,12 +122,16 @@ lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) REQUIRE (self); REQUIRE (source); - llist_move (&self->link, &source->link); + llist_init (&self->link); + llist_insertlist_next (&self->link, &source->link); self->parent = source->parent; - llist_move (&self->childs, &source->childs); - llist_move (&self->lookup, &source->lookup); + llist_init (&self->childs); + llist_insertlist_next (&self->childs, &source->childs); + + llist_init (&self->lookup); + llist_insertlist_next (&self->lookup, &source->lookup); self->line = source->line; source->line = NULL; diff --git a/tests/20config.tests b/tests/20config.tests index 65dfb5404..7a4ea2517 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -135,8 +135,8 @@ END PLANNED "bool set" < Date: Mon, 25 Aug 2008 21:37:06 -0400 Subject: [PATCH 058/102] replace INCLUDES with AM_CPPFLAGS INCLUDES is deprecated (http://www.gnu.org/software/automake/manual/automake.html#Program-variables) --- src/gui/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index db652d99b..3508b9fe8 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -21,7 +21,7 @@ lumigui_srcdir = $(top_srcdir)/src/gui #lumigui_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror #lumigui_CPPFLAGS = -I$(top_srcdir)/src/ -INCLUDES = \ +AM_CPPFLAGS = \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ From 700a7e9645775dae6caa033a393d393b17726650 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Wed, 27 Aug 2008 11:00:10 +0200 Subject: [PATCH 059/102] Added directive-parser and tests for a content-check of a parsed configitem --- src/backend/configitem.c | 54 +++++++++++++++++++++++++++++++++++ tests/20config.tests | 56 +++++++++++++++++++++++++++++++++++++ tests/backend/test-config.c | 31 ++++++++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index a49694280..9ce36328b 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -208,6 +208,60 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) else if (*itr == '@' ) { /*this is a directive*/ + + /*itr points now to @*/ + self->key = itr; + + /*check whether there are illegal whitespaces after @*/ + itr++; + if (*itr && !isspace(*itr)) + { + /*now look for the end of the directive and set the keysize*/ + self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); + + 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 */ + + if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) )) + { + /*look for given arguments*/ + + /*skip blanks*/ + while (*itr && isspace (*itr)) + itr++; + + if (*itr) + { + /*there are arguments given, thus set delim*/ + self->delim = itr - 1; + } + else + { + /*no arguments were given*/ + self->delim = NULL; + } + } + else + { + /*malformed lines shall be treated like if they were comments*/ + self->key = NULL; + self->key_size = 0; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + } + } + else + { + /*there occurred already an error right after the @!*/ + /*malformed lines shall be treated like if they were comments*/ + self->key = NULL; + self->key_size = 0; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + } } else if (*itr == '[' ) { diff --git a/tests/20config.tests b/tests/20config.tests index 7a4ea2517..4f2ba9018 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -140,3 +140,59 @@ END TEST "create configitem with blank line" configitem_simple_ctor_dtor $' \t \t' <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 diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index 1369aa8bc..eae982fc6 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -141,5 +141,36 @@ TEST ("configitem_simple_ctor_dtor") lumiera_config_destroy (); } +TEST ("configitem_simple_content_check") +{ + REQUIRE (argv[2]); + lumiera_config_init ("./"); + + LumieraConfigitem item; + + item = lumiera_configitem_new (argv[2]); + + if ( item->line ) + { + printf("item->line = \'%s\'\n", item->line); + } + if ( item->key_size ) + { + printf("item->key_size = \'%i\'\n", item->key_size); + } + if ( item->key ) + { + printf("item->key = \'%s\'\n", item->key); + } + if ( item->delim ) + { + printf("item->delim = \'%s\'\n", item->delim); + } + + lumiera_configitem_delete (item); + + lumiera_config_destroy (); +} + TESTS_END From 8bbcc57f48ce10ce049d007cfd44425297f86e1c Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 30 Aug 2008 11:49:31 -0400 Subject: [PATCH 060/102] set per-target CPPFLAGS for lumigui instead of global AM_CPPFLAGS this prevents strange (_CPPFLAGS) dependencies such as the one that was identified and fixed in admin/Makefile.am Also, make sure to include the global $(AM_CPPFLAGS) flags in the per-target ones --- admin/Makefile.am | 2 +- src/gui/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/Makefile.am b/admin/Makefile.am index 9eb4fbb89..643ef3ac0 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -24,5 +24,5 @@ vgsuppression_LDADD = liblumi.a -lnobugmt -lpthread -ldl noinst_PROGRAMS += rsvg-convert rsvg_convert_SOURCES = $(admin_srcdir)/rsvg-convert.c -rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror +rsvg_convert_CPPFLAGS = $(GTK_LUMIERA_CFLAGS) $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror rsvg_convert_LDADD = -lcairo -lglib-2.0 -lgthread-2.0 -lrsvg-2 diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 3508b9fe8..0e1726956 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -21,7 +21,7 @@ lumigui_srcdir = $(top_srcdir)/src/gui #lumigui_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror #lumigui_CPPFLAGS = -I$(top_srcdir)/src/ -AM_CPPFLAGS = \ +lumigui_CPPFLAGS = $(AM_CPPFLAGS) \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ From 8bdab41ea094db29d3dc66f56ec321df5a6b6c51 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Wed, 27 Aug 2008 22:30:23 -0400 Subject: [PATCH 061/102] factor out -I$(top_srcdir)/src/ to a top-level AM_CPPFLAGS also remove a related unnecesary comment in src/gui/Makefile.am --- Makefile.am | 2 ++ admin/Makefile.am | 2 +- src/backend/Makefile.am | 1 - src/common/Makefile.am | 1 - src/gui/Makefile.am | 1 - src/lib/Makefile.am | 1 - src/proc/Makefile.am | 7 ------- tests/Makefile.am | 16 ++++++++-------- tests/common/Makefile.am | 2 +- tests/components/Makefile.am | 2 +- tests/plugin/Makefile.am | 6 +++--- 11 files changed, 16 insertions(+), 25 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3cf851c55..747a33b93 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,8 @@ BUILT_SOURCES = EXTRA_DIST = SUBDIRS = +AM_CPPFLAGS = -I$(top_srcdir)/src/ + # Only use subdirs if really needed, prefer the include scheme below #SUBDIRS += diff --git a/admin/Makefile.am b/admin/Makefile.am index 643ef3ac0..cf9083504 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -19,7 +19,7 @@ admin_srcdir = $(top_srcdir)/admin noinst_PROGRAMS += vgsuppression vgsuppression_SOURCES = $(admin_srcdir)/vgsuppression.c -vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror vgsuppression_LDADD = liblumi.a -lnobugmt -lpthread -ldl noinst_PROGRAMS += rsvg-convert diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 8b33df06a..8ad4cce2b 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -19,7 +19,6 @@ liblumibackend_a_srcdir = $(top_srcdir)/src/backend noinst_LIBRARIES += liblumibackend.a liblumibackend_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror -liblumibackend_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 29d794f7a..d7c95467c 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -22,7 +22,6 @@ liblumicommon_a_srcdir = $(top_srcdir)/src/common noinst_LIBRARIES += liblumicommon.a liblumicommon_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumicommon_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumicommon_a_SOURCES = \ $(liblumicommon_a_srcdir)/lumitime.cpp \ diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 0e1726956..9fb72b7ff 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -19,7 +19,6 @@ lumigui_srcdir = $(top_srcdir)/src/gui #noinst_LIBRARIES += liblumigui.a #lumigui_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror -#lumigui_CPPFLAGS = -I$(top_srcdir)/src/ lumigui_CPPFLAGS = $(AM_CPPFLAGS) \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 85b32ba80..f7d9058ae 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -19,7 +19,6 @@ liblumi_a_srcdir = $(top_srcdir)/src/lib noinst_LIBRARIES += liblumi.a liblumi_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror -liblumi_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumi_a_SOURCES = \ $(liblumi_a_srcdir)/plugin.c \ diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index 10de0d119..2338420bb 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -22,7 +22,6 @@ liblumiproc_a_srcdir = $(top_srcdir)/src/proc noinst_LIBRARIES += liblumiproc.a liblumiproc_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumiproc_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumiproc_a_SOURCES = \ $(liblumiproc_a_srcdir)/controllerfacade.cpp \ @@ -37,7 +36,6 @@ liblumiprocasset_a_srcdir = $(top_srcdir)/src/proc/asset noinst_LIBRARIES += liblumiprocasset.a liblumiprocasset_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumiprocasset_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumiprocasset_a_SOURCES = \ $(liblumiprocasset_a_srcdir)/codec.cpp \ @@ -62,7 +60,6 @@ liblumiprocengine_a_srcdir = $(top_srcdir)/src/proc/engine noinst_LIBRARIES += liblumiprocengine.a liblumiprocengine_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumiprocengine_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumiprocengine_a_SOURCES = \ $(liblumiprocengine_a_srcdir)/buffhandle.cpp \ @@ -85,7 +82,6 @@ liblumiprocmobject_a_srcdir = $(top_srcdir)/src/proc/mobject noinst_LIBRARIES += liblumiprocmobject.a liblumiprocmobject_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumiprocmobject_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumiprocmobject_a_SOURCES = \ $(liblumiprocmobject_a_srcdir)/builderfacade.cpp \ @@ -101,7 +97,6 @@ liblumiprocmobjectbuilder_a_srcdir = $(top_srcdir)/src/proc/mobject/builder noinst_LIBRARIES += liblumiprocmobjectbuilder.a liblumiprocmobjectbuilder_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumiprocmobjectbuilder_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumiprocmobjectbuilder_a_SOURCES = \ $(liblumiprocmobjectbuilder_a_srcdir)/assembler.cpp \ @@ -115,7 +110,6 @@ liblumiprocmobjectcontroller_a_srcdir = $(top_srcdir)/src/proc/mobject/controlle noinst_LIBRARIES += liblumiprocmobjectcontroller.a liblumiprocmobjectcontroller_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumiprocmobjectcontroller_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumiprocmobjectcontroller_a_SOURCES = \ $(liblumiprocmobjectcontroller_a_srcdir)/pathmanager.cpp @@ -125,7 +119,6 @@ liblumiprocmobjectsession_a_srcdir = $(top_srcdir)/src/proc/mobject/session noinst_LIBRARIES += liblumiprocmobjectsession.a liblumiprocmobjectsession_a_CXXFLAGS = $(CXXFLAGS) -Wall -liblumiprocmobjectsession_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumiprocmobjectsession_a_SOURCES = \ $(liblumiprocmobjectsession_a_srcdir)/abstractmo.cpp \ diff --git a/tests/Makefile.am b/tests/Makefile.am index c51133995..d9df41271 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,7 +20,7 @@ tests_srcdir = $(top_srcdir)/tests check_PROGRAMS += test-error test_error_SOURCES = $(tests_srcdir)/error/errortest.c -test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_error_LDADD = liblumi.a -lnobugmt -lpthread -ldl check_PROGRAMS += test-locking @@ -28,37 +28,37 @@ test_locking_SOURCES = \ $(tests_srcdir)/locking/test-locking.c \ $(tests_srcdir)/locking/mutex.c \ $(tests_srcdir)/locking/condition.c -test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_locking_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm check_PROGRAMS += test-llist test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c -test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_llist_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm check_PROGRAMS += test-safeclib test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c -test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_safeclib_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm check_PROGRAMS += test-uuid test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c -test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_uuid_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm check_PROGRAMS += test-references test_references_SOURCES = $(tests_srcdir)/library/test-references.c -test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_references_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm -lrt check_PROGRAMS += test-filedescriptors test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c -test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_filedescriptors_LDADD = liblumibackend.a liblumi.a -lnobugmt -lpthread -ldl -lm check_PROGRAMS += test-filehandles test_filehandles_SOURCES = $(tests_srcdir)/backend/test-filehandles.c -test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_filehandles_LDADD = liblumibackend.a liblumi.a -lnobugmt -lpthread -ldl -lm TESTS = $(tests_srcdir)/test.sh diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am index 7a985bec9..a8e62a528 100644 --- a/tests/common/Makefile.am +++ b/tests/common/Makefile.am @@ -19,7 +19,7 @@ testcommon_srcdir = $(top_srcdir)/tests/common check_PROGRAMS += test-common -test_common_CPPFLAGS = $(AM_CPPFLAGS) -Wall -I$(top_srcdir)/src -I$(testcommon_srcdir) +test_common_CPPFLAGS = $(AM_CPPFLAGS) -Wall -I$(testcommon_srcdir) test_common_LDADD = \ liblumiproc.a \ liblumiprocengine.a \ diff --git a/tests/components/Makefile.am b/tests/components/Makefile.am index 3fce30365..771818c9e 100644 --- a/tests/components/Makefile.am +++ b/tests/components/Makefile.am @@ -19,7 +19,7 @@ testcomponents_srcdir = $(top_srcdir)/tests/components check_PROGRAMS += test-components -test_components_CPPFLAGS = $(AM_CPPFLAGS) -Wall -I$(top_srcdir)/src -I$(testcomponents_srcdir) +test_components_CPPFLAGS = $(AM_CPPFLAGS) -Wall -I$(testcomponents_srcdir) test_components_LDADD = \ liblumiproc.a \ liblumiprocengine.a \ diff --git a/tests/plugin/Makefile.am b/tests/plugin/Makefile.am index c6afc8e36..f9fc1b5a2 100644 --- a/tests/plugin/Makefile.am +++ b/tests/plugin/Makefile.am @@ -19,19 +19,19 @@ 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 -I$(top_srcdir)/src +test_plugin_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror test_plugin_LDADD = liblumi.a -lnobugmt -lpthread -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 -I$(top_srcdir)/src +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 -I$(top_srcdir)/src +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 4a3ce814d30f2176d477631f9ceba2a40e663cbf Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 30 Aug 2008 10:16:34 -0400 Subject: [PATCH 062/102] fix section identifier comment --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b5a61ab03..42b6961dc 100644 --- a/configure.ac +++ b/configure.ac @@ -158,7 +158,7 @@ AC_CHECK_LIB(Xv, XvQueryAdaptors, , # END X11 Dependancies -############## Pkg Dependancies +############## Gtk Dependancies PKG_CHECK_MODULES(GTK_LUMIERA, [ gtkmm-2.4 >= 2.8 gdl-1.0 >= 0.6.1 cairomm-1.0 >= 0.6.0 gavl >= 0.2.5 librsvg-2.0 >= 2.18.1]) From 387ba8c3219a56849af4c73b5b3b8289e42daf93 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 30 Aug 2008 13:28:24 -0400 Subject: [PATCH 063/102] find and configure NoBug by using pkg-config --- Makefile.am | 3 ++- admin/Makefile.am | 2 +- configure.ac | 22 +++++++++++++--------- src/gui/Makefile.am | 2 +- tests/Makefile.am | 16 ++++++++-------- tests/common/Makefile.am | 2 +- tests/components/Makefile.am | 2 +- tests/plugin/Makefile.am | 2 +- 8 files changed, 28 insertions(+), 23 deletions(-) diff --git a/Makefile.am b/Makefile.am index 747a33b93..27b972d68 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,8 @@ BUILT_SOURCES = EXTRA_DIST = SUBDIRS = -AM_CPPFLAGS = -I$(top_srcdir)/src/ +AM_CPPFLAGS = -I$(top_srcdir)/src/ \ + $(NOBUGMT_LUMIERA_CFLAGS) # Only use subdirs if really needed, prefer the include scheme below #SUBDIRS += diff --git a/admin/Makefile.am b/admin/Makefile.am index cf9083504..ab0be86fa 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -20,7 +20,7 @@ admin_srcdir = $(top_srcdir)/admin noinst_PROGRAMS += vgsuppression vgsuppression_SOURCES = $(admin_srcdir)/vgsuppression.c vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -vgsuppression_LDADD = liblumi.a -lnobugmt -lpthread -ldl +vgsuppression_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl noinst_PROGRAMS += rsvg-convert rsvg_convert_SOURCES = $(admin_srcdir)/rsvg-convert.c diff --git a/configure.ac b/configure.ac index 42b6961dc..8c6e4300d 100644 --- a/configure.ac +++ b/configure.ac @@ -80,15 +80,6 @@ AC_ARG_ENABLE(release, AC_HELP_STRING([--enable-release], [select NoBug RELEASE # C headers and libraries AC_LANG_PUSH([C]) -AC_CHECK_HEADER([nobug.h], - AC_DEFINE(HAVE_NOBUG_H), - AC_MSG_ERROR([NoBug header missing (http://www.pipapo.org/pipawiki/NoBug)]) - ) -AC_CHECK_LIB([nobugmt], nobug_thread_id_get, - , - AC_MSG_ERROR([NoBug multithreading library missing (http://www.pipapo.org/pipawiki/NoBug)]) - ) - AC_CHECK_HEADER([execinfo.h], AC_DEFINE(HAVE_EXECINFO_H)) # there is a warning in nobug, disabled til fixed AC_CHECK_HEADER([valgrind/valgrind.h], AC_DEFINE(HAVE_VALGRIND_VALGRIND_H)) @@ -168,6 +159,19 @@ AC_SUBST(GTK_LUMIERA_LIBS) # END Gtk Dependancies + +############## Nobug Dependancies +PKG_CHECK_MODULES(NOBUG_LUMIERA, [nobug >= 0.3rc1], + AC_DEFINE(HAVE_NOBUG_H), + AC_MSG_ERROR([NoBug pkg-config metadata missing (http://www.pipapo.org/pipawiki/NoBug)]) +) +PKG_CHECK_MODULES(NOBUGMT_LUMIERA, [nobugmt >= 0.3rc1], + AC_DEFINE(HAVE_NOBUGMT_H), + AC_MSG_ERROR([NoBug pkg-config metadata missing (http://www.pipapo.org/pipawiki/NoBug)]) +) + +# END Nobug Dependancies + # Print a summary AC_MSG_RESULT([ Configuration Summary:]) diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 9fb72b7ff..a4d3df708 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -77,7 +77,7 @@ lumigui_SOURCES = \ $(lumigui_srcdir)/output/xvdisplayer.hpp lumigui_LDFLAGS = -lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumicommon.a liblumi.a +lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumicommon.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) lumigui_DEPENDENCIES = \ $(top_builddir)/lumiera_ui.rc \ diff --git a/tests/Makefile.am b/tests/Makefile.am index d9df41271..564c8a454 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,7 +21,7 @@ tests_srcdir = $(top_srcdir)/tests check_PROGRAMS += test-error test_error_SOURCES = $(tests_srcdir)/error/errortest.c test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_error_LDADD = liblumi.a -lnobugmt -lpthread -ldl +test_error_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl check_PROGRAMS += test-locking test_locking_SOURCES = \ @@ -29,36 +29,36 @@ test_locking_SOURCES = \ $(tests_srcdir)/locking/mutex.c \ $(tests_srcdir)/locking/condition.c test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_locking_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm +test_locking_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-llist test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_llist_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm +test_llist_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-safeclib test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_safeclib_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm +test_safeclib_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-uuid test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_uuid_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm +test_uuid_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-references test_references_SOURCES = $(tests_srcdir)/library/test-references.c test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_references_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm -lrt +test_references_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm -lrt check_PROGRAMS += test-filedescriptors test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c test_filedescriptors_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_filedescriptors_LDADD = liblumibackend.a liblumi.a -lnobugmt -lpthread -ldl -lm +test_filedescriptors_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-filehandles test_filehandles_SOURCES = $(tests_srcdir)/backend/test-filehandles.c test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_filehandles_LDADD = liblumibackend.a liblumi.a -lnobugmt -lpthread -ldl -lm +test_filehandles_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm TESTS = $(tests_srcdir)/test.sh diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am index a8e62a528..55393df9c 100644 --- a/tests/common/Makefile.am +++ b/tests/common/Makefile.am @@ -31,7 +31,7 @@ test_common_LDADD = \ liblumi.a \ liblumicommon.a \ liblumibackend.a \ - -lnobugmt -lpthread -ldl -lboost_program_options-mt -lboost_regex-mt + $(NOBUGMT_LUMIERA_LIBS) -ldl -lboost_program_options-mt -lboost_regex-mt test_common_SOURCES = \ $(testcommon_srcdir)/appconfigtest.cpp \ diff --git a/tests/components/Makefile.am b/tests/components/Makefile.am index 771818c9e..733737580 100644 --- a/tests/components/Makefile.am +++ b/tests/components/Makefile.am @@ -31,7 +31,7 @@ test_components_LDADD = \ liblumi.a \ liblumicommon.a \ liblumibackend.a \ - -lnobugmt -lpthread -ldl -lboost_program_options-mt -lboost_regex-mt + $(NOBUGMT_LUMIERA_LIBS) -ldl -lboost_program_options-mt -lboost_regex-mt test_components_SOURCES = \ $(testcomponents_srcdir)/backend/mediaaccessmock.cpp \ diff --git a/tests/plugin/Makefile.am b/tests/plugin/Makefile.am index f9fc1b5a2..c8cf9a22f 100644 --- a/tests/plugin/Makefile.am +++ b/tests/plugin/Makefile.am @@ -20,7 +20,7 @@ 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 -lnobugmt -lpthread -ldl +test_plugin_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl test_plugin_SOURCES = $(examples_srcdir)/plugin_main.c noinst_HEADERS += $(examples_srcdir)/hello_interface.h From 859437794ea7bb8039054950c5e1d57de8b5fe16 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 30 Aug 2008 13:32:24 -0400 Subject: [PATCH 064/102] put global AM_CPPFLAGS at the front of the per-target variables for consistency --- Makefile.am | 2 ++ admin/Makefile.am | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 27b972d68..da413d117 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,6 +27,8 @@ BUILT_SOURCES = EXTRA_DIST = SUBDIRS = +# global pre-processor flags. Per-target variables should include +# these at the front (if possible) for consistency AM_CPPFLAGS = -I$(top_srcdir)/src/ \ $(NOBUGMT_LUMIERA_CFLAGS) diff --git a/admin/Makefile.am b/admin/Makefile.am index ab0be86fa..f2c9c0636 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -24,5 +24,5 @@ vgsuppression_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl noinst_PROGRAMS += rsvg-convert rsvg_convert_SOURCES = $(admin_srcdir)/rsvg-convert.c -rsvg_convert_CPPFLAGS = $(GTK_LUMIERA_CFLAGS) $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror +rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) $(GTK_LUMIERA_CFLAGS) -std=gnu99 -Wall -Werror rsvg_convert_LDADD = -lcairo -lglib-2.0 -lgthread-2.0 -lrsvg-2 From 16b433a6c3590542b50e24ffd3a9e55d7919121d Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 30 Aug 2008 17:13:36 -0400 Subject: [PATCH 065/102] added a check for the minimum boost version copied an m4 macro: http://autoconf-archive.cryp.to/ax_boost_base.m4 --- Makefile.am | 2 + configure.ac | 5 +- m4/ax_boost_base.m4 | 223 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 m4/ax_boost_base.m4 diff --git a/Makefile.am b/Makefile.am index da413d117..8a2bc889f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +ACLOCAL_AMFLAGS = -I m4 + bin_PROGRAMS = lib_LTLIBRARIES = noinst_PROGRAMS = diff --git a/configure.ac b/configure.ac index 8c6e4300d..0ef7ffd00 100644 --- a/configure.ac +++ b/configure.ac @@ -103,7 +103,10 @@ AC_CHECK_HEADER([boost/program_options.hpp], , AC_MSG_ERROR([boost::program_options missing (http://www.boost.org/)]) ) -# checking for library left out, name contains compiler version here (libboost_program_options-gcc42-mt-1_34_1.so.1.34.1) any ides how to use that? + +# check for the minimum Boost version +# (http://www.randspringer.de/boost/upt.html) +AX_BOOST_BASE([1.34.1]) AC_CHECK_HEADER([boost/regex.hpp], , diff --git a/m4/ax_boost_base.m4 b/m4/ax_boost_base.m4 new file mode 100644 index 000000000..2e5afd091 --- /dev/null +++ b/m4/ax_boost_base.m4 @@ -0,0 +1,223 @@ +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_boost_base.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_BASE([MINIMUM-VERSION]) +# +# DESCRIPTION +# +# Test for the Boost C++ libraries of a particular version (or newer) +# +# If no path to the installed boost library is given the macro searchs +# under /usr, /usr/local, /opt and /opt/local and evaluates the +# $BOOST_ROOT environment variable. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) +# +# And sets: +# +# HAVE_BOOST +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Thomas Porschberg +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AX_BOOST_BASE], +[ +AC_ARG_WITH([boost], + AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ac_boost_path="" + else + want_boost="yes" + ac_boost_path="$withval" + fi + ], + [want_boost="yes"]) + + +AC_ARG_WITH([boost-libdir], + AS_HELP_STRING([--with-boost-libdir=LIB_DIR], + [Force given directory for boost libraries. Note that this will overwrite library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]), + [ + if test -d $withval + then + ac_boost_lib_path="$withval" + else + AC_MSG_ERROR(--with-boost-libdir expected directory name) + fi + ], + [ac_boost_lib_path=""] +) + +if test "x$want_boost" = "xyes"; then + boost_lib_version_req=ifelse([$1], ,1.20.0,$1) + boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` + boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` + boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$boost_lib_version_req_sub_minor" = "x" ; then + boost_lib_version_req_sub_minor="0" + fi + WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` + AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) + succeeded=no + + dnl first we check the system location for boost libraries + dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl or if you install boost with RPM + if test "$ac_boost_path" != ""; then + BOOST_LDFLAGS="-L$ac_boost_path/lib" + BOOST_CPPFLAGS="-I$ac_boost_path/include" + else + for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then + BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib" + BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" + break; + fi + done + fi + + dnl overwrite ld flags if we have required special directory with + dnl --with-boost-libdir parameter + if test "$ac_boost_lib_path" != ""; then + BOOST_LDFLAGS="-L$ac_boost_lib_path" + fi + + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + + + + dnl if we found no boost with system layout we search for boost libraries + dnl built and installed without the --layout=system option or for a staged(not installed) version + if test "x$succeeded" != "xyes"; then + _version=0 + if test "$ac_boost_path" != ""; then + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" + done + fi + else + for ac_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + best_path=$ac_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + if test "$ac_boost_lib_path" = "" + then + BOOST_LDFLAGS="-L$best_path/lib" + fi + + if test "x$BOOST_ROOT" != "x"; then + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then + AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + fi + + if test "$succeeded" != "yes" ; then + if test "$_version" = "0" ; then + AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) + else + AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) + fi + else + AC_SUBST(BOOST_CPPFLAGS) + AC_SUBST(BOOST_LDFLAGS) + AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" +fi + +]) From 12c651f4ede3f43a2db09bd6684dd3bad30c3d6e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 5 Sep 2008 15:54:23 +0200 Subject: [PATCH 066/102] fix name of 'doc' target, remove the OPENGL flag for now --- SConstruct | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index 2b3e2cfd0..9c56cece3 100644 --- a/SConstruct +++ b/SConstruct @@ -79,7 +79,7 @@ def setupBasicEnvironment(): env.Append(CPPDEFINES = '_GNU_SOURCE') appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG') - appendCppDefine(env,'OPENGL','USE_OPENGL') +# appendCppDefine(env,'OPENGL','USE_OPENGL') appendVal(env,'ARCHFLAGS', 'CCFLAGS') # for both C and C++ appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3') appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb') @@ -128,7 +128,7 @@ def defineCmdlineOptions(): allowed_values=('ALPHA', 'BETA', 'RELEASE')) ,BoolOption('DEBUG', 'Build with debugging information and no optimizations', False) ,BoolOption('OPTIMIZE', 'Build with strong optimization (-O3)', False) - ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False) +# ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False) # ,EnumOption('DIST_TARGET', 'Build target architecture', 'auto', # allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2) ,PathOption('DESTDIR', 'Installation dir prefix', '/usr/local') @@ -337,8 +337,8 @@ def definePostBuildTargets(env, artifacts): env.Clean ('build', [ '$SRCDIR/pre.gch' ]) doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile') - env.Alias ('doxydoc', doxydoc) - env.Clean ('doxydoc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt']) + env.Alias ('doc', doxydoc) + env.Clean ('doc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt']) def defineInstallTargets(env, artifacts): From 43291cb9cc1ddb1e361600394b91e84852850c07 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 5 Sep 2008 17:01:24 +0200 Subject: [PATCH 067/102] fix some warnings --- src/common/cmdline.cpp | 2 +- src/common/cmdline.hpp | 2 +- src/common/error.cpp | 10 ++++++---- src/proc/asset/category.cpp | 4 +++- src/proc/mobject/session/defsregistry.hpp | 1 + tests/common/mainsuite.cpp | 2 +- tests/common/singletontestmocktest.cpp | 4 ++-- tests/common/test/cmdlinewrappertest.cpp | 2 +- 8 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp index dec1a0620..eca0b18bb 100644 --- a/src/common/cmdline.cpp +++ b/src/common/cmdline.cpp @@ -52,7 +52,7 @@ namespace util /** create as a tokenized copy of the current commandline. * Note that argv[0] is allways ignored. */ - Cmdline::Cmdline (int argc, char* argv[]) + Cmdline::Cmdline (int argc, const char** argv) : vector (noneg(argc-1)) { for (int i=1; i (&cause); if (err) - if (isnil (err->cause_)) - return cause.what(); // cause is root cause - else - return err->cause_; // cause was caused by another exception + { + if (isnil (err->cause_)) + return cause.what(); // cause is root cause + else + return err->cause_; // cause was caused by another exception + } // unknown other exception type return cause.what (); diff --git a/src/proc/asset/category.cpp b/src/proc/asset/category.cpp index dcb767ccf..3d178e549 100644 --- a/src/proc/asset/category.cpp +++ b/src/proc/asset/category.cpp @@ -38,7 +38,9 @@ namespace asset */ Category::operator string () const { - char *kinds[6] = { "AUDIO" + typedef const char * const SymID; + + SymID kinds[6] = { "AUDIO" , "VIDEO" , "EFFECT" , "CODEC" diff --git a/src/proc/mobject/session/defsregistry.hpp b/src/proc/mobject/session/defsregistry.hpp index 64f84ab32..73925e11a 100644 --- a/src/proc/mobject/session/defsregistry.hpp +++ b/src/proc/mobject/session/defsregistry.hpp @@ -53,6 +53,7 @@ namespace mobject using boost::lambda::var; namespace // Implementation details //////////////////TODO better a named implementation namespace (avoids warnings on gcc 4.3) +//////////////////////////////////////////////////////////FIXME this is a *real* problem, because this namespace create storage, which it shouldn't { struct TableEntry { diff --git a/tests/common/mainsuite.cpp b/tests/common/mainsuite.cpp index 3ef740744..455bfd98e 100644 --- a/tests/common/mainsuite.cpp +++ b/tests/common/mainsuite.cpp @@ -34,7 +34,7 @@ using lumiera::ON_GLOBAL_SHUTDOWN; * cmd line argument. * Note: to ease debugging, we don't catch any exceptions. */ -int main (int argc, char* argv[]) +int main (int argc, const char* argv[]) { util::Cmdline args (argc,argv); test::TestOption optparser (args); diff --git a/tests/common/singletontestmocktest.cpp b/tests/common/singletontestmocktest.cpp index ea5e1d70e..2be296bb1 100644 --- a/tests/common/singletontestmocktest.cpp +++ b/tests/common/singletontestmocktest.cpp @@ -50,11 +50,11 @@ namespace lumiera class TestSingletonO { int callCnt; - char* typid; + Symbol typid; format msg; public: - TestSingletonO(char* ty="TestSingletonO") + TestSingletonO(Symbol ty="TestSingletonO") : callCnt (0), typid(ty), msg ("%s::doIt() call=%d\n") { TRACE (singleton, "ctor %s", typid); diff --git a/tests/common/test/cmdlinewrappertest.cpp b/tests/common/test/cmdlinewrappertest.cpp index 668ce8121..f5d1eaf25 100644 --- a/tests/common/test/cmdlinewrappertest.cpp +++ b/tests/common/test/cmdlinewrappertest.cpp @@ -85,7 +85,7 @@ namespace util */ void testStandardCmdlineformat() { - char* fakeArg[3] = {"CMD", "one ", "two"}; + const char* fakeArg[3] = {"CMD", "one ", "two"}; Cmdline theCmdline(3, fakeArg); cout << "Standard Cmdlineformat:" << theCmdline << "\n"; } From 6c34fc63f15f9a8ef4d2a212daa6e9d388da2c9a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 9 Aug 2008 16:15:29 +0200 Subject: [PATCH 068/102] Move the resource announce/forget into the rwlock init/destroy --- tests/library/test-locking.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/library/test-locking.c b/tests/library/test-locking.c index 7cceea1cc..55ea91cdb 100644 --- a/tests/library/test-locking.c +++ b/tests/library/test-locking.c @@ -151,6 +151,4 @@ TEST ("conditionforgotunlock") lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON)); } - - TESTS_END From e2b7561c76fecbbd9a815eb5520e776a193219c3 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 11 Aug 2008 10:12:05 +0200 Subject: [PATCH 069/102] FIX: put a note to list_relocate, add test There was a fatal thinko, llist_relocate NUST NOT be called on a empty list, the pointers will just point to invaildated memory. This cant be handled by the llist code. The programmer is responsible to take proper actions. --- src/lib/llist.h | 4 ++++ tests/15list.tests | 4 +++- tests/library/test-llist.c | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/lib/llist.h b/src/lib/llist.h index 128a3e826..353fe4320 100644 --- a/src/lib/llist.h +++ b/src/lib/llist.h @@ -299,6 +299,9 @@ LLIST_FUNC (LList llist_unlink (LList self), /** * Fix a node which got relocated in memory. * It is supported to realloc/move list nodes in memory but one must call 'list_relocate' after doing so. + * IMPORTANT: it is not possible to relocate nodes which are empty this way, nor can this be determined + * after the relocation, so either llist_init them afterwards or insert a bogus node before moving the node + * and relocating it and remove it afterwards. * @param self node which got relocated * @return self */ @@ -306,6 +309,7 @@ LLIST_FUNC (LList llist_relocate (LList self), return self->next->prev = self->prev->next = self; ); + /** * Insert a node after another. * @param self node after which we want to insert diff --git a/tests/15list.tests b/tests/15list.tests index 88aef3c49..e04044f27 100644 --- a/tests/15list.tests +++ b/tests/15list.tests @@ -44,9 +44,11 @@ out: . out: . END +TEST "llist_relocate" relocate < Date: Fri, 15 Aug 2008 17:04:29 +0200 Subject: [PATCH 070/102] Add lumiera_tmpbuf_strcat3 for concating up to three strings to safeclib --- src/lib/safeclib.c | 12 ++++++++++++ src/lib/safeclib.h | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/lib/safeclib.c b/src/lib/safeclib.c index 3d1468627..0f61a7a92 100644 --- a/src/lib/safeclib.c +++ b/src/lib/safeclib.c @@ -175,6 +175,18 @@ lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...) } +char* +lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len, + const char* str2, size_t str2_len, + const char* str3, size_t str3_len) +{ + return lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s%s%.*s%s%.*s", + str1?str1_len:0, str1?str1:"", str1?".":"", + str2?str2_len:0, str2?str2:"", + str3?".":"", str3?str3_len:0, str3?str3:""); +} + + char* lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def) { diff --git a/src/lib/safeclib.h b/src/lib/safeclib.h index 2cd95502d..d5b7eb0a8 100644 --- a/src/lib/safeclib.h +++ b/src/lib/safeclib.h @@ -135,6 +135,21 @@ lumiera_tmpbuf_strndup (const char* src, size_t size); char* lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...); +/** + * Concat up to 3 strings in a tmpbuf. + * @param str1 first string to concat or NULL + * @param str1_len how much of the first string shall be used + * @param str2 second string to concat or NULL + * @param str2_len how much of the second string shall be used + * @param str3 third string to concat or NULL + * @param str3_len how much of the third string shall be used + * @return temporary buffer containing the constructed of the string + */ +char* +lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len, + const char* str2, size_t str2_len, + const char* str3, size_t str3_len); + /** * Translates characters in a string, similar to the shell 'tr' utility * @param in input string to be translated From 9471e47cdf81a1ee9111353666a17ad6eb4840f4 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 11:38:56 +0200 Subject: [PATCH 071/102] WIP: Cuckoo hash update, leave it at a insane state * add a destructor function for elements * rename cuckoo_free to cuckoo_delete to be consistent with the rest * add a custom copy function to the cuckoo hash * Cuckoo hash update, use a vtable to pass functions to the constructor * make the source of a move non-const, just in case something needs to be cleaned up there. * let cuckoo_insert return the hash table entry directly --- src/lib/cuckoo.c | 224 ++++++++++++++++++++++++++--------------------- src/lib/cuckoo.h | 72 +++++++++------ 2 files changed, 171 insertions(+), 125 deletions(-) diff --git a/src/lib/cuckoo.c b/src/lib/cuckoo.c index bbcb0e71a..b2ad064c0 100644 --- a/src/lib/cuckoo.c +++ b/src/lib/cuckoo.c @@ -23,6 +23,8 @@ #include +#define CUCKOO_GRANULARITY int + enum compact_state { COMPACTING_OFF, @@ -35,14 +37,11 @@ struct cuckoo_struct size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */ size_t itemsize; - cuckoo_hashfunc h1; /* hash function */ - uint32_t r1; /* random, reset for each rehash */ - cuckoo_hashfunc h2; - uint32_t r2; - cuckoo_hashfunc h3; - uint32_t r3; + struct cuckoo_vtable vtable; - cuckoo_cmpfunc cmp; + uint32_t r1; /* random, reset for each rehash */ + uint32_t r2; + uint32_t r3; void* t1; void* t2; @@ -61,28 +60,59 @@ static inline uint32_t cuckoo_fast_prng () return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1); } +static inline int +iszero (void* mem, size_t size) +{ + while (size && !*(CUCKOO_GRANULARITY*)mem) + { + size -= sizeof (CUCKOO_GRANULARITY); + mem += sizeof (CUCKOO_GRANULARITY); + } + return !size; +} + +static inline void +xmemmov (void* dst, void* src, size_t size) +{ + while (size) + { + size -= sizeof (CUCKOO_GRANULARITY); + *(CUCKOO_GRANULARITY*)(dst + size) = *(CUCKOO_GRANULARITY*)(src + size); + } +} + + Cuckoo -cuckoo_init (Cuckoo self, - cuckoo_hashfunc h1, - cuckoo_hashfunc h2, - cuckoo_hashfunc h3, - cuckoo_cmpfunc cmp, - size_t itemsize, - unsigned startsize) +cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable) { if (!self) return NULL; - self->size = 1<itemsize = itemsize; - self->h1 = h1; + self->size = 16; + self->itemsize = (itemsize * sizeof (CUCKOO_GRANULARITY) + + sizeof (CUCKOO_GRANULARITY) - 1) / sizeof (CUCKOO_GRANULARITY); /* round up to next CUCKOO_GRANULARITY boundary */ self->r1 = cuckoo_fast_prng (); - self->h2 = h2; self->r2 = cuckoo_fast_prng (); - self->h3 = h3; self->r3 = cuckoo_fast_prng (); - self->cmp = cmp; + if (!vtable->h1 || !vtable->h2 || !vtable->h3) + return NULL; + + self->vtable.h1 = vtable->h1; + self->vtable.h2 = vtable->h2; + self->vtable.h3 = vtable->h3; + + if (!vtable->cmp) + return NULL; + + self->vtable.cmp = vtable->cmp; + + self->vtable.dtor = vtable->dtor; + + if (vtable->mov) + self->vtable.mov = vtable->mov; + else + self->vtable.mov = xmemmov; self->t1 = calloc (self->size * 4, itemsize); self->t2 = calloc (self->size * 2, itemsize); @@ -101,19 +131,15 @@ cuckoo_init (Cuckoo self, self->autocompact = COMPACTING_AUTO; self->elements = 0; + return self; } Cuckoo -cuckoo_new (cuckoo_hashfunc h1, - cuckoo_hashfunc h2, - cuckoo_hashfunc h3, - cuckoo_cmpfunc cmp, - size_t itemsize, - unsigned startsize) +cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable) { Cuckoo self = malloc (sizeof (struct cuckoo_struct)); - if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize)) + if (!cuckoo_init (self, itemsize, vtable)) { free (self); return NULL; @@ -126,6 +152,18 @@ cuckoo_destroy (Cuckoo self) { if (self) { + + if (self->vtable.dtor) + { + void* elem; + for (elem = self->t1; elem < self->t1 + self->size * 4; elem += self->size) + self->vtable.dtor (elem); + for (elem = self->t2; elem < self->t1 + self->size * 2; elem += self->size) + self->vtable.dtor (elem); + for (elem = self->t3; elem < self->t1 + self->size; elem += self->size) + self->vtable.dtor (elem); + } + free (self->t1); free (self->t2); free (self->t3); @@ -135,76 +173,57 @@ cuckoo_destroy (Cuckoo self) void -cuckoo_free (Cuckoo self) +cuckoo_delete (Cuckoo self) { free (cuckoo_destroy (self)); } -static inline int -iszero (void* mem, size_t size) -{ - while (size && !*(int*)mem) - { - size -= sizeof (int); - mem += sizeof (int); - } - return !size; -} - -static inline void -xmemcpy (void* dst, void* src, size_t size) -{ - while (size) - { - size -= sizeof (int); - *(int*)(dst + size) = *(int*)(src + size); - } -} - - -static int +static void* cuckoo_insert_internal_ (Cuckoo self, void* item) { void* pos; - char tmp[self->itemsize]; + CUCKOO_GRANULARITY tmp[self->itemsize / sizeof(CUCKOO_GRANULARITY)]; for (unsigned n = 0; n < self->maxloops; ++n) { /* find nest */ - pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size)); + pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size)); /* kick old egg out */ - xmemcpy (tmp, pos, self->itemsize); + if (iszero (pos, self->itemsize)) + memset (tmp, 0, self->itemsize); + else + self->vtable.mov (tmp, pos, self->itemsize); /* lay egg */ - xmemcpy (pos, item, self->itemsize); + self->vtable.mov (pos, item, self->itemsize); if (iszero (tmp, self->itemsize)) - return 1; + return pos; /* find nest */ - pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size)); + pos = self->t2 + self->itemsize * (self->vtable.h2 (tmp, self->r2) % (2*self->size)); /* kick old egg out */ - xmemcpy (item, pos, self->itemsize); + self->vtable.mov (item, pos, self->itemsize); /* lay egg */ - xmemcpy (pos, tmp, self->itemsize); + self->vtable.mov (pos, tmp, self->itemsize); if (iszero (item, self->itemsize)) - return 1; + return pos; /* find nest */ - pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size); + pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size); /* kick old egg out */ - xmemcpy (tmp, pos, self->itemsize); + self->vtable.mov (tmp, pos, self->itemsize); /* lay egg */ - xmemcpy (pos, item, self->itemsize); + self->vtable.mov (pos, item, self->itemsize); if (iszero (tmp, self->itemsize)) - return 1; + return pos; /* copy tmp to item, which will be reinserted on next interation / after rehashing */ - xmemcpy (item, tmp, self->itemsize); + self->vtable.mov (item, tmp, self->itemsize); } - return 0; + return NULL; } @@ -230,14 +249,14 @@ cuckoo_rehash (Cuckoo self) { for (n = 0; n < self->maxloops; ++n) { - unsigned hash = self->h1 (pos, self->r1) % (4*self->size); + unsigned hash = self->vtable.h1 (pos, self->r1) % (4*self->size); if (hash != i) { char t[self->itemsize]; void* hpos = self->t1 + self->itemsize * hash; - xmemcpy (t, hpos, self->itemsize); - xmemcpy (hpos, pos, self->itemsize); - xmemcpy (pos, t, self->itemsize); + self->vtable.mov (t, hpos, self->itemsize); + self->vtable.mov (hpos, pos, self->itemsize); + self->vtable.mov (pos, t, self->itemsize); if (iszero (t, self->itemsize)) break; } @@ -260,14 +279,14 @@ cuckoo_rehash (Cuckoo self) { for (n = 0; n < self->maxloops; ++n) { - unsigned hash = self->h2 (pos, self->r2) % (2*self->size); + unsigned hash = self->vtable.h2 (pos, self->r2) % (2*self->size); if (hash != i) { char t[self->itemsize]; void* hpos = self->t2 + self->itemsize * hash; - xmemcpy (t, hpos, self->itemsize); - xmemcpy (hpos, pos, self->itemsize); - xmemcpy (pos, t, self->itemsize); + self->vtable.mov (t, hpos, self->itemsize); + self->vtable.mov (hpos, pos, self->itemsize); + self->vtable.mov (pos, t, self->itemsize); if (iszero (t, self->itemsize)) break; } @@ -290,14 +309,14 @@ cuckoo_rehash (Cuckoo self) { for (n = 0; n < self->maxloops; ++n) { - unsigned hash = self->h3 (pos, self->r3) % self->size; + unsigned hash = self->vtable.h3 (pos, self->r3) % self->size; if (hash != i) { char t[self->itemsize]; void* hpos = self->t3 + self->itemsize * hash; - xmemcpy (t, hpos, self->itemsize); - xmemcpy (hpos, pos, self->itemsize); - xmemcpy (pos, t, self->itemsize); + self->vtable.mov (t, hpos, self->itemsize); + self->vtable.mov (hpos, pos, self->itemsize); + self->vtable.mov (pos, t, self->itemsize); if (iszero (t, self->itemsize)) break; } @@ -314,10 +333,10 @@ static int cuckoo_grow (Cuckoo self) { /* rotate hashfuncs, tables, randoms */ - cuckoo_hashfunc th = self->h3; - self->h3 = self->h2; - self->h2 = self->h1; - self->h1 = th; + cuckoo_hashfunc th = self->vtable.h3; + self->vtable.h3 = self->vtable.h2; + self->vtable.h2 = self->vtable.h1; + self->vtable.h1 = th; uint32_t tr = self->r3; self->r3 = self->r2; @@ -380,10 +399,10 @@ cuckoo_compact (Cuckoo self) if (self->size > 2 && self->elements < self->size * 3) { - cuckoo_hashfunc th = self->h1; - self->h1 = self->h2; - self->h2 = self->h3; - self->h3 = th; + cuckoo_hashfunc th = self->vtable.h1; + self->vtable.h1 = self->vtable.h2; + self->vtable.h2 = self->vtable.h3; + self->vtable.h3 = th; uint32_t tr = self->r1; self->r1 = self->r2; @@ -425,7 +444,7 @@ cuckoo_compact (Cuckoo self) } -int +void* cuckoo_insert (Cuckoo self, void* item) { char tmp[self->itemsize]; @@ -433,30 +452,32 @@ cuckoo_insert (Cuckoo self, void* item) void* found; if ((found = cuckoo_find (self, item))) { - xmemcpy (found, item, self->itemsize); - return 1; + if (self->vtable.dtor) + self->vtable.dtor (found); + self->vtable.mov (found, item, self->itemsize); + return found; } - xmemcpy (tmp, item, self->itemsize); + self->vtable.mov (tmp, item, self->itemsize); for (unsigned n = 6; n; --n) /* rehash/grow loop */ { - if (cuckoo_insert_internal_ (self, tmp)) + if ((found = cuckoo_insert_internal_ (self, tmp))) { ++self->elements; - return 1; + return found; } if (self->elements > n*self->size) { n = 6; if (!cuckoo_grow (self)) - return 0; + return NULL; } else cuckoo_rehash (self); } - return 0; + return NULL; } @@ -465,16 +486,16 @@ cuckoo_find (Cuckoo self, void* item) { void* pos; - pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size)); - if (!iszero (pos, self->itemsize) && self->cmp (item, pos)) + pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size)); + if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos)) return pos; - pos = self->t2 + self->itemsize * (self->h2 (item, self->r2) % (2*self->size)); - if (!iszero (pos, self->itemsize) && self->cmp (item, pos)) + pos = self->t2 + self->itemsize * (self->vtable.h2 (item, self->r2) % (2*self->size)); + if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos)) return pos; - pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size); - if (!iszero (pos, self->itemsize) && self->cmp (item, pos)) + pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size); + if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos)) return pos; return NULL; @@ -486,6 +507,9 @@ cuckoo_remove (Cuckoo self, void* item) { if (item) { + if (self->vtable.dtor) + self->vtable.dtor (item); + memset (item, 0, self->itemsize); --self->elements; diff --git a/src/lib/cuckoo.h b/src/lib/cuckoo.h index 323b5cc75..84546d002 100644 --- a/src/lib/cuckoo.h +++ b/src/lib/cuckoo.h @@ -54,41 +54,61 @@ typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r); */ typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2); +/** + * Item destructor function. + * User supplied destructor function. This function is called when items are removed + * from the hash or at hash detroy/delete time. Must be safe to be called on a zeroed element. + * @param item address of the item to be destroyed + */ +typedef void (*cuckoo_dtorfunc)(void* item); + +/** + * Move function. + * User supplied item move function + * @param dest target address for the move operation + * @param src source for the move operation + * @param size size of a item (requested size rounded up to the next CUCKOO_GRANULARITY) + * It might be necessary to invalidate the source in some case, cuckoo will zero it out + * after moving. + */ +typedef void (*cuckoo_movfunc)(void* dest, void* src, size_t size); + + +/** + * Function table used to specialize various funtions used by the hash. + * TODO some elements might be NULL, then defaults are used + */ +struct cuckoo_vtable +{ + cuckoo_hashfunc h1; + cuckoo_hashfunc h2; + cuckoo_hashfunc h3; + cuckoo_cmpfunc cmp; + cuckoo_dtorfunc dtor; + cuckoo_movfunc mov; +}; + + /** * Initialize a cuckoo hash. * @param self pointer to a uninitialized cuckoo datastructure - * @param h1 hash function for the first table - * @param h2 hash function for the second table - * @param h3 hash function for the third table - * @param cmp function which compares two keys - * @param startsize initial size of table t3, as 2's exponent + * @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY + * @param vtable initialized vtable * @return The initialized hashtable or NULL at allocation failure */ Cuckoo -cuckoo_init (Cuckoo self, - cuckoo_hashfunc h1, - cuckoo_hashfunc h2, - cuckoo_hashfunc h3, - cuckoo_cmpfunc cmp, - size_t itemsize, - unsigned startsize); +cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable); /** * Allocate a new cuckoo hash. - * @param h1 hash function for the first table - * @param h2 hash function for the second table - * @param h3 hash function for the third table - * @param cmp function which compares two keys + * @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY * @param startsize initial size of table t3, as 2's exponent + * @param vtable initialized vtable * @return The initialized hashtable or NULL at allocation failure */ Cuckoo -cuckoo_new (cuckoo_hashfunc h1, - cuckoo_hashfunc h2, - cuckoo_hashfunc h3, - cuckoo_cmpfunc cmp, - size_t itemsize, - unsigned startsize); +cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable); + /** * Destroy a cuckoo hash. @@ -104,7 +124,7 @@ cuckoo_destroy (Cuckoo self); * @param self handle of the hash table to be freed */ void -cuckoo_free (Cuckoo self); +cuckoo_delete (Cuckoo self); /** * Get the number of elements stored in a hash. @@ -117,12 +137,14 @@ cuckoo_nelements (Cuckoo self); * Insert an element into a hash. * amortized O(1) complexity because it may rarely rehash the tables or even grow them. * see cuckoo_reserve() about how to preallocate entries to prevent the growing costs. + * Inserting an element already in the hash calls the dtor for the old entry and places + * the new one into the hash. * @param self handle to the hash table * @param item pointer to a item to be inserted - * @return 1 on successful insert, 0 on allocation failure + * @return pointer to inserted element on successful insert, NULL on allocation failure * Note: at failure there is one arbitary hash cell lost! */ -int +void* cuckoo_insert (Cuckoo self, void* item); /** From bc055ab803455adfdb90b319728770a3657e517f Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 2 Sep 2008 20:28:47 +0200 Subject: [PATCH 072/102] Probabilistic Splay Tree implementation Generalized an older implementation I already had, the splay formulas need some improvements. Documentation comes next. --- src/lib/Makefile.am | 2 + src/lib/psplay.c | 505 ++++++++++++++++++++++++++++++++++++ src/lib/psplay.h | 272 +++++++++++++++++++ tests/Makefile.am | 5 + tests/library/test-psplay.c | 471 +++++++++++++++++++++++++++++++++ 5 files changed, 1255 insertions(+) create mode 100644 src/lib/psplay.c create mode 100644 src/lib/psplay.h create mode 100644 tests/library/test-psplay.c diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index ca09d3e25..b372af6b7 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -30,6 +30,7 @@ liblumi_a_SOURCES = \ $(liblumi_a_srcdir)/luid.c \ $(liblumi_a_srcdir)/safeclib.c \ $(liblumi_a_srcdir)/cuckoo.c \ + $(liblumi_a_srcdir)/psplay.c \ $(liblumi_a_srcdir)/mrucache.c \ $(liblumi_a_srcdir)/time.c \ $(liblumi_a_srcdir)/appconfig.cpp @@ -43,6 +44,7 @@ noinst_HEADERS += \ $(liblumi_a_srcdir)/luid.h \ $(liblumi_a_srcdir)/safeclib.h \ $(liblumi_a_srcdir)/cuckoo.h \ + $(liblumi_a_srcdir)/psplay.h \ $(liblumi_a_srcdir)/mrucache.h \ $(liblumi_a_srcdir)/time.h \ $(liblumi_a_srcdir)/appconfig.hpp \ diff --git a/src/lib/psplay.c b/src/lib/psplay.c new file mode 100644 index 000000000..6031e3c5f --- /dev/null +++ b/src/lib/psplay.c @@ -0,0 +1,505 @@ +/* + psplay.c - probabilistic splay tree + + Copyright (C) + 2004, 2005, 2006, Christian Thaeter + Copyright (C) CinelerraCV + 2007, 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/psplay.h" + +#include +#include +#include +#include + +NOBUG_DEFINE_FLAG (psplay); + +#ifndef PSPLAY_TRAIL_DEPTH +#define PSPLAY_TRAIL_DEPTH 128 +#endif + +/* + probabilistic distribution, this are the direct splay equations used to determine if to splay + or break out of the splaying algorithm. + + useable variables/functions are: + self->log2 - log2 of the tree elements, this would be the depth of a fully balanced tree + splayfactor - user defined weigth for splaying, we define '100' to be the default + depth - depth of the current node in the tree + trail->dir - dervitation from tree center + psplay_fast_prng () - returns a prng in the range 1...2^31 +*/ + +#define PSPLAY_FORMULA (self->log2*100/(depth + (psplay_fast_prng () & 63)) + trail->dir) * splayfactor + +#ifndef PSPLAY_PROB_ZIGZIG +#define PSPLAY_PROB_ZIGZIG 5000 +#endif +#ifndef PSPLAY_PROB_ZIGZAG +#define PSPLAY_PROB_ZIGZAG 2500 +#endif + + + +/* simple prng with 2^31-1 cycle */ +static inline uint32_t psplay_fast_prng () +{ + static uint32_t rnd=0xbabeface; + return rnd = rnd<<1 ^ ((rnd >> 30) & 1) ^ ((rnd>>2) & 1); +} + + +PSplay +psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete) +{ + NOBUG_INIT_FLAG (psplay); + TRACE (psplay); + REQUIRE (cmp); + REQUIRE (key); + + if (self) + { + self->tree = NULL; + self->found_parent = &self->tree; + self->cmp = cmp; + self->key = key; + self->delete = delete; + self->elem_cnt = 0; + self->log2 = 0; + } + return self; +} + + +PSplay +psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete) +{ + PSplay self = malloc (sizeof *self); + if (self) + { + psplay_init (self , cmp, key, delete); + } + return self; +} + + + +PSplay +psplay_destroy (PSplay self) +{ + TRACE (psplay); + if (self) while (self->tree) + { + PSplaynode n = psplay_remove (self, self->tree); + if (self->delete) + self->delete (n); + } + return self; +} + + +void +psplay_delete (PSplay self) +{ + free (psplay_destroy (self)); +} + + +PSplaynode +psplaynode_init (PSplaynode self) +{ + if (self) + self->left = self->right = NULL; + return self; +} + + + +/* + Lookup operations (lookup and insert) record the path as they decend into the tree + this will allow bottom up splaying without storing 'up' pointers in the node. + The length of this trail (PSPLAY_TRAIL_DEPTH) also define the maximal limit on how much + a node can be splayed up giving some hard bound for the splay operation. + + General wisdom tells that top down splaying is more efficent to implement than bottom + up splaying. Nevertheless we do bottom up splaying here because we can decide + randomly on each level if we want to continue splaying or not. No splaying + is certainly more efficent than top-down splaying. +*/ +struct psplaytrail +{ + int dir; + unsigned depth; + PSplaynode* trail[PSPLAY_TRAIL_DEPTH]; +}; + +static inline unsigned +trailidx (unsigned n) +{ + return n & (PSPLAY_TRAIL_DEPTH-1); +} + + +static inline void +psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor) +{ + TRACE (psplay, "%p %u", self, splayfactor); + + if (trail->dir < 0) trail->dir = - trail->dir; + + for (unsigned lim = PSPLAY_TRAIL_DEPTH, depth = trail->depth; lim > 2 && depth > 2; lim-=2, depth-=2) + { + PSplaynode node = *trail->trail [trailidx (depth)]; + PSplaynode parent = *trail->trail [trailidx (depth-1)]; + PSplaynode grandparent = *trail->trail [trailidx (depth-2)]; + + unsigned r = PSPLAY_FORMULA; + TRACE (psplay, "r is %u", r); + + if (parent == grandparent->left) + { + TRACE (psplay, "ZIG.."); + if (node == parent->left) + { + TRACE (psplay, "..ZIG"); + if (r < PSPLAY_PROB_ZIGZIG) + { + TRACE (psplay, "BREAK"); + return; + } + + grandparent->left = parent->right; + parent->right = grandparent; + + parent->left = node->right; + node->right = parent; + } + else + { + TRACE (psplay, "..ZAG"); + if (r < PSPLAY_PROB_ZIGZAG) + { + TRACE (psplay, "BREAK"); + return; + } + + parent->right = node->left; + node->left = parent; + + grandparent->left = node->right; + node->right = grandparent; + } + } + else + { + TRACE (psplay, "ZAG.."); + if (node == parent->left) + { + TRACE (psplay, "..ZIG"); + if (r < PSPLAY_PROB_ZIGZAG) + { + TRACE (psplay, "BREAK"); + return; + } + + parent->left = node->right; + node->right = parent; + + grandparent->right = node->left; + node->left = grandparent; + } + else + { + TRACE (psplay, "..ZAG"); + if (r < PSPLAY_PROB_ZIGZIG) + { + TRACE (psplay, "BREAK"); + return; + } + + grandparent->right = parent->left; + parent->left = grandparent; + + parent->right = node->left; + node->left = parent; + } + } + *trail->trail [trailidx (depth-2)] = node; + } +} + + +PSplaynode +psplay_insert (PSplay self, PSplaynode node, int splayfactor) +{ + TRACE (psplay); + PSplaynode n = self->tree; + struct psplaytrail trail; + + trail.dir = 0; + trail.depth = 0; + trail.trail [0] = &self->tree; + + if (!n) + self->tree = node; + else + { + while (n != node) + { + int c; + c = self->cmp (self->key (node), self->key (n)); + ++trail.depth; + + if (c < 0) + { + --trail.dir; + if (!n->left) + n->left = node; + trail.trail [trailidx (trail.depth)] = &n->left; + n = n->left; + } + else if (c > 0) + { + ++trail.dir; + if (!n->right) + n->right = node; + trail.trail [trailidx (trail.depth)] = &n->right; + n = n->right; + } + else + { + TODO ("policy for multiple entered items (before, after, fail, replace)"); + return NULL; + } + } + } + ++self->elem_cnt; + if (self->elem_cnt >= 1<log2) ++self->log2; + if (splayfactor && trail.depth > 2) + psplay_splay (self, &trail, splayfactor); + return node; +} + + + +PSplaynode +psplay_find (PSplay self, const void* key, int splayfactor) +{ + TRACE (psplay); + PSplaynode node = self->tree; + struct psplaytrail trail; + trail.dir = 0; + trail.depth = 0; + trail.trail [0] = &self->tree; + + while (node) + { + int c; + c = self->cmp (key, self->key (node)); + ++trail.depth; + + if (c < 0) + { + --trail.dir; + trail.trail [trailidx (trail.depth)] = &node->left; + node = node->left; + } + else if (c > 0) + { + ++trail.dir; + trail.trail [trailidx (trail.depth)] = &node->right; + node = node->right; + } + else + { + self->found_parent = trail.trail [trailidx (--trail.depth)]; + break; + } + } + if (node && splayfactor && trail.depth > 2) + psplay_splay (self, &trail, splayfactor); + return node; +} + + +PSplaynode +psplay_remove (PSplay self, PSplaynode node) +{ + TRACE (psplay); + if (!node) return NULL; + + PSplaynode* r = self->found_parent; + + while (*r != node) + { + if (!psplay_find (self, self->key (node), 0)) + { + WARN (psplay, "node %p is not in splay tree %p", node, self); + return NULL; + } + r = self->found_parent; + } + + if (!node->left) + *r = node->right; + else if (!node->right) + *r = node->left; + else + { + PSplaynode i, iparent = NULL; + if (psplay_fast_prng()&1) /* 50% probability removing left or right wards */ + { + for (i = node->left; i->right; iparent = i, i = i->right); + if (iparent) + iparent->right = i->left; + if (node->left != i) + i->left = node->left; + i->right = node->right; + } + else + { + for (i = node->right; i->left; iparent = i, i = i->left); + if (iparent) + iparent->left = i->right; + if (node->right != i) + i->right = node->right; + i->left = node->left; + } + *r = i; + } + --self->elem_cnt; + if (self->elem_cnt < 1<log2) --self->log2; + return node; +} + + +PSplaynode +psplay_remove_key (PSplay self, void* key) +{ + return psplay_remove (self, psplay_find (self, key, 0)); +} + + +const psplay_delete_fn PSPLAY_CONT = (psplay_delete_fn)0x0; +const psplay_delete_fn PSPLAY_STOP = (psplay_delete_fn)0x1; +const psplay_delete_fn PSPLAY_REMOVE = (psplay_delete_fn)0x2; + +static int +psplay_handle (PSplay self, PSplaynode node, psplay_delete_fn res) +{ + if (res == PSPLAY_CONT) + return 1; + + if (res == PSPLAY_STOP) + ; + else if (res == PSPLAY_REMOVE) + { + psplay_remove (self, node); + if (self->delete) + self->delete (node); + } + else + { + psplay_remove (self, node); + res (node); + } + return 0; +} + + +int +psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data) +{ + if (!self->tree) + return 1; + + if (!node) + node = self->tree; + + psplay_delete_fn res; + + res = action (node, PSPLAY_PREORDER, level, data); + if (!psplay_handle (self, node, res)) + return 0; + + if (node->left) + if (!psplay_walk (self, node->left, action, level+1, data)) + return 0; + + res = action (node, PSPLAY_INORDER, level, data); + if (!psplay_handle (self, node, res)) + return 0; + + if (node->right) + if (!psplay_walk (self, node->right, action, level+1, data)) + return 0; + + res = action (node, PSPLAY_POSTORDER, level, data); + if (!psplay_handle (self, node, res)) + return 0; + + return 1; +} + + +static psplay_delete_fn +psplay_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data) +{ + FILE* fh = data; + static char* sp = " "; + if (level>40) + { + if (which == PSPLAY_PREORDER) + fprintf (fh, "%s ...\n", sp); + return PSPLAY_CONT; + } + + switch (which) + { + case PSPLAY_PREORDER: + fprintf (fh, "%s%p\n", sp+40-level, node); + if (node->left) + fprintf (fh, "%sleft %p\n", sp+40-level, node->left); + break; + case PSPLAY_INORDER: + if (node->right) + fprintf (fh, "%sright %p\n", sp+40-level, node->right); + break; + case PSPLAY_POSTORDER: + break; + } + + return PSPLAY_CONT; +} + +void +psplay_dump (PSplay self, FILE* dest) +{ + fprintf (dest, "root %p\n", self->tree); + psplay_walk (self, NULL, psplay_print_node, 0, dest); +} + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/psplay.h b/src/lib/psplay.h new file mode 100644 index 000000000..a2f077c61 --- /dev/null +++ b/src/lib/psplay.h @@ -0,0 +1,272 @@ +/* + psplay.h - probabilistic splay tree + + Copyright (C) + 2004, 2005, 2006, Christian Thaeter + Copyright (C) Lumiera.org + 2007, 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 PSPLAY_H +#define PSPLAY_H + +#include +#include + +/** + * @file + * Probabilistic splay trees + * A splay trees is self-optimizing (in contrast to self-balancing) datastructure. + * We introduce here a probabilistic bottom up approach which reduces the splay costs. + * Without affecting the performance. The randomization gives also some insurance that + * worst case situations are extremely unlikely. + * Tree nodes are very small (just 2 pointers) and are intrusively placed into the users + * datastructure. + */ + + +/** + * Type and handle for a psplay tree node + * This node have to be placed inside users data. + */ +typedef struct psplaynode_struct psplaynode; +typedef psplaynode* PSplaynode; +struct psplaynode_struct +{ + PSplaynode left; + PSplaynode right; +}; + + +/** + * Function use to compare keys + * @param a first key + * @param b second key + * @return shall return -1/0/1 when a is less than/equal to/biggier than b. + */ +typedef int (*psplay_cmp_fn)(const void* a, const void* b); + + +/** + * Destructor for user defined data + * Called when an element got removed from a splay tree. + * @param node pointer to the intrusive node inside the users datastructure + * The user is responsible for casting 'node' back to his real datastructure (maybe with OFFSET_OF()), + * free all resources associated with it and finally free the datastructure itself. + */ +typedef void (*psplay_delete_fn)(PSplaynode node); + + +/** + * Retrieve the key from a user datastructure + * @param node pointer to the intrusive node inside the users datastructure + * This functiom must return a pointer to the key under which the user stores his data. + */ +typedef const void* (*psplay_key_fn)(const PSplaynode node); + + +/** + * Type and handle for a psplay root structure + * This structure shall be treated opaque, its only defined in the header to allow + * one to integrate it directly instead referencing it. + */ +typedef struct psplay_struct psplay; +typedef psplay* PSplay; + +struct psplay_struct +{ + PSplaynode tree; /* the tree */ + PSplaynode* found_parent; /* maybe direct parent of last found node, used for fast remove */ + psplay_cmp_fn cmp; + psplay_key_fn key; + psplay_delete_fn delete; + + size_t elem_cnt; + unsigned log2; /* roughly log2 of the elem_cnt*/ +}; + + +/** + * Number of elements in tree + * @param self pointer to the tree + * @return number of elements + */ +static inline size_t +psplay_nelements (PSplay self) +{ + return self->elem_cnt; +}; + + +/** + * Initialize a splay tree + * @param self pointer to the psplay structure + * @param cmp user supplied compare function + * @param key user supplied function to retrieve a key + * @param delete user supplied destructor function or NULL if no destructor is necessary + * @return self + */ +PSplay +psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete); + + +/** + * Destroy a splay tree + * Frees all elements and associated resources of a splay tree + * @param self pointer to the psplay structure + * @return self + */ +PSplay +psplay_destroy (PSplay self); + +/** + * Allocate a splay tree + * @param cmp user supplied compare function + * @param key user supplied function to retrieve a key + * @param delete user supplied destructor function or NULL if no destructor is necessary + * @return allcoated splay tree or NULL on error + */ +PSplay +psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete); + + +/** + * Delete a splay tree + * Frees all elements and associated resources of a splay tree and then itseld + * @param self pointer to the psplay structure + */ +void +psplay_delete (PSplay self); + + +/** + * Initialize a splay tree node + * The user has to place this nodes within his datastructure and must + * initialize them before using them. + * @param self pointer to the node to be initialized + * @return self + */ +PSplaynode +psplaynode_init (PSplaynode self); + + +/** + * Insert a element into a splay tree + * @param self pointer to the splay tree + * @param node pointer to the node to be inserted + * @param splayfactor weight for the probabilistic splaying, + * 0 disables the splaying, 100 is the expected normal value + * use 100 when in doubt + * @return self or NULL when a node with same key already in the tree + */ +PSplaynode +psplay_insert (PSplay self, PSplaynode node, int splayfactor); + + +/** + * Find a element in a splay tree + * @param self pointer to the splay tree + * @param key pointer to the key to be searched + * @param splayfactor weight for the probabilistic splaying, + * 0 disables the splaying, 100 is the expected normal value + * @return found node or NULL if the key was not found in the tree + */ +PSplaynode +psplay_find (PSplay self, const void* key, int splayfactor); + + +/** + * Remove a node from a splay tree + * @param self pointer to the splay tree + * @param node node to be removed + * @return pointer to the removed node + * removal is optimized for the case where one call it immediately after one did a + * psplay_find() as last operation on that tree + */ +PSplaynode +psplay_remove (PSplay self, PSplaynode node); + + +/** + * Remove a node by key from a splay tree + * @param self pointer to the splay tree + * @param key key of the node to be removed + * @return pointer to the removed node + */ +PSplaynode +psplay_remove_key (PSplay self, void* key); + + +enum psplay_order_enum + { + PSPLAY_PREORDER, + PSPLAY_INORDER, + PSPLAY_POSTORDER + }; + +/** + * Traverse a splay tree + * Traversing a tree calls a user supplied action three times + * An 'action' must not alter the tree itself but it can indicate aborting the tree traversal and + * how the current node is handled by its return value. + * @param node pointer to the currently traversed node + * @param which state of the traversal: + * PSPLAY_PREORDER before visiting the left subtree, + * PSPLAY_INORDER after visiting the left subtree and before the right subtree + * PSPLAY_POSTORDER finally after visiting the right subtree. + * Example: For to traverse the tree in order action would only handle PSPLAY_INORDER. + * This action shall return PSPLAY_CONT when the traversal of the tree shall continue. + * @param level depth of the node in the tree + * @param data user supplied data which is transparently passed around + * @return a pointer to a function which indicates how to proceed, there are three special + * return values predefined: + * PSPLAY_CONT - continue with the traversal + * PSPLAY_STOP - stop the traversal + * PSPLAY_REMOVE - stops the traversal and removes the current node, calling the delete handler + * any other psplay_delete_fn - stops the traversal and removes the current node, calling the returned delete handler with it + */ +typedef psplay_delete_fn (*psplay_action_fn)(PSplaynode node, const enum psplay_order_enum which, int level, void* data); + +extern const psplay_delete_fn PSPLAY_CONT; +extern const psplay_delete_fn PSPLAY_STOP; +extern const psplay_delete_fn PSPLAY_REMOVE; + +/** + * Start a tree traversal + * @param self the tree to be traversed + * @param node pointer to root node where traversal shall start, use NULL for the whole tree + * @param action handler function as defined above + * @param level initial value for the level + * @param data user supplied data which is transparently passed to the action + * @return 0 when the tree traversal got aborted (by anything but PSPLAY_CONT as action handler return) + * 1 when the whole tree was traversed successfully + */ +int +psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data); + + +void +psplay_dump (PSplay self, FILE* dest); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/tests/Makefile.am b/tests/Makefile.am index af3e9f829..1231573d9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,6 +33,11 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ test_llist_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm +check_PROGRAMS += test-psplay +test_psplay_SOURCES = $(tests_srcdir)/library/test-psplay.c +test_psplay_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_psplay_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm + check_PROGRAMS += test-safeclib test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ diff --git a/tests/library/test-psplay.c b/tests/library/test-psplay.c new file mode 100644 index 000000000..f7989bae7 --- /dev/null +++ b/tests/library/test-psplay.c @@ -0,0 +1,471 @@ +/* + test-psplay.c - test the probanilistic splay tree + + 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 +#include + +#include "lib/psplay.h" +#include "tests/test.h" + +struct testitem +{ + psplaynode node; + char* key; +}; +typedef struct testitem* TestItem; + +TestItem +testitem_new (const char* str) +{ + TestItem self = malloc (sizeof *self); + psplaynode_init (&self->node); + self->key = strdup (str); + return self; +} + +void +testitem_delete (TestItem self) +{ + free (self->key); + free (self); +} + + + +static int +cmp_fn (const void*, const void*); + +static const void* +key_fn (const PSplaynode); + +static void +delete_fn (PSplaynode); + +//static psplay_delete_fn +//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data); + +static int +fcmp_fn (const void*, const void*); + +static const void* +fkey_fn (const PSplaynode); + +static void +fdelete_fn (PSplaynode); + +//static psplay_delete_fn +//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data); + + +psplay_delete_fn +testitem_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data) +{ + FILE* fh = data; + static char* sp = " "; + if (level>40) + { + if (which == PSPLAY_PREORDER) + fprintf (fh, "%s ...\n", sp); + return PSPLAY_CONT; + } + + switch (which) + { + case PSPLAY_PREORDER: + fprintf (fh, "%s%p '%s'\n", sp+40-level, node, ((TestItem)node)->key); + if (node->left) fprintf (fh, "%sleft %p '%s'\n", sp+40-level, node->left, ((TestItem)node->left)->key); + break; + case PSPLAY_INORDER: + if (node->right) fprintf (fh, "%sright %p '%s'\n", sp+40-level, node->right, ((TestItem)node->right)->key); + break; + case PSPLAY_POSTORDER: + break; + } + + return PSPLAY_CONT; +} + +void +testitem_dump (PSplay self, FILE* dest) +{ + fprintf (dest, "root %p '%s'\n", self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY"); + psplay_walk (self, NULL, testitem_print_node, 0, dest); + fprintf (dest, "\n"); +} + +psplay_delete_fn +testitem_graphvizprint_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data) +{ + FILE* fh = data; + + switch (which) + { + case PSPLAY_PREORDER: + if (node->left) + fprintf (fh, "\t\"%p:%s\":sw -> \"%p:%s\":ne;\n", + node, + ((TestItem)node)->key, + node->left, + ((TestItem)node->left)->key); + break; + case PSPLAY_INORDER: + if (node->right) + fprintf (fh, "\t\"%p:%s\":se -> \"%p:%s\":nw;\n", + node, + ((TestItem)node)->key, + node->right, + ((TestItem)node->right)->key); + break; + case PSPLAY_POSTORDER: + break; + } + + return PSPLAY_CONT; +} + + + +void +testitem_graphvizdump (PSplay self, FILE* dest) +{ + static int cnt = 0; + if (!cnt) cnt = (time(NULL) % 1000) * 100; + char cmd[256]; + + sprintf(cmd,"dot -Tps >/var/tmp/dbg%d.ps; gv /var/tmp/dbg%d.ps",cnt,cnt); + FILE * graph = popen(cmd, "w"); + + fprintf(graph, "digraph \"%s\" { center=true; size=\"6,6\"; node [color=lightblue2, style=filled];", "psplay"); + ++cnt; + + fprintf(graph, "\t\"root\":s -> \"%p:%s\":n;\n", + self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY"); + + psplay_walk (self, NULL, testitem_graphvizprint_node, 0, graph); + + fprintf(graph, "}"); + + pclose(graph); +} + + + +TESTS_BEGIN + +TEST ("basic") +{ + psplay splay_tree; + psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn); + + psplay_dump (&splay_tree, stdout); + + psplay_destroy (&splay_tree); +} + + +TEST ("basic_insert_dump") +{ + REQUIRE (argv[2]); + + psplay splay_tree; + psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn); + + int end = atoi (argv[2]); + + char key[1024]; + + for (int i = 1; i <= end; ++i) + { + sprintf (key, "%d", i); + TRACE (tests, "insert %s", key); + psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100); + } + + psplay_dump (&splay_tree, stderr); + +#if 0 + for (int i = 1; i <= end; ++i) + { + sprintf (key, "%d", i); + TRACE (tests, "insert %s", key); + psplay_remove_key (&splay_tree, key); + psplay_dump (&splay_tree, stderr); + } + for (int i = end; i; --i) + { + sprintf (key, "%d", i); + TRACE (tests, "insert %s", key); + psplay_remove_key (&splay_tree, key); + psplay_dump (&splay_tree, stderr); + } +#endif + + psplay_destroy (&splay_tree); + printf ("done\n"); +} + + +TEST ("insert_find") +{ + psplay splay_tree; + psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn); + + psplay_insert (&splay_tree, (PSplaynode)testitem_new ("foo"), 100); + psplay_insert (&splay_tree, (PSplaynode)testitem_new ("bar"), 100); + psplay_insert (&splay_tree, (PSplaynode)testitem_new ("baz"), 100); + psplay_insert (&splay_tree, (PSplaynode)testitem_new ("test"), 100); + psplay_insert (&splay_tree, (PSplaynode)testitem_new ("pap"), 100); + psplay_insert (&splay_tree, (PSplaynode)testitem_new ("qux"), 100); + + testitem_graphvizdump (&splay_tree, stdout); + psplay_dump (&splay_tree, stdout); + + //TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100); + TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100); + ENSURE (f); + printf ("found %p (%.4s)\n", &f->node, f->key); + psplay_dump (&splay_tree, stdout); + + f = (TestItem) psplay_find (&splay_tree, "test", 100); + ENSURE (f); + printf ("found %p (%.4s)\n", &f->node, f->key); + psplay_dump (&splay_tree, stdout); + + f = (TestItem) psplay_find (&splay_tree, "test", 100); + ENSURE (f); + printf ("found %p (%.4s)\n", &f->node, f->key); + psplay_dump (&splay_tree, stdout); + + f = (TestItem) psplay_find (&splay_tree, "foo", 100); + ENSURE (f); + printf ("found %p (%.4s)\n", &f->node, f->key); + psplay_dump (&splay_tree, stdout); + +#if 0 + psplay_delete (psplay_remove (&splay_tree, root.tree)); + psplay_dump (&splay_tree, stdout); + + psplay_delete (psplay_remove (&splay_tree, root.tree)); + psplay_dump (&splay_tree, stdout); + + psplay_delete (psplay_remove (&splay_tree, root.tree)); + psplay_dump (&splay_tree, stdout); +#endif + printf ("destroying\n"); + psplay_destroy (&splay_tree); + psplay_dump (&splay_tree, stdout); +#if 0 + psplay_delete (psplay_remove (&splay_tree, root.tree)); + psplay_dump (&splay_tree, stdout); + + psplay_delete (psplay_remove (&splay_tree, root.tree)); + psplay_dump (&splay_tree, stdout); + + psplay_delete (psplay_remove (&splay_tree, root.tree)); + psplay_dump (&splay_tree, stdout); +#endif + return 0; +} + +TEST ("basic_insert_splay") +{ + REQUIRE (argv[2]); + + psplay splay_tree; + psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn); + + int end = atoi (argv[2]); + + char key[1024]; + + for (int i = 1; i <= end; ++i) + { + sprintf (key, "%d", i); + TRACE (tests, "insert %s", key); + psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100); + } + + for (int i = end/2; i <= end; ++i) + { + psplay_dump (&splay_tree, stderr); + sprintf (key, "%d", i); + psplay_find (&splay_tree, key, 100); + } + psplay_destroy (&splay_tree); + printf ("done\n"); +} + + +TEST ("basic_rand_insert_dump") +{ + REQUIRE (argv[2]); + + psplay splay_tree; + psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn); + + int end = atoi (argv[2]); + + char key[1024]; + + for (int i = 1; i <= end; ++i) + { + sprintf (key, "%d", i /*rand()*/); + psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100); + } + + testitem_graphvizdump (&splay_tree, stdout); + //testitem_dump (&splay_tree, stdout); + + psplay_destroy (&splay_tree); + printf ("done\n"); +} + + +TEST ("fast_insert") +{ + REQUIRE (argv[2]); + + psplay splay_tree; + psplay_init (&splay_tree, fcmp_fn, fkey_fn, fdelete_fn); + + int end = atoi (argv[2]); + + char key[1024]; + + for (int i = 1; i <= end; ++i) + { + sprintf (key, "%d", i); + psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100); + } + + psplay_destroy (&splay_tree); + printf ("done\n"); +} + + + + +TEST ("nonexistant") +{ + REQUIRE (argv[2]); + +} + + +TEST ("insert") +{ + REQUIRE (argv[2]); + +} + + + +TEST ("insert_rand") +{ + REQUIRE (argv[2]); + +} + + + +TEST ("insert_fastcheck") +{ + REQUIRE (argv[2]); + +} + + + +TESTS_END + + + + +/* + cuckoo support functions +*/ + +static int +cmp_fn (const void* a, const void* b) +{ + REQUIRE (a); + REQUIRE (b); + return strcmp (a, b); +} + +static const void* +key_fn (const PSplaynode node) +{ + REQUIRE (node); + REQUIRE (((TestItem)node)->key); + + return ((TestItem)node)->key; +} + +static void +delete_fn (PSplaynode node) +{ + REQUIRE (node); + testitem_delete ((TestItem) node); +} + + +//static psplay_delete_fn +//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data) +//{ +//} + + +static int +fcmp_fn (const void* a, const void* b) +{ + return strcmp (a, b); +} + +static const void* +fkey_fn (const PSplaynode node) +{ + return ((TestItem)node)->key; +} + +static void +fdelete_fn (PSplaynode node) +{ + testitem_delete ((TestItem) node); +} + +//static psplay_delete_fn +//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data) +//{ +//} + + + + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From 86deb4e72dd0dae41721e422789376da560c7f08 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 2 Sep 2008 20:28:47 +0200 Subject: [PATCH 073/102] Probabilistic Splay Tree implementation Generalized an older implementation I already had, the splay formulas need some improvements. Documentation comes next. --- src/lib/psplay.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/lib/psplay.h b/src/lib/psplay.h index a2f077c61..26639910a 100644 --- a/src/lib/psplay.h +++ b/src/lib/psplay.h @@ -211,6 +211,26 @@ PSplaynode psplay_remove_key (PSplay self, void* key); +/** + * Delete a node from a splay tree + * @param self pointer to the splay tree + * @param node node to be removed + * Calls the registered delete handler, frees all resources. + */ +void +psplay_delete_node (PSplay self, PSplaynode node); + + +/** + * Delete a node by key from a splay tree + * @param self pointer to the splay tree + * @param key key of the node to be removed + * Calls the registered delete handler, frees all resources. + */ +void +psplay_delete_key (PSplay self, void* key); + + enum psplay_order_enum { PSPLAY_PREORDER, From dc34ea994c77c021940004d6296d89f21b5f82b8 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 6 Sep 2008 06:20:50 +0200 Subject: [PATCH 074/102] add psplay_delete_node and psplay_delete_key functions Both delete a entry from a splay tree by calling the registered delete handler. --- src/lib/psplay.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib/psplay.c b/src/lib/psplay.c index 6031e3c5f..7647fd905 100644 --- a/src/lib/psplay.c +++ b/src/lib/psplay.c @@ -396,6 +396,23 @@ psplay_remove_key (PSplay self, void* key) } +void +psplay_delete_node (PSplay self, PSplaynode node) +{ + if (node) + self->delete (psplay_remove (self, node)); +} + + +void +psplay_delete_key (PSplay self, void* key) +{ + PSplaynode node = psplay_find (self, key, 0); + psplay_delete_node (self, node); +} + + + const psplay_delete_fn PSPLAY_CONT = (psplay_delete_fn)0x0; const psplay_delete_fn PSPLAY_STOP = (psplay_delete_fn)0x1; const psplay_delete_fn PSPLAY_REMOVE = (psplay_delete_fn)0x2; From d8c0c33eb01a0a1d8665ebc469df48d014d7bc1a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 3 Sep 2008 08:05:22 +0200 Subject: [PATCH 075/102] test.h cosmetic, add a 'tests' nobug flag, give diagnostics --- tests/test.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/test.h b/tests/test.h index d25fa0a59..060d007fc 100644 --- a/tests/test.h +++ b/tests/test.h @@ -26,6 +26,9 @@ #include "lib/error.h" +#include + +NOBUG_DEFINE_FLAG (tests); LUMIERA_ERROR_DEFINE (TEST, "test error"); #define TESTS_BEGIN \ @@ -33,20 +36,35 @@ int \ main (int argc, char** argv) \ { \ NOBUG_INIT; \ + NOBUG_INIT_FLAG (tests); \ \ if (argc == 1) \ - return 1; + { \ + fprintf (stderr, "missing argument\n"); \ + return 1; \ + } -#define TEST(name) \ +#define TEST(name) \ else if (!strcmp(argv[1], name)) #define TESTS_END \ else \ - return 1; \ + { \ + fprintf (stderr, "unknown test\n"); \ + return 1; \ + } \ \ return 0; \ } #endif + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From 79fee295192018d34ab5761d689e8b1b1fe24f47 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 6 Sep 2008 11:44:08 +0200 Subject: [PATCH 076/102] small note annd cosmetics for safeclib --- src/lib/safeclib.c | 1 + src/lib/safeclib.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/lib/safeclib.c b/src/lib/safeclib.c index 0f61a7a92..1c5cf28c6 100644 --- a/src/lib/safeclib.c +++ b/src/lib/safeclib.c @@ -103,6 +103,7 @@ static void lumiera_tmpbuf_init (void) { pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy); + TODO ("register an atexit() handler to free tmpbufs"); } diff --git a/src/lib/safeclib.h b/src/lib/safeclib.h index d5b7eb0a8..79f10d024 100644 --- a/src/lib/safeclib.h +++ b/src/lib/safeclib.h @@ -135,6 +135,7 @@ lumiera_tmpbuf_strndup (const char* src, size_t size); char* lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...); + /** * Concat up to 3 strings in a tmpbuf. * @param str1 first string to concat or NULL From b594ffb3c502efeaebb236f92cc3ab30e76f1e09 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 6 Sep 2008 11:49:44 +0200 Subject: [PATCH 077/102] Doxyfile update new doxwizard insisted to add some new config vars, so let it be. --- doc/devel/Doxyfile | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/doc/devel/Doxyfile b/doc/devel/Doxyfile index b7c59fa54..f43b69042 100644 --- a/doc/devel/Doxyfile +++ b/doc/devel/Doxyfile @@ -1,11 +1,11 @@ -# Doxyfile 1.5.5 +# Doxyfile 1.5.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = Lumiera -PROJECT_NUMBER = 0.1+pre +PROJECT_NUMBER = 3.0+alpha OUTPUT_DIRECTORY = CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English @@ -32,7 +32,7 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = YES +DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 @@ -44,6 +44,7 @@ OPTIMIZE_OUTPUT_VHDL = NO BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO @@ -65,8 +66,8 @@ CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES -SORT_MEMBER_DOCS = NO -SORT_BRIEF_DOCS = NO +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = YES SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES @@ -77,6 +78,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages @@ -87,7 +90,7 @@ WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = warnings.txt +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- @@ -179,18 +182,20 @@ HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Lumiera Doxygen docs" +DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project HTML_DYNAMIC_SECTIONS = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO +CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = YES TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- @@ -268,6 +273,8 @@ CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES +DOT_FONTNAME = FreeSans +DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES From 1f8906a2d88e1425bd5418f11b235345620e71fc Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 10 Aug 2008 19:38:31 +0200 Subject: [PATCH 078/102] More mockup of the configitem bootstrap * started low-level parser * give the charsets for config keys some constants --- src/backend/config.c | 6 +- src/backend/config.h | 2 + src/backend/configentry.c | 74 +++++++++++ src/backend/configentry.h | 67 ++++++++++ src/backend/configitem.c | 258 ++++++++++++++++++++++++++++++++++++++ src/backend/configitem.h | 136 ++++++++++++++++++++ 6 files changed, 540 insertions(+), 3 deletions(-) create mode 100644 src/backend/configentry.c create mode 100644 src/backend/configentry.h create mode 100644 src/backend/configitem.c create mode 100644 src/backend/configitem.h diff --git a/src/backend/config.c b/src/backend/config.c index 1bf30b245..db8d929a7 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -127,11 +127,11 @@ lumiera_config_get (const char* key, const char** value) int ret = -1; - /* we translate the key for the env var override by making it uppercase and replace . and - with _, + /* we translate the key for the env var override by making it uppercase and replace . with _, as side effect, this also checks the key syntax */ char* tr_key = lumiera_tmpbuf_tr (key, - "abcdefghijklmnopqrstuvwxyz0123456789_.", - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__", + LUMIERA_CONFIG_KEY_CHARS, + LUMIERA_CONFIG_ENV_CHARS, NULL); if (!tr_key) { diff --git a/src/backend/config.h b/src/backend/config.h index 38ffce9e2..27d14980b 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -58,6 +58,8 @@ LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader */ +#define LUMIERA_CONFIG_KEY_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_." +#define LUMIERA_CONFIG_ENV_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__" struct lumiera_config_struct { diff --git a/src/backend/configentry.c b/src/backend/configentry.c new file mode 100644 index 000000000..e2c846b12 --- /dev/null +++ b/src/backend/configentry.c @@ -0,0 +1,74 @@ +/* + configentry.c - single entries from configfiles + + 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/safeclib.h" + +//TODO: Lumiera header includes// +#include "backend/configentry.h" + +//TODO: internal/static forward declarations// + + +//TODO: System includes// + + +/** + * @file + * + */ + +//code goes here// +LumieraConfigitem +lumiera_configentry_new (LumieraConfigitem tmp) +{ + LumieraConfigentry self = lumiera_malloc (sizeof (*self)); + lumiera_configitem_move ((LumieraConfigitem)self, tmp); + + TODO ("initialize other stuff here (lookup, parent, ...)"); + + return (LumieraConfigitem)self; +} + + +LumieraConfigitem +lumiera_configentry_destroy (LumieraConfigitem self) +{ + TODO ("cleanup other stuff here (lookup, parent, ...)"); + + return self; +} + +struct lumiera_configitem_vtable lumiera_configentry_funcs = + { + .new = lumiera_configentry_new, + .destroy = lumiera_configentry_destroy + }; + + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/configentry.h b/src/backend/configentry.h new file mode 100644 index 000000000..61f5f5f73 --- /dev/null +++ b/src/backend/configentry.h @@ -0,0 +1,67 @@ +/* + configentry.h - single entries from configfiles + + 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_CONFIGENTRY_H +#define LUMIERA_CONFIGENTRY_H + +//TODO: Support library includes// + + +//TODO: Forward declarations// +typedef struct lumiera_configentry_struct lumiera_configentry; +typedef lumiera_configentry* LumieraConfigentry; + + +//TODO: Lumiera header includes// +#include "backend/configitem.h" + +//TODO: System includes// +#include + + +/** + * @file + */ + +//TODO: declarations go here// +struct lumiera_configentry_struct +{ + lumiera_configitem entry; +}; + +extern struct lumiera_configitem_vtable lumiera_configentry_funcs; + + +LumieraConfigitem +lumiera_configentry_new (LumieraConfigitem tmp); + + +LumieraConfigitem +lumiera_configentry_destroy (LumieraConfigitem self); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/configitem.c b/src/backend/configitem.c new file mode 100644 index 000000000..a715ca99b --- /dev/null +++ b/src/backend/configitem.c @@ -0,0 +1,258 @@ +/* + configitem.c - generalized hierachy of configuration items + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + Simeon Voelkel + + 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/llist.h" +#include "lib/safeclib.h" + + +//TODO: Lumiera header includes// +#include "backend/config.h" +#include "backend/configitem.h" +#include "backend/configentry.h" + +//TODO: internal/static forward declarations// + + +//TODO: System includes// +#include + +/** + * @file + * + */ + + +//code goes here// + +LumieraConfigitem +lumiera_configitem_init (LumieraConfigitem self) +{ + TRACE (config_item); + REQUIRE (self); + + llist_init (&self->link); + self->parent = NULL; + llist_init (&self->childs); + + llist_init (&self->lookup); + + self->line = NULL; + + self->key = NULL; + self->key_size = 0; + self->delim = NULL; + self->vtable = NULL; + + return self; +} + +LumieraConfigitem +lumiera_configitem_destroy (LumieraConfigitem self) +{ + TRACE (config_item); + + if (self) + { + if (self->vtable && self->vtable->destroy) + self->vtable->destroy (self); + + ENSURE (!llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); + ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); + + llist_unlink (&self->link); + lumiera_free (self->line); + } + + return self; +} + + +LumieraConfigitem +lumiera_configitem_new (const char* line) +{ + TRACE (config_item); + + lumiera_configitem tmp; + lumiera_configitem_init (&tmp); + + lumiera_configitem_parse (&tmp, line); + + LumieraConfigitem self = tmp.vtable && tmp.vtable->new + ? tmp.vtable->new (&tmp) + : lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp); + + return self; +} + + +void +lumiera_configitem_delete (LumieraConfigitem self) +{ + TRACE (config_item); + lumiera_free (lumiera_configitem_destroy (self)); +} + + + +LumieraConfigitem +lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) +{ + TRACE (config_item); + REQUIRE (self); + REQUIRE (source); + + llist_move (&self->link, &source->link); + + self->parent = source->parent; + + llist_move (&self->childs, &source->childs); + llist_move (&self->lookup, &source->lookup); + + self->line = source->line; + source->line = NULL; + + self->key = source->key; + self->key_size = source->key_size; + self->delim = source->delim; + self->vtable = source->vtable; + return self; +} + + +LumieraConfigitem +lumiera_configitem_parse (LumieraConfigitem self, const char* line) +{ + TRACE (config_item); + + self->line = lumiera_strndup (line, SIZE_MAX); + + FIXME ("MOCKUP START"); + + TODO ("parsing here"); + /* + HOWTO parse (for simav) + in self->line liegt jetzt der 'rohe' string + + parsen setzt folgende werte in self: .key, .key_size, .delim und vtable. den rest macht dann die 'new' funktion aus der vtable + + es geht jetzt da drum rauszufinden ob diese zeile einses der folgenden sachen ist: + (ich zeig hier nur die grundsyntax, das parsen sollte auch entartete situationen behandeln, insbesondere leerzeichen/tabulatoren an allen moeglichen stellen) + auserdem sollt hier alles soweit wie moeglich validiert werden z.b. keys auf erlaubte zeichen gescheckt (siehe die _tr function) + + section: + '[prefix suffix]' + .key == prefix + .delim == das leerzeichen (oder tab) vor suffix oder aufs abschliessende ] wenn kein suffix + + kommentar: + leere zeile, zeile nur aus leerzeichen und tabulatoren, leerzeichen und tabulatoren gefolgt von # bis zum zeilenende + alles ausser vtable auf NULL + + direktive: + '@direktive argumente' + .key == @ + .delim == leerzeichen oder tab vor argumente, NULL wenn keine argumente + + configentry: + 'key = value' + .key == key begin + .delim == '=' + 'key < redirect' + .key == key begin + .delim == '>' + + */ + /* + * What should be working (for cehteh) or not yet.. + * + * die Elemente sollten bereits richtig unterschieden werden, die {} sind noch zu füllen. + * + * TODO: include für verwendete Funkionen wie strlen und isspace + * + * */ + + char* itr = self->line; + + /*skip leading whitespaces*/ + while (*itr && isspace (*itr)) + itr++; + + /*decide what this line represents*/ + if (!*itr || *itr == '#' ) + { + /*this is an empty line or a a comment*/ + } + else if (*itr == '@' ) + { + /*this is a directive*/ + } + else if (*itr == '[' ) + { + /*this is a section*/ + } + else + { + /*this is a probably configentry*/ + + /*itr points now to the first not-whitespace-character*/ + self->key = itr; + + /*now look for the end of the key and set the keysize*/ + self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); + + TODO ("if(self->keysize==0) then key_syntax_error"); + + /* skip blanks */ + itr += self->key_size; + while (*itr && isspace(*itr)) + itr++; + + if (*itr == '=') + { + self->delim = itr; + } + else if (*itr == '<') + { + self->delim = itr; + } + else + TODO ("syntax error"); + + /* TODO only if still everything ok */ + self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry + + } + + + + return self; +} + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/configitem.h b/src/backend/configitem.h new file mode 100644 index 000000000..c2b0bea92 --- /dev/null +++ b/src/backend/configitem.h @@ -0,0 +1,136 @@ +/* + configitem.h - generalized hierachy of configuration items + + 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_CONFIGITEM_H +#define LUMIERA_CONFIGITEM_H + +//TODO: Support library includes// +#include "lib/llist.h" + + +//TODO: Forward declarations// +typedef struct lumiera_configitem_struct lumiera_configitem; +typedef lumiera_configitem* LumieraConfigitem; + +struct lumiera_configitem_vtable; + +//TODO: Lumiera header includes// + + +//TODO: System includes// +#include + + +/** + * @file + * configitems build a 3 level hierachy: + * + * 1. file: + * contain sections + * + * 2. section: + * [prefix suffix] + * contain lines + * + * 3. lines are + * comment: + * empty line or line only containing spaces and tabs + * line starting with spaces and tabs followed by a # + * directive: + * '@include name' or '@readonly' + * directives are only valid at the toplevel section [] + * configurationentry: + * 'key = value' or 'key < redirect' + */ + + +//TODO: declarations go here// +/** + * @file + * configitems build a 3 level hierachy: + * + * 1. file: + * contain sections + * + * 2. section: + * [prefix suffix] + * contain lines + * + * 3. lines are + * comment: + * empty line or line only containing spaces and tabs + * line starting with spaces and tabs followed by a # + * directive: + * '@include name' or '@readonly' + * directives are only valid at the toplevel section [] + * configurationentry: + * 'key = value' or 'key < redirect' + * errorneous: + * any line which cant be parsed + */ + +struct lumiera_configitem_vtable +{ + LumieraConfigitem (*new)(LumieraConfigitem); + LumieraConfigitem (*destroy)(LumieraConfigitem); +}; + +struct lumiera_configitem_struct +{ + llist link; // all lines on the same hierachy level are linked here (see childs) + LumieraConfigitem parent; // parent section + llist childs; // root node for all lines below this hierachy + + llist lookup; // all lines with the same key are stacked up on the loockup + + char* line; // raw line as read in allocated here trailing \n will be replaced with \0 + char* key; // pointer into line to start of key + size_t key_size; + char* delim; // delimiter, value starts at delim+1 + struct lumiera_configitem_vtable* vtable; // functiontable for subclassing +}; + +LumieraConfigitem +lumiera_configitem_init (LumieraConfigitem self); + +LumieraConfigitem +lumiera_configitem_destroy (LumieraConfigitem self); + +LumieraConfigitem +lumiera_configitem_new (const char* line); + +void +lumiera_configitem_delete (LumieraConfigitem self); + +LumieraConfigitem +lumiera_configitem_parse (LumieraConfigitem self, const char* line); + +LumieraConfigitem +lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem dest); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From a51f61683f9e22a533d6395ff6970d8c73bb2311 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 08:13:15 +0200 Subject: [PATCH 079/102] add configitem and configentry to the build system --- src/backend/Makefile.am | 8 ++++++-- src/backend/config.c | 2 ++ src/backend/config.h | 2 ++ src/backend/config_typed.c | 2 +- src/backend/configitem.c | 4 +--- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 34d48c9ed..afe7cc1f3 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -29,7 +29,9 @@ liblumibackend_a_SOURCES = \ $(liblumibackend_a_srcdir)/filedescriptor.c \ $(liblumibackend_a_srcdir)/filehandlecache.c \ $(liblumibackend_a_srcdir)/config.c \ - $(liblumibackend_a_srcdir)/config_typed.c + $(liblumibackend_a_srcdir)/config_typed.c \ + $(liblumibackend_a_srcdir)/configentry.c \ + $(liblumibackend_a_srcdir)/configitem.c noinst_HEADERS += \ @@ -39,5 +41,7 @@ noinst_HEADERS += \ $(liblumibackend_a_srcdir)/filehandle.h \ $(liblumibackend_a_srcdir)/filedescriptor.h \ $(liblumibackend_a_srcdir)/filehandlecache.h \ - $(liblumibackend_a_srcdir)/config.h + $(liblumibackend_a_srcdir)/config.h \ + $(liblumibackend_a_srcdir)/configentry.h \ + $(liblumibackend_a_srcdir)/configitem.h diff --git a/src/backend/config.c b/src/backend/config.c index db8d929a7..deec72697 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -42,6 +42,7 @@ NOBUG_DEFINE_FLAG_PARENT (config_all, backend); NOBUG_DEFINE_FLAG_PARENT (config, config_all); NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); +NOBUG_DEFINE_FLAG_PARENT (config_item, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile"); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key"); @@ -65,6 +66,7 @@ lumiera_config_init (const char* path) NOBUG_INIT_FLAG (config); NOBUG_INIT_FLAG (config_typed); NOBUG_INIT_FLAG (config_file); + NOBUG_INIT_FLAG (config_item); lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); diff --git a/src/backend/config.h b/src/backend/config.h index 27d14980b..1daf54087 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -38,6 +38,8 @@ NOBUG_DECLARE_FLAG (config); NOBUG_DECLARE_FLAG (config_typed); /* file operations */ NOBUG_DECLARE_FLAG (config_file); +/* single config items */ +NOBUG_DECLARE_FLAG (config_item); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index a8c18ad15..78f2e8cd7 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -157,7 +157,7 @@ scan_string (const char* in) if (end) { - ret = lumiera_tmpbuf_strndup (in, end-in); + ret = lumiera_tmpbuf_strndup (in, end - in); /* replace double quote chars with single one */ char* wpos; diff --git a/src/backend/configitem.c b/src/backend/configitem.c index a715ca99b..bf413e7e5 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -187,8 +187,6 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) * * die Elemente sollten bereits richtig unterschieden werden, die {} sind noch zu füllen. * - * TODO: include für verwendete Funkionen wie strlen und isspace - * * */ char* itr = self->line; @@ -212,7 +210,7 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) } else { - /*this is a probably configentry*/ + /*this is probably a configentry*/ /*itr points now to the first not-whitespace-character*/ self->key = itr; From 1a66b58fcb15dfecb3665a9abb3f6317fd237cc8 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Tue, 12 Aug 2008 10:29:05 +0200 Subject: [PATCH 080/102] added CONFIG_SYNTAX errors --- src/backend/configitem.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index bf413e7e5..075304c37 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -190,6 +190,7 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) * */ char* itr = self->line; + bool faultless = true; /*skip leading whitespaces*/ while (*itr && isspace (*itr)) @@ -199,6 +200,9 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) if (!*itr || *itr == '#' ) { /*this is an empty line or a a comment*/ + self->key = NULL; + self->keysize = 0; + self->delim = NULL; } else if (*itr == '@' ) { @@ -218,7 +222,17 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) /*now look for the end of the key and set the keysize*/ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); - TODO ("if(self->keysize==0) then key_syntax_error"); + if ( self->keysize==0 ) + { + /*Obviously a malformed "key"; treat this line like a comment*/ + self->key = NULL; + self->keysize = 0; + self->delim = NULL; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + + faultless = false; + } /* skip blanks */ itr += self->key_size; @@ -234,10 +248,21 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) self->delim = itr; } else - TODO ("syntax error"); + { + /*this is not a valid configentry; treat this line like a comment*/ + self->key = NULL; + self->keysize = 0; + self->delim = NULL; - /* TODO only if still everything ok */ - self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + faultless = false; + } + + /*just set vtable if we are sure we had no syntax-error*/ + if (faultless) + { + self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry + } } From 36375ce0f657241ecbe5072b88c9b96bde29f2ce Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Tue, 12 Aug 2008 10:57:46 +0200 Subject: [PATCH 081/102] parser improvements, compiles now --- src/backend/configitem.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 075304c37..1148b3486 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -35,6 +35,7 @@ //TODO: System includes// #include +#include /** * @file @@ -190,7 +191,6 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) * */ char* itr = self->line; - bool faultless = true; /*skip leading whitespaces*/ while (*itr && isspace (*itr)) @@ -200,9 +200,6 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) if (!*itr || *itr == '#' ) { /*this is an empty line or a a comment*/ - self->key = NULL; - self->keysize = 0; - self->delim = NULL; } else if (*itr == '@' ) { @@ -222,47 +219,32 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) /*now look for the end of the key and set the keysize*/ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); - if ( self->keysize==0 ) - { - /*Obviously a malformed "key"; treat this line like a comment*/ - self->key = NULL; - self->keysize = 0; - self->delim = NULL; - - LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); - - faultless = false; - } - /* skip blanks */ itr += self->key_size; while (*itr && isspace(*itr)) itr++; - if (*itr == '=') + if (self->key_size && *itr == '=') { + /*this configentry assigns a value to a key*/ self->delim = itr; + self->vtable = &lumiera_configentry_funcs; } - else if (*itr == '<') + else if (self->key_size && *itr == '<') { + /*this configentry is a redirect*/ self->delim = itr; + self->vtable = &lumiera_configentry_funcs; } else { /*this is not a valid configentry; treat this line like a comment*/ self->key = NULL; - self->keysize = 0; - self->delim = NULL; + self->key_size = 0; LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); - faultless = false; } - /*just set vtable if we are sure we had no syntax-error*/ - if (faultless) - { - self->vtable = &lumiera_configentry_funcs; // MOCKUP pretend this is a configentry - } } From a52b08bfc535679357177c089b26f53f80621f53 Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Tue, 12 Aug 2008 12:39:48 +0200 Subject: [PATCH 082/102] added section part to parser --- src/backend/configitem.c | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 1148b3486..7e52f269e 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -208,6 +208,71 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) else if (*itr == '[' ) { /*this is a section*/ + + /*skip blanks before prefix*/ + itr++; + while (*itr && isspace(*itr)) + itr++; + + /*itr points now to the begin of the key*/ + self->key = itr; + + /*now look for the end of the key and set the keysize*/ + self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS); + + itr += self->key_size; + + /*if the line ends ends with prefix] delim points to ] + * and not the last (blank) character before the final square bracket*/ + if (self->key_size && *itr && *itr == ']') + { + self->delim = itr; + TODO("self->vtable = &lumiera_configsection_funcs;"); + } + else if (self->key_size && *itr && isspace(*itr)) + { + /* skip blanks until we reach the suffix or the final square bracket*/ + while (*itr && isspace(*itr)) + itr++; + + if (*itr && *itr == ']') + { + /*final square bracket reached, so place delim one char before the + * actual position which must be a whitespace: no extra check necessary*/ + self->delim = itr - 1; + TODO("self->vtable = &lumiera_configsection_funcs;"); + } + else if (*itr) + { + TODO("check wheter suffix is made of legal characters"); + + /*delim points to the last whitespace before the actual position; + * no extra check needed*/ + self->delim = itr - 1; + TODO("self->vtable = &lumiera_configsection_funcs;"); + } + else + { + /*malformed section line, treat this line like a comment*/ + self->key = NULL; + self->key_size = 0; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + + } + } + else + { + /*error: either *itr is false, points neither to a blank nor to a closed square + * bracket or the key_size is zero*/ + + /*treat this line like a comment*/ + self->key = NULL; + self->key_size = 0; + + LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX); + + } } else { From 33297325cc1a7613a450e910f5f5060db5a301fa Mon Sep 17 00:00:00 2001 From: Simeon Voelkel Date: Wed, 13 Aug 2008 08:35:31 +0200 Subject: [PATCH 083/102] Added two very simple tests for configitem --- tests/20config.tests | 5 +++++ tests/backend/test-config.c | 24 +++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/20config.tests b/tests/20config.tests index bbcd4debd..65dfb5404 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -135,3 +135,8 @@ END PLANNED "bool set" < + Simeon Voelkel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -21,6 +22,7 @@ #include "lib/safeclib.h" #include "backend/config.h" +#include "backend/configitem.h" #include "tests/test.h" @@ -125,5 +127,25 @@ TEST ("word_get") lumiera_config_destroy (); } +TEST ("empty_line_configitem") +{ + LumieraConfigitem item; + + item = lumiera_configitem_new ( "" ); + + lumiera_configitem_delete(item); + item = NULL; +} + +TEST ("blank_line_configitem") +{ + LumieraConfigitem item; + + item = lumiera_configitem_new ( " " ); + + lumiera_configitem_delete(item); + item = NULL; +} + TESTS_END From d9f2b6d6fa5ea80eadbb10f70cde36683ca5dd37 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 21:24:41 +0200 Subject: [PATCH 084/102] WIP: add config_lookup skeleton --- src/backend/Makefile.am | 6 +- src/backend/config.c | 5 ++ src/backend/config.h | 7 +- src/backend/config_lookup.c | 151 ++++++++++++++++++++++++++++++++++++ src/backend/config_lookup.h | 102 ++++++++++++++++++++++++ 5 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 src/backend/config_lookup.c create mode 100644 src/backend/config_lookup.h diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index afe7cc1f3..f9d19d5e1 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -31,7 +31,8 @@ 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 += \ @@ -43,5 +44,6 @@ noinst_HEADERS += \ $(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/backend/config.c b/src/backend/config.c index deec72697..b68d30168 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -43,6 +43,7 @@ NOBUG_DEFINE_FLAG_PARENT (config, config_all); NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all); NOBUG_DEFINE_FLAG_PARENT (config_file, config_all); NOBUG_DEFINE_FLAG_PARENT (config_item, config_all); +NOBUG_DEFINE_FLAG_PARENT (config_lookup, config_all); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile"); LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key"); @@ -67,9 +68,12 @@ lumiera_config_init (const char* path) NOBUG_INIT_FLAG (config_typed); NOBUG_INIT_FLAG (config_file); NOBUG_INIT_FLAG (config_item); + NOBUG_INIT_FLAG (config_lookup); lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); + lumiera_config_lookup_init (&lumiera_global_config->keys); + lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config)); return 0; @@ -83,6 +87,7 @@ lumiera_config_destroy () if (lumiera_global_config) { lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config)); + lumiera_config_lookup_destroy (&lumiera_global_config->keys); lumiera_free (lumiera_global_config->path); lumiera_free (lumiera_global_config); lumiera_global_config = NULL; diff --git a/src/backend/config.h b/src/backend/config.h index 1daf54087..80a3f787f 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -40,6 +40,8 @@ NOBUG_DECLARE_FLAG (config_typed); NOBUG_DECLARE_FLAG (config_file); /* single config items */ NOBUG_DECLARE_FLAG (config_item); +/* lookup config keys */ +NOBUG_DECLARE_FLAG (config_lookup); LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX); @@ -49,7 +51,7 @@ LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY); LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); //TODO: Lumiera header includes// - +#include "backend/config_lookup.h" //TODO: System includes// #include @@ -65,7 +67,8 @@ LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); struct lumiera_config_struct { - // cuckoo hash + lumiera_config_lookup keys; + // configfile list char* path; /* diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c new file mode 100644 index 000000000..b0b6caeaa --- /dev/null +++ b/src/backend/config_lookup.c @@ -0,0 +1,151 @@ +/* + config_lookup.c - Lookup functions for the config subsystem + + 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/safeclib.h" + + +//TODO: Lumiera header includes// +#include "backend/config_lookup.h" +#include "backend/config.h" + +//TODO: System includes// +//#include +//#include + +//TODO: internal/static forward declarations// +static size_t +h1 (const void* item, const uint32_t r); + +static size_t +h2 (const void* item, const uint32_t r); + +static size_t +h3 (const void* item, const uint32_t r); + +static int +cmp (const void* keya, const void* keyb); + +static int +cmp (const void* keya, const void* keyb); + +/** + * @file + * + */ + + +//code goes here// + + + +LumieraConfigLookup +lumiera_config_lookup_init (LumieraConfigLookup self) +{ + self->hash = cuckoo_new (h1, h2, h3, cmp, sizeof (lumiera_config_lookupentry), 3, NULL, NULL); // TODO copy func, dtor + return self; +} + + +LumieraConfigLookup +lumiera_config_lookup_destroy (LumieraConfigLookup self) +{ + cuckoo_delete (self->hash); + return self; +} + + + + + + +LumieraConfigLookupentry +lumiera_config_lookupentry_new (const char* prefix, const char* name, const char* suffix) +{ + char* tmpstr = lumiera_tmpbuf_snprintf (LUMIERA_CONFIG_KEY_MAX, "%s%s%s%s%s", + prefix?prefix:"", prefix?".":"", + name?name:"", + suffix?".":"", suffix?suffix:""); + + TRACE (config_lookup, "new key %s", tmpstr); + + LumieraConfigLookupentry self = lumiera_malloc (sizeof (*self)); + + self->full_key = lumiera_strndup (tmpstr, LUMIERA_CONFIG_KEY_MAX); + llist_init (&self->configitems); + + return self; +} + +void +lumiera_config_lookupentry_delete (LumieraConfigLookupentry self) +{ + TRACE (config_lookup); + + lumiera_free (self->full_key); + ENSURE (llist_is_empty (&self->configitems)); + lumiera_free (self); +} + + + + +/* + Support functions for the cuckoo hash +*/ + +static size_t +h1 (const void* item, const uint32_t r) +{ + (void) item; + return r; +} + +static size_t +h2 (const void* item, const uint32_t r) +{ + (void) item; + return r; +} + +static size_t +h3 (const void* item, const uint32_t r) +{ + (void) item; + return r; +} + +static int +cmp (const void* keya, const void* keyb) +{ + (void) keya; + (void) keyb; + + return 0; +} + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h new file mode 100644 index 000000000..cb653dab8 --- /dev/null +++ b/src/backend/config_lookup.h @@ -0,0 +1,102 @@ +/* + config_lookup.h - Lookup functions for the config subsystem + + 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_CONFIG_LOOKUP_H +#define LUMIERA_CONFIG_LOOKUP_H + +//TODO: Support library includes// +#include "lib/cuckoo.h" +#include "lib/llist.h" + + +//TODO: Forward declarations// + + +//TODO: Lumiera header includes// + + +//TODO: System includes// +#include + + +/** + * @file + * + */ + +#define LUMIERA_CONFIG_KEY_MAX 1023 + + + +//TODO: declarations go here// + +/* + Lookup uses a cuckoo hash for now +*/ + +struct lumiera_config_lookup_struct +{ + Cuckoo hash; +}; +typedef struct lumiera_config_lookup_struct lumiera_config_lookup; +typedef lumiera_config_lookup* LumieraConfigLookup; + +LumieraConfigLookup +lumiera_config_lookup_init (LumieraConfigLookup self); + +LumieraConfigLookup +lumiera_config_lookup_destroy (LumieraConfigLookup self); + + + +/* + Lookup hash entries for the cuckoo hash +*/ + +struct lumiera_config_lookupentry_struct +{ + /* + we store a copy of the full key here + configentry keys are complete as expected + section keys are the prefix stored with a trailing dot + */ + char* full_key; + /* stack of all configitems stored under this key */ + llist configitems; +}; +typedef struct lumiera_config_lookupentry_struct lumiera_config_lookupentry; +typedef lumiera_config_lookupentry* LumieraConfigLookupentry; + +LumieraConfigLookupentry +lumiera_config_lookupentry_init (const char* prefix, const char* name, const char* suffix); + +void +lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self); + + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ From a55c122cc30f11019154063303a88d73adcc520a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Wed, 13 Aug 2008 10:50:27 +0200 Subject: [PATCH 085/102] Fixed configitem_move, first parsing tests pass now --- src/backend/configitem.c | 12 ++++++++---- tests/20config.tests | 4 ++-- tests/backend/test-config.c | 20 +++++++------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 7e52f269e..a49694280 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -77,7 +77,7 @@ lumiera_configitem_destroy (LumieraConfigitem self) if (self->vtable && self->vtable->destroy) self->vtable->destroy (self); - ENSURE (!llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); + ENSURE (llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); llist_unlink (&self->link); @@ -122,12 +122,16 @@ lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) REQUIRE (self); REQUIRE (source); - llist_move (&self->link, &source->link); + llist_init (&self->link); + llist_insertlist_next (&self->link, &source->link); self->parent = source->parent; - llist_move (&self->childs, &source->childs); - llist_move (&self->lookup, &source->lookup); + llist_init (&self->childs); + llist_insertlist_next (&self->childs, &source->childs); + + llist_init (&self->lookup); + llist_insertlist_next (&self->lookup, &source->lookup); self->line = source->line; source->line = NULL; diff --git a/tests/20config.tests b/tests/20config.tests index 65dfb5404..7a4ea2517 100644 --- a/tests/20config.tests +++ b/tests/20config.tests @@ -135,8 +135,8 @@ END PLANNED "bool set" < Date: Sun, 17 Aug 2008 00:35:40 +0200 Subject: [PATCH 086/102] split tests for the config subsystem into lowlevel and highlevel part --- tests/20config_lowlevel.tests | 27 ++++++++ ...0config.tests => 22config_highlevel.tests} | 12 ---- tests/backend/test-config.c | 61 ++++++++++++++----- 3 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 tests/20config_lowlevel.tests rename tests/{20config.tests => 22config_highlevel.tests} (90%) diff --git a/tests/20config_lowlevel.tests b/tests/20config_lowlevel.tests new file mode 100644 index 000000000..6b1e0abbe --- /dev/null +++ b/tests/20config_lowlevel.tests @@ -0,0 +1,27 @@ +TESTING "test configuration system" ./test-config + +TEST "initializing config system" init <line); + if (item->key) + printf ("key = '%.*s'\n", (int)item->key_size, item->key); + if (item->delim) + { + printf ("delim = '%c'\n", *item->delim); + printf ("value = '%s'\n", item->delim+1); + } + + lumiera_configitem_delete (item); + + lumiera_config_destroy (); +} + + +TEST ("lookup") +{ + lumiera_config_init ("./"); + + lumiera_config_lookup lookup; + lumiera_config_lookup_init (&lookup); + + LumieraConfigitem item = lumiera_configitem_new ("foo.bar = test"); + lumiera_config_lookup_insert (&lookup, item); + + // LumieraConfigitem found = lumiera_config_lookup_item_find (&lookup, "foo.bar"); + // ENSURE (found == item); + + //lumiera_config_lookup_remove (&lookup, found); + //ENSURE (found == NULL); + + lumiera_config_lookup_destroy (&lookup); + lumiera_config_destroy (); +} + + TEST ("number_get") { REQUIRE (argv[2]); @@ -127,19 +173,4 @@ TEST ("word_get") lumiera_config_destroy (); } -TEST ("configitem_simple_ctor_dtor") -{ - REQUIRE (argv[2]); - lumiera_config_init ("./"); - - LumieraConfigitem item; - - item = lumiera_configitem_new (argv[2]); - - lumiera_configitem_delete (item); - - lumiera_config_destroy (); -} - - TESTS_END From 1dca87271f4124a5bef61f3da2ac1a0b9517b881 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 17 Aug 2008 00:50:56 +0200 Subject: [PATCH 087/102] ConfigLookup working (for now) added the missing unimplemented function, fixed some prototypes, some cosmetics. Barely tested, no documentation yet. --- src/backend/config_lookup.c | 175 +++++++++++++++++++++++++++--------- src/backend/config_lookup.h | 42 +++++---- tests/backend/test-config.c | 8 +- 3 files changed, 162 insertions(+), 63 deletions(-) diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c index b0b6caeaa..d2833089b 100644 --- a/src/backend/config_lookup.c +++ b/src/backend/config_lookup.c @@ -18,20 +18,12 @@ 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/safeclib.h" - -//TODO: Lumiera header includes// #include "backend/config_lookup.h" #include "backend/config.h" -//TODO: System includes// -//#include -//#include -//TODO: internal/static forward declarations// static size_t h1 (const void* item, const uint32_t r); @@ -44,23 +36,24 @@ h3 (const void* item, const uint32_t r); static int cmp (const void* keya, const void* keyb); -static int -cmp (const void* keya, const void* keyb); +static void +dtor (void* item); + +static void +mov (void* dest, void* src, size_t size); + + /** * @file * */ - -//code goes here// - - - LumieraConfigLookup lumiera_config_lookup_init (LumieraConfigLookup self) { - self->hash = cuckoo_new (h1, h2, h3, cmp, sizeof (lumiera_config_lookupentry), 3, NULL, NULL); // TODO copy func, dtor + TRACE (config_lookup); + self->hash = cuckoo_new (sizeof (lumiera_config_lookupentry), &(struct cuckoo_vtable){h1, h2, h3, cmp, dtor, mov}); return self; } @@ -68,41 +61,109 @@ lumiera_config_lookup_init (LumieraConfigLookup self) LumieraConfigLookup lumiera_config_lookup_destroy (LumieraConfigLookup self) { + TRACE (config_lookup); cuckoo_delete (self->hash); return self; } +LumieraConfigLookupentry +lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) +{ + TRACE (config_lookup); + REQUIRE (self); + REQUIRE (item); + REQUIRE (item->key); + REQUIRE (item->key_size); + + lumiera_config_lookupentry tmp; + FIXME ("implement section prefix/suffix for the key"); + lumiera_config_lookupentry_init (&tmp, lumiera_tmpbuf_strcat3 (NULL, 0, item->key, item->key_size, NULL, 0)); + + LumieraConfigLookupentry entry = cuckoo_find (self->hash, &tmp); + + if (!entry) + entry = cuckoo_insert (self->hash, &tmp); + + if (entry) + llist_insert_head (&entry->configitems, &item->lookup); + + return entry; +} + + +LumieraConfigitem +lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) +{ + TRACE (config_lookup); + REQUIRE (!llist_is_empty (&item->lookup), "item is not in a lookup hash"); + + if (llist_is_single (&item->lookup)) + { + /* last item in lookup, remove it from hash */ + LumieraConfigLookupentry entry = (LumieraConfigLookupentry)llist_next (&item->lookup); + llist_unlink (&item->lookup); + cuckoo_remove (self->hash, entry); + } + else + { + /* more than this item present in hash, just unlink this item */ + llist_unlink (&item->lookup); + } + + return item; +} + +LumieraConfigLookupentry +lumiera_config_lookup_find (LumieraConfigLookup self, const char* key) +{ + TRACE (config_lookup); + + /* fast temporary init without strdup */ + lumiera_config_lookupentry tmp; + tmp.full_key = (char*)key; + + return cuckoo_find (self->hash, &tmp); +} + + +LumieraConfigitem +lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key) +{ + TRACE (config_lookup); + + LumieraConfigLookupentry entry = + lumiera_config_lookup_find (self, key); + + if (entry && !llist_is_empty (&entry->configitems)) + return LLIST_TO_STRUCTP (llist_head (&entry->configitems), lumiera_configitem, lookup); + + return NULL; +} + + + + LumieraConfigLookupentry -lumiera_config_lookupentry_new (const char* prefix, const char* name, const char* suffix) +lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key) { - char* tmpstr = lumiera_tmpbuf_snprintf (LUMIERA_CONFIG_KEY_MAX, "%s%s%s%s%s", - prefix?prefix:"", prefix?".":"", - name?name:"", - suffix?".":"", suffix?suffix:""); - - TRACE (config_lookup, "new key %s", tmpstr); - - LumieraConfigLookupentry self = lumiera_malloc (sizeof (*self)); - - self->full_key = lumiera_strndup (tmpstr, LUMIERA_CONFIG_KEY_MAX); + TRACE (config_lookup, "key = %s", key); + self->full_key = lumiera_strndup (key, SIZE_MAX); llist_init (&self->configitems); - return self; } + void lumiera_config_lookupentry_delete (LumieraConfigLookupentry self) { TRACE (config_lookup); - + REQUIRE (llist_is_empty (&self->configitems), "lookup node still in use"); lumiera_free (self->full_key); - ENSURE (llist_is_empty (&self->configitems)); - lumiera_free (self); } @@ -115,33 +176,65 @@ lumiera_config_lookupentry_delete (LumieraConfigLookupentry self) static size_t h1 (const void* item, const uint32_t r) { - (void) item; - return r; + REQUIRE (item); + REQUIRE (((LumieraConfigLookupentry)item)->full_key); + size_t hash = r; + for (const char* s = ((LumieraConfigLookupentry)item)->full_key; *s; ++s) + hash = *s ^ ~(*s << 5) ^ (hash << 3) ^ (hash >> 7); + return hash; } static size_t h2 (const void* item, const uint32_t r) { - (void) item; - return r; + REQUIRE (item); + REQUIRE (((LumieraConfigLookupentry)item)->full_key); + size_t hash = r; + for (const char* s = ((LumieraConfigLookupentry)item)->full_key; *s; ++s) + hash = *s ^ ~(*s << 7) ^ (hash << 3) ^ (hash >> 5); + return hash; } static size_t h3 (const void* item, const uint32_t r) { - (void) item; - return r; + REQUIRE (item); + REQUIRE (((LumieraConfigLookupentry)item)->full_key); + size_t hash = r; + for (const char* s = ((LumieraConfigLookupentry)item)->full_key; *s; ++s) + hash = *s ^ ~(*s << 3) ^ (hash << 5) ^ (hash >> 7); + return hash; } static int cmp (const void* keya, const void* keyb) { - (void) keya; - (void) keyb; - - return 0; + REQUIRE (keya); + REQUIRE (((LumieraConfigLookupentry)keya)->full_key); + REQUIRE (keyb); + REQUIRE (((LumieraConfigLookupentry)keyb)->full_key); + return !strcmp (((LumieraConfigLookupentry)keya)->full_key, ((LumieraConfigLookupentry)keyb)->full_key); } +static void +dtor (void* item) +{ + if (((LumieraConfigLookupentry)item)->full_key) + { + REQUIRE (llist_is_empty (&((LumieraConfigLookupentry)item)->configitems), "lookup node still in use"); + lumiera_free (((LumieraConfigLookupentry)item)->full_key); + } +} + +static void +mov (void* dest, void* src, size_t size) +{ + ((LumieraConfigLookupentry)dest)->full_key = ((LumieraConfigLookupentry)src)->full_key; + llist_init (&((LumieraConfigLookupentry)dest)->configitems); + llist_insertlist_next (&((LumieraConfigLookupentry)dest)->configitems, &((LumieraConfigLookupentry)src)->configitems); +} + + /* // Local Variables: // mode: C diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h index cb653dab8..d7ddc13d3 100644 --- a/src/backend/config_lookup.h +++ b/src/backend/config_lookup.h @@ -22,18 +22,20 @@ #ifndef LUMIERA_CONFIG_LOOKUP_H #define LUMIERA_CONFIG_LOOKUP_H -//TODO: Support library includes// #include "lib/cuckoo.h" #include "lib/llist.h" -//TODO: Forward declarations// +typedef struct lumiera_config_lookup_struct lumiera_config_lookup; +typedef lumiera_config_lookup* LumieraConfigLookup; + +typedef struct lumiera_config_lookupentry_struct lumiera_config_lookupentry; +typedef lumiera_config_lookupentry* LumieraConfigLookupentry; -//TODO: Lumiera header includes// +#include "backend/configitem.h" -//TODO: System includes// #include @@ -42,11 +44,6 @@ * */ -#define LUMIERA_CONFIG_KEY_MAX 1023 - - - -//TODO: declarations go here// /* Lookup uses a cuckoo hash for now @@ -56,8 +53,6 @@ struct lumiera_config_lookup_struct { Cuckoo hash; }; -typedef struct lumiera_config_lookup_struct lumiera_config_lookup; -typedef lumiera_config_lookup* LumieraConfigLookup; LumieraConfigLookup lumiera_config_lookup_init (LumieraConfigLookup self); @@ -65,6 +60,18 @@ lumiera_config_lookup_init (LumieraConfigLookup self); LumieraConfigLookup lumiera_config_lookup_destroy (LumieraConfigLookup self); +LumieraConfigLookupentry +lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item); + +LumieraConfigitem +lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item); + +LumieraConfigLookupentry +lumiera_config_lookup_find (LumieraConfigLookup self, const char* key); + +LumieraConfigitem +lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key); + /* @@ -73,22 +80,21 @@ lumiera_config_lookup_destroy (LumieraConfigLookup self); struct lumiera_config_lookupentry_struct { + /* stack of all configitems stored under this key MUST BE FIRST IN THIS STRUCT */ + llist configitems; /* we store a copy of the full key here configentry keys are complete as expected - section keys are the prefix stored with a trailing dot + section keys are the prefix stored with a trailing dot, suffixes will be found by iteration */ char* full_key; - /* stack of all configitems stored under this key */ - llist configitems; }; -typedef struct lumiera_config_lookupentry_struct lumiera_config_lookupentry; -typedef lumiera_config_lookupentry* LumieraConfigLookupentry; + LumieraConfigLookupentry -lumiera_config_lookupentry_init (const char* prefix, const char* name, const char* suffix); +lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key); -void +LumieraConfigLookupentry lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self); diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index f6f983fab..f6f49e099 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -72,11 +72,11 @@ TEST ("lookup") LumieraConfigitem item = lumiera_configitem_new ("foo.bar = test"); lumiera_config_lookup_insert (&lookup, item); - // LumieraConfigitem found = lumiera_config_lookup_item_find (&lookup, "foo.bar"); - // ENSURE (found == item); + LumieraConfigitem found = lumiera_config_lookup_item_find (&lookup, "foo.bar"); + ENSURE (found == item); - //lumiera_config_lookup_remove (&lookup, found); - //ENSURE (found == NULL); + lumiera_config_lookup_remove (&lookup, found); + ENSURE (!lumiera_config_lookup_item_find (&lookup, "foo.bar")); lumiera_config_lookup_destroy (&lookup); lumiera_config_destroy (); From a0105eec42f8a18f581478e046697b17eb14f93c Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 17 Aug 2008 21:23:29 +0200 Subject: [PATCH 088/102] Documentation and error handling for config_lookup --- src/backend/config_lookup.c | 21 +++++++++---- src/backend/config_lookup.h | 60 +++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c index d2833089b..fc124d636 100644 --- a/src/backend/config_lookup.c +++ b/src/backend/config_lookup.c @@ -23,6 +23,9 @@ #include "backend/config_lookup.h" #include "backend/config.h" +/* we only use one fatal error for now, when allocation in the config system fail, something else is pretty wrong */ +LUMIERA_ERROR_DEFINE (CONFIG_LOOKUP, "config lookup failure"); + static size_t h1 (const void* item, const uint32_t r); @@ -46,7 +49,7 @@ mov (void* dest, void* src, size_t size); /** * @file - * + * Implementation of the lookup of configuration keys using a cuckoo hash. */ LumieraConfigLookup @@ -54,6 +57,10 @@ lumiera_config_lookup_init (LumieraConfigLookup self) { TRACE (config_lookup); self->hash = cuckoo_new (sizeof (lumiera_config_lookupentry), &(struct cuckoo_vtable){h1, h2, h3, cmp, dtor, mov}); + + if (!self->hash) + LUMIERA_DIE (CONFIG_LOOKUP); + return self; } @@ -62,12 +69,12 @@ LumieraConfigLookup lumiera_config_lookup_destroy (LumieraConfigLookup self) { TRACE (config_lookup); - cuckoo_delete (self->hash); + if (self) + cuckoo_delete (self->hash); return self; } - LumieraConfigLookupentry lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) { @@ -88,6 +95,8 @@ lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) if (entry) llist_insert_head (&entry->configitems, &item->lookup); + else + LUMIERA_DIE (CONFIG_LOOKUP); return entry; } @@ -144,9 +153,9 @@ lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key) - - - +/* + Hash table entries +*/ LumieraConfigLookupentry lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key) diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h index d7ddc13d3..af22b2335 100644 --- a/src/backend/config_lookup.h +++ b/src/backend/config_lookup.h @@ -24,7 +24,7 @@ #include "lib/cuckoo.h" #include "lib/llist.h" - +#include "lib/error.h" typedef struct lumiera_config_lookup_struct lumiera_config_lookup; typedef lumiera_config_lookup* LumieraConfigLookup; @@ -41,34 +41,78 @@ typedef lumiera_config_lookupentry* LumieraConfigLookupentry; /** * @file - * + * Lookup of configuration keys. Configuration key are dynamically stored in a hashtable + * this happens for defaults, loaded config files and entries which are set explicitly. + * The system maintains no central registry of all possible keys. + * We store here the full keys of configentries as well as the keys of section prefixes. + * Section prefixes are stored with a trailing dot to disambiguate them from entry keys. */ -/* - Lookup uses a cuckoo hash for now -*/ +LUMIERA_ERROR_DECLARE (CONFIG_LOOKUP); +/** + * Just contains a hashtable to give sufficent abstraction. + */ struct lumiera_config_lookup_struct { Cuckoo hash; }; +/** + * Initialize a lookup structure. + * @param self lookup structure to be initialized + * @return self on success else NULL + */ LumieraConfigLookup lumiera_config_lookup_init (LumieraConfigLookup self); +/** + * Destruct a lookup structure. + * @param self lookup structure to be destructed + * @return self + */ LumieraConfigLookup lumiera_config_lookup_destroy (LumieraConfigLookup self); +/** + * Add a config item to a lookup structure. + * Config items are stored under their key and stacked in insertion order. + * @param self lookup structure where the item shall be added + * @param item config item to add to the lookup structure + * @return opaque pointer to a hashtable entry + */ LumieraConfigLookupentry lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item); +/** + * Remove a config item from a lookup structure. + * Config must be removed from the lookup when they are not used anymore. + * Removing a config item unlinks it from the stack of all config items with the same key. + * When this was the last config item under that key, the lookup entry is cleaned up. + * @param self lookup structure where the item shall be removed + * @param item config item to be removed from the lookup + * @return item + */ LumieraConfigitem lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item); +/** + * Find a hashtable entry in the lookup structure. + * Internal function, can be used to check if at least one item is available for a given key. + * @param self lookup structure where the key shall be searched + * @param key string to be looked up + * @return NULL if nothing is found, otherwise a opaque pointer to a hash table entry + */ LumieraConfigLookupentry lumiera_config_lookup_find (LumieraConfigLookup self, const char* key); +/** + * Find a the topmost config item stored to a given key. + * @param self lookup structure where the key shall be searched + * @param key string to be looked up + * @return the config item which was last stored under the given key or NULL when nothing was found + */ LumieraConfigitem lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key); @@ -78,6 +122,10 @@ lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key); Lookup hash entries for the cuckoo hash */ +/** + * Structure defining single hash table entries. + * @internal + */ struct lumiera_config_lookupentry_struct { /* stack of all configitems stored under this key MUST BE FIRST IN THIS STRUCT */ @@ -91,9 +139,11 @@ struct lumiera_config_lookupentry_struct }; +/* internal */ LumieraConfigLookupentry lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key); +/* internal */ LumieraConfigLookupentry lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self); From c3e2941eb87a02cd1b4e096ad4812d19118ddf04 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 19 Aug 2008 22:32:54 +0200 Subject: [PATCH 089/102] some machinery for registering and retrieving defaults * let config_setdefault() take a complete configline instead key:value pair --- src/backend/config.c | 116 +++++++++++++++++++++++++++++++++--- src/backend/config.h | 38 ++++++++++-- src/backend/config_lookup.c | 40 +++++++++++++ src/backend/config_lookup.h | 25 ++++++++ src/backend/config_typed.c | 104 ++++++++++---------------------- src/backend/configitem.c | 14 +++-- src/backend/configitem.h | 5 +- tests/backend/test-config.c | 19 +++--- 8 files changed, 261 insertions(+), 100 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index b68d30168..9cb532780 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -32,6 +32,7 @@ //TODO: System includes// #include #include +#include /** * @file @@ -74,8 +75,14 @@ lumiera_config_init (const char* path) lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); lumiera_config_lookup_init (&lumiera_global_config->keys); + lumiera_configitem_init (&lumiera_global_config->defaults); + 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)); + TODO ("register path as config.path itself"); + return 0; } @@ -87,6 +94,9 @@ lumiera_config_destroy () if (lumiera_global_config) { lumiera_rwlock_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); lumiera_config_lookup_destroy (&lumiera_global_config->keys); lumiera_free (lumiera_global_config->path); lumiera_free (lumiera_global_config); @@ -140,11 +150,8 @@ lumiera_config_get (const char* key, const char** value) LUMIERA_CONFIG_KEY_CHARS, LUMIERA_CONFIG_ENV_CHARS, NULL); - if (!tr_key) - { - LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY); - } - else + + if (tr_key) { char* env = lumiera_tmpbuf_snprintf (2048, "LUMIERA_%s", tr_key); @@ -156,24 +163,117 @@ lumiera_config_get (const char* key, const char** value) } else { - TODO ("lookup key"); - ret = 0; /* assume that the lockup worked for now, value is still NULL, just no error set */ + TODO ("follow '<' delegates?"); + LumieraConfigitem item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key); + + if (item) + { + *value = item->delim+1; + ret = 0; + } + else + LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); } } + else + { + LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY); + } return ret; } int -lumiera_config_set (const char* key, const char* value) +lumiera_config_get_default (const char* key, const char** value) { TRACE (config); + REQUIRE (key); + REQUIRE (value); + + int ret = -1; + + TODO ("follow '<' delegates?"); + TODO ("refactor _get and get_default to iterator access"); + LumieraConfigitem item = lumiera_config_lookup_item_tail_find (&lumiera_global_config->keys, key); + + if (item && item->parent == &lumiera_global_config->defaults) + { + *value = item->delim+1; + ret = 0; + } + + return ret; +} + + +int +lumiera_config_set (const char* key, const char* delim_value) +{ + TRACE (config); + + TODO ("if does this item already exist in a user writeable file?"); + TODO (" replace delim_value"); + + TODO ("else"); + TODO (" find matching prefix"); + TODO (" find matching suffix"); + TODO (" find proper prefix indentation, else use config.indent"); + TODO (" create configitem with prefix/suffix removed"); + + + +// * set a value by key +// * handles internally everything as string:string key:value pair. +// * lowlevel function +// * tag file as dirty +// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called. + + + UNIMPLEMENTED(); return -1; } +LumieraConfigitem +lumiera_config_setdefault (const char* line) +{ + TRACE (config); + REQUIRE (line); + + LumieraConfigitem item = NULL; + + LUMIERA_WRLOCK_SECTION (config, &lumiera_global_config->lock) + { + const char* key = line; + while (*key && isspace (*key)) + key++; + + key = lumiera_tmpbuf_strndup (line, strspn (line, LUMIERA_CONFIG_KEY_CHARS)); + + if (!(item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key)) || item->parent != &lumiera_global_config->defaults) + { + item = lumiera_configitem_new (line); + + if (item) + { + ENSURE (item->delim, "default must be a configentry with key=value or keydelim == '=' || *item->delim == '<', "default must be a configentry with key=value or keyline); + + llist_insert_head (&lumiera_global_config->defaults.childs, &item->link); + item->parent = &lumiera_global_config->defaults; + + lumiera_config_lookup_insert_default (&lumiera_global_config->keys, item); + } + } + } + + return item; +} + + int lumiera_config_reset (const char* key) { diff --git a/src/backend/config.h b/src/backend/config.h index 80a3f787f..e5363796d 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -59,7 +59,7 @@ LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); /** * @file - * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader + * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader */ #define LUMIERA_CONFIG_KEY_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_." @@ -69,8 +69,12 @@ struct lumiera_config_struct { lumiera_config_lookup keys; - // configfile list + lumiera_configitem defaults; /* registered default values */ + 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 */ + char* path; + /* all access is protected with rwlock's. We use rwlocks here since concurrent reads are likely common. @@ -89,6 +93,7 @@ typedef lumiera_config* LumieraConfig; */ /* TODO: add here as 'LUMIERA_CONFIG_TYPE(name, ctype)' the _get/_set prototypes are declared automatically below, you still have to implement them in config.c */ #define LUMIERA_CONFIG_TYPES \ + LUMIERA_CONFIG_TYPE(link, char*) \ LUMIERA_CONFIG_TYPE(number, signed long long) \ LUMIERA_CONFIG_TYPE(real, long double) \ LUMIERA_CONFIG_TYPE(string, char*) \ @@ -160,17 +165,38 @@ int lumiera_config_get (const char* key, const char** value); +int +lumiera_config_get_default (const char* key, const char** value); + + // * {{{ lumiera_config_set(...) }}} // * set a value by key // * handles internally everything as string:string key:value pair. // * lowlevel function // * tag file as dirty // * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called. + /** + * + * + * @param key + * @param delim_value delimiter (= or <) followed by the value to be set * */ int -lumiera_config_set (const char* key, const char* value); +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. + * @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 + */ +LumieraConfigitem +lumiera_config_setdefault (const char* line); @@ -187,7 +213,7 @@ lumiera_config_set (const char* key, const char* value); */ #define LUMIERA_CONFIG_TYPE(name, type) \ int \ - lumiera_config_##name##_get (const char* key, type* value, const char* def); + lumiera_config_##name##_get (const char* key, type* value); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE @@ -200,7 +226,7 @@ LUMIERA_CONFIG_TYPES */ #define LUMIERA_CONFIG_TYPE(name, type) \ int \ - lumiera_config_##name##_set (const char* key, type* value, const char* fmt); + lumiera_config_##name##_set (const char* key, type* value); LUMIERA_CONFIG_TYPES #undef LUMIERA_CONFIG_TYPE @@ -211,7 +237,7 @@ LUMIERA_CONFIG_TYPES * */ int -lumiera_config_reset(const char* key); +lumiera_config_reset (const char* key); // * Find exact place of a setting. diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c index fc124d636..88fd8b102 100644 --- a/src/backend/config_lookup.c +++ b/src/backend/config_lookup.c @@ -102,6 +102,32 @@ lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) } +LumieraConfigLookupentry +lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item) +{ + TRACE (config_lookup); + REQUIRE (self); + REQUIRE (item); + REQUIRE (item->key); + REQUIRE (item->key_size); + + lumiera_config_lookupentry tmp; + lumiera_config_lookupentry_init (&tmp, lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s", item->key_size, item->key)); + + LumieraConfigLookupentry entry = cuckoo_find (self->hash, &tmp); + + if (!entry) + entry = cuckoo_insert (self->hash, &tmp); + + if (entry) + llist_insert_tail (&entry->configitems, &item->lookup); + else + LUMIERA_DIE (CONFIG_LOOKUP); + + return entry; +} + + LumieraConfigitem lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) { @@ -151,6 +177,20 @@ lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key) return NULL; } +LumieraConfigitem +lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) +{ + TRACE (config_lookup); + + LumieraConfigLookupentry entry = + lumiera_config_lookup_find (self, key); + + if (entry && !llist_is_empty (&entry->configitems)) + return LLIST_TO_STRUCTP (llist_tail (&entry->configitems), lumiera_configitem, lookup); + + return NULL; +} + /* diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h index af22b2335..42c06842e 100644 --- a/src/backend/config_lookup.h +++ b/src/backend/config_lookup.h @@ -85,6 +85,21 @@ lumiera_config_lookup_destroy (LumieraConfigLookup self); LumieraConfigLookupentry lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item); + +/** + * Add a default config item to a lookup structure. + * @internal + * This function is used internal. + * The item must contain a full key and not part of any 'section' + * and is inserted as tail of the lookup list. + * @param self lookup structure where the item shall be added + * @param item config item to add to the lookup structure + * @return opaque pointer to a hashtable entry + */ +LumieraConfigLookupentry +lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item); + + /** * Remove a config item from a lookup structure. * Config must be removed from the lookup when they are not used anymore. @@ -116,6 +131,16 @@ lumiera_config_lookup_find (LumieraConfigLookup self, const char* key); LumieraConfigitem lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key); +/** + * Find a the bottommost config item stored to a given key. + * defaults sits at the bottom if exists + * @param self lookup structure where the key shall be searched + * @param key string to be looked up + * @return TODO + */ +LumieraConfigitem +lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key); + /* diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 78f2e8cd7..02e75d0db 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -38,12 +38,29 @@ extern LumieraConfig lumiera_global_config; * Here are the high level typed configuration interfaces defined. */ +int +lumiera_config_link_get (const char* key, char** value) +{ + TRACE (config_typed); + UNIMPLEMENTED(); + return 0; +} + +int +lumiera_config_link_set (const char* key, char** value) +{ + TRACE (config_typed); + UNIMPLEMENTED(); + return 0; +} + + /** * Number * signed integer numbers, in different formats (decimal, hex, oct, binary(for masks)) */ int -lumiera_config_number_get (const char* key, long long* value, const char* def) +lumiera_config_number_get (const char* key, long long* value) { TRACE (config_typed); @@ -63,31 +80,12 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) else { LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE); - if (def) - /* even when we return an error code we still try to initialize value with our default while in error state */ - goto try_default; - } - } - else if (def) - { - /* not found, fall back to default */ - ret = 0; /* we presume that the default is ok */ - try_default: - - if (sscanf (def, "%Li", value) == 1) - { - TODO ("register default (writelock or mutex!)"); - } - else - { - /* default value is broken!! */ - /* note that this error gets ignored by the application when we had a type error above, but will still be logged with nobug */ - ret = -1; - LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); + /* try default instead */ + if (!lumiera_config_get_default (key, &raw_value)) + sscanf (raw_value, "%Li", value); } } else - /* finally, no config, no default, give up */ LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); } } @@ -96,7 +94,7 @@ lumiera_config_number_get (const char* key, long long* value, const char* def) } int -lumiera_config_number_set (const char* key, long long* value, const char* fmt) +lumiera_config_number_set (const char* key, long long* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -109,7 +107,7 @@ lumiera_config_number_set (const char* key, long long* value, const char* fmt) * floating point number in standard formats (see printf/scanf) */ int -lumiera_config_real_get (const char* key, long double* value, const char* def) +lumiera_config_real_get (const char* key, long double* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -117,7 +115,7 @@ lumiera_config_real_get (const char* key, long double* value, const char* def) } int -lumiera_config_real_set (const char* key, long double* value, const char* fmt) +lumiera_config_real_set (const char* key, long double* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -189,7 +187,7 @@ scan_string (const char* in) } int -lumiera_config_string_get (const char* key, char** value, const char* def) +lumiera_config_string_get (const char* key, char** value) { TRACE (config_typed); @@ -204,27 +202,9 @@ lumiera_config_string_get (const char* key, char** value, const char* def) if (raw_value) { *value = scan_string (raw_value); - if (*value) ret = 0; /* all ok */ - else if (def) - goto try_default; - } - else if (def) - { - ret = 0; - try_default: - - *value = scan_string (def); - if (*value) - { - TODO ("register default (writelock or mutex!)"); - } - else - { - ret = -1; - LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); - } + /* else error was raised by scan_string */ } else LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); @@ -235,7 +215,7 @@ lumiera_config_string_get (const char* key, char** value, const char* def) } int -lumiera_config_string_set (const char* key, char** value, const char* fmt) +lumiera_config_string_set (const char* key, char** value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -271,7 +251,7 @@ scan_word (const char* in) } int -lumiera_config_word_get (const char* key, char** value, const char* def) +lumiera_config_word_get (const char* key, char** value) { TRACE (config_typed, "KEY %s", key); @@ -286,30 +266,8 @@ lumiera_config_word_get (const char* key, char** value, const char* def) if (raw_value) { *value = scan_word (raw_value); - - TRACE (config_typed, "RAW_VALUE %s, scanned .%s.", raw_value, *value); - if (*value) ret = 0; /* all ok */ - else if (def) - goto try_default; - } - else if (def) - { - ret = 0; - try_default: - - *value = scan_word (def); - TRACE (config_typed, "DEFAULT %s, scanned .%s.", def, *value); - if (*value) - { - TODO ("register default (writelock or mutex!)"); - } - else - { - ret = -1; - LUMIERA_ERROR_SET (config_typed, CONFIG_DEFAULT); - } } else LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY); @@ -320,7 +278,7 @@ lumiera_config_word_get (const char* key, char** value, const char* def) } int -lumiera_config_word_set (const char* key, char** value, const char* fmt) +lumiera_config_word_set (const char* key, char** value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -333,7 +291,7 @@ lumiera_config_word_set (const char* key, char** value, const char* fmt) * Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear) */ int -lumiera_config_bool_get (const char* key, int* value, const char* def) +lumiera_config_bool_get (const char* key, int* value) { TRACE (config_typed); UNIMPLEMENTED(); @@ -341,7 +299,7 @@ lumiera_config_bool_get (const char* key, int* value, const char* def) } int -lumiera_config_bool_set (const char* key, int* value, const char* fmt) +lumiera_config_bool_set (const char* key, int* value) { TRACE (config_typed); UNIMPLEMENTED(); diff --git a/src/backend/configitem.c b/src/backend/configitem.c index a49694280..0d7830b87 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -68,7 +68,7 @@ lumiera_configitem_init (LumieraConfigitem self) } LumieraConfigitem -lumiera_configitem_destroy (LumieraConfigitem self) +lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup) { TRACE (config_item); @@ -77,7 +77,12 @@ lumiera_configitem_destroy (LumieraConfigitem self) if (self->vtable && self->vtable->destroy) self->vtable->destroy (self); - ENSURE (llist_is_empty (&self->lookup), "destructor didn't cleaned lookup up"); + if (!llist_is_empty (&self->lookup)) + lumiera_config_lookup_remove (lookup, self); + + LLIST_WHILE_HEAD (&self->childs, node) + lumiera_configitem_delete ((LumieraConfigitem) node, lookup); + ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); llist_unlink (&self->link); @@ -102,15 +107,16 @@ lumiera_configitem_new (const char* line) ? tmp.vtable->new (&tmp) : lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp); + TRACE (config_item, "key size of %s is %d", tmp.key, tmp.key_size); return self; } void -lumiera_configitem_delete (LumieraConfigitem self) +lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup) { TRACE (config_item); - lumiera_free (lumiera_configitem_destroy (self)); + lumiera_free (lumiera_configitem_destroy (self, lookup)); } diff --git a/src/backend/configitem.h b/src/backend/configitem.h index c2b0bea92..c2395b6dc 100644 --- a/src/backend/configitem.h +++ b/src/backend/configitem.h @@ -33,6 +33,7 @@ typedef lumiera_configitem* LumieraConfigitem; struct lumiera_configitem_vtable; //TODO: Lumiera header includes// +#include "backend/config_lookup.h" //TODO: System includes// @@ -112,13 +113,13 @@ LumieraConfigitem lumiera_configitem_init (LumieraConfigitem self); LumieraConfigitem -lumiera_configitem_destroy (LumieraConfigitem self); +lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup); LumieraConfigitem lumiera_configitem_new (const char* line); void -lumiera_configitem_delete (LumieraConfigitem self); +lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup); LumieraConfigitem lumiera_configitem_parse (LumieraConfigitem self, const char* line); diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c index f6f49e099..8fed601f8 100644 --- a/tests/backend/test-config.c +++ b/tests/backend/test-config.c @@ -56,7 +56,7 @@ TEST ("configitem_simple") printf ("value = '%s'\n", item->delim+1); } - lumiera_configitem_delete (item); + lumiera_configitem_delete (item, NULL); lumiera_config_destroy (); } @@ -92,7 +92,9 @@ TEST ("number_get") long long number = 0; - if (!lumiera_config_number_get (argv[2], &number, argv[3])) + lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3])); + + if (!lumiera_config_number_get (argv[2], &number)) printf ("%lld\n", number); else printf ("%s, %lld\n", lumiera_error (), number); @@ -109,7 +111,7 @@ TEST ("number_get_nodefault") long long number = 0; - if (!lumiera_config_number_get (argv[2], &number, NULL)) + if (!lumiera_config_number_get (argv[2], &number)) printf ("%lld\n", number); else printf ("%s\n", lumiera_error ()); @@ -127,7 +129,9 @@ TEST ("string_get") char* string; - if (!lumiera_config_string_get (argv[2], &string, argv[3])) + lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3])); + + if (!lumiera_config_string_get (argv[2], &string)) printf ("'%s'\n", string); else printf ("%s, '%s'\n", lumiera_error (), string); @@ -139,11 +143,10 @@ TEST ("string_get") TEST ("string_set") { REQUIRE (argv[2]); - REQUIRE (argv[3]); lumiera_config_init ("./"); - lumiera_config_string_set (argv[2], &argv[3], NULL); + lumiera_config_string_set (argv[2], &argv[3]); FIXME ("handle error"); const char* string; @@ -165,7 +168,9 @@ TEST ("word_get") char* word; - if (!lumiera_config_word_get (argv[2], &word, argv[3])) + lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3])); + + if (!lumiera_config_word_get (argv[2], &word)) printf ("'%s'\n", word); else printf ("%s, '%s'\n", lumiera_error (), word); From a1bd3ee1f5ecc181dbb542b33c8cf4981fa867f1 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Tue, 12 Aug 2008 11:39:35 +0200 Subject: [PATCH 090/102] use psplay trees for the filedescriptor registry --- src/backend/filedescriptor.c | 92 ++++++++++++++-------------- src/backend/filedescriptor.h | 4 +- tests/20filedescriptor.tests | 12 ++++ tests/backend/test-filedescriptors.c | 26 ++++++++ 4 files changed, 87 insertions(+), 47 deletions(-) diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index fee877dfd..4daa04f3e 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -21,7 +21,6 @@ #include "lib/mutex.h" #include "lib/safeclib.h" -#include "lib/cuckoo.h" #include "backend/file.h" #include "backend/filedescriptor.h" @@ -42,46 +41,50 @@ NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all); This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore. */ -static Cuckoo registry = NULL; +static PSplay registry = NULL; static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER}; -/* - * setup hashing and compare functions for cuckoo hashing - */ -static size_t -h1 (const void* item, const uint32_t r) -{ - const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item; - return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK) - ^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>7)^r; -} - -static size_t -h2 (const void* item, const uint32_t r) -{ - const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item; - return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK) - ^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>5)^r; -} - -static size_t -h3 (const void* item, const uint32_t r) -{ - const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item; - return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK) - ^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>3)^r; -} - static int -cmp (const void* keya, const void* keyb) +cmp_fn (const void* keya, const void* keyb) { - const LumieraFiledescriptor a = *(const LumieraFiledescriptor*)keya; - const LumieraFiledescriptor b = *(const LumieraFiledescriptor*)keyb; - return a->stat.st_dev == b->stat.st_dev && a->stat.st_ino == b->stat.st_ino - && (a->flags&LUMIERA_FILE_MASK) == (b->flags&LUMIERA_FILE_MASK); + const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya; + const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb; + + if (a->stat.st_dev < b->stat.st_dev) + return -1; + else if (a->stat.st_dev > b->stat.st_dev) + return 1; + + if (a->stat.st_ino < b->stat.st_ino) + return -1; + else if (a->stat.st_ino > b->stat.st_ino) + return 1; + + if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK)) + return -1; + else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK)) + return 1; + + return 0; } + +static void +delete_fn (PSplaynode node) +{ + lumiera_filedescriptor_delete ((LumieraFiledescriptor) node); +} + + +static const void* +key_fn (const PSplaynode node) +{ + return node; +} + + + void lumiera_filedescriptor_registry_init (void) { @@ -89,9 +92,7 @@ lumiera_filedescriptor_registry_init (void) TRACE (filedescriptor); REQUIRE (!registry); - registry = cuckoo_new (h1, h2, h3, cmp, - sizeof (LumieraFiledescriptor), - 3); + registry = psplay_new (cmp_fn, key_fn, delete_fn); if (!registry) LUMIERA_DIE (NO_MEMORY); @@ -103,12 +104,12 @@ void lumiera_filedescriptor_registry_destroy (void) { TRACE (filedescriptor); - REQUIRE (!cuckoo_nelements (registry)); + REQUIRE (!psplay_nelements (registry)); RESOURCE_FORGET (filedescriptor, registry_mutex.rh); if (registry) - cuckoo_free (registry); + psplay_destroy (registry); registry = NULL; } @@ -162,10 +163,9 @@ lumiera_filedescriptor_acquire (const char* name, int flags) } /* lookup/create descriptor */ - dest = &fdesc; - LumieraFiledescriptor* found = cuckoo_find (registry, &dest); + dest = (LumieraFiledescriptor) psplay_find (registry, &fdesc, 100); - if (!found) + if (!dest) { TRACE (filedescriptor, "Descriptor not found"); @@ -173,12 +173,11 @@ lumiera_filedescriptor_acquire (const char* name, int flags) if (!dest) goto error; - cuckoo_insert (registry, &dest); + psplay_insert (registry, &dest->node, 100); } else { TRACE (filedescriptor, "Descriptor already existing"); - dest = *found; ++dest->refcount; } error: ; @@ -191,7 +190,7 @@ lumiera_filedescriptor_acquire (const char* name, int flags) void lumiera_filedescriptor_release (LumieraFiledescriptor self) { - TRACE (filedescriptor); + TRACE (filedescriptor, "%p", self); if (!--self->refcount) lumiera_filedescriptor_delete (self); } @@ -203,6 +202,7 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template) LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor)); TRACE (filedescriptor, "at %p", self); + psplaynode_init (&self->node); self->stat = template->stat; self->flags = template->flags; @@ -224,7 +224,7 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self) { REQUIRE (self->refcount == 0); - cuckoo_remove (registry, cuckoo_find (registry, &self)); + psplay_remove (registry, &self->node); TODO ("destruct other members (WIP)"); diff --git a/src/backend/filedescriptor.h b/src/backend/filedescriptor.h index 668419b10..d91296956 100644 --- a/src/backend/filedescriptor.h +++ b/src/backend/filedescriptor.h @@ -23,6 +23,7 @@ #define LUMIERA_FILEDESCRIPTOR_H #include "lib/mutex.h" +#include "lib/psplay.h" #include @@ -47,7 +48,8 @@ typedef lumiera_filedescriptor* LumieraFiledescriptor; struct lumiera_filedescriptor_struct { - struct stat stat; /* create after first open, maintained metadata, MUST BE FIRST! */ + psplaynode node; /* node for the lookup tree */ + struct stat stat; /* create after first open, maintained metadata */ int flags; /* open flags, must be masked for reopen */ lumiera_mutex lock; /* locks operations on this file descriptor */ unsigned refcount; /* reference counter, all users sans registry */ diff --git a/tests/20filedescriptor.tests b/tests/20filedescriptor.tests index 78639e7b8..03d6fb2ac 100644 --- a/tests/20filedescriptor.tests +++ b/tests/20filedescriptor.tests @@ -13,6 +13,18 @@ END rm ,tmp_testfile +echo testdata > ,tmp_testfile1 +echo testdata > ,tmp_testfile2 +echo testdata > ,tmp_testfile3 + +TEST "acquire 3 files" acquire_existing_3files < Date: Fri, 5 Sep 2008 06:40:19 +0200 Subject: [PATCH 091/102] use psplay trees instead cuckoo hashes in config_lookup --- src/backend/config_lookup.c | 182 +++++++++++++----------------------- src/backend/config_lookup.h | 21 +++-- 2 files changed, 79 insertions(+), 124 deletions(-) diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c index 88fd8b102..12f8ae023 100644 --- a/src/backend/config_lookup.c +++ b/src/backend/config_lookup.c @@ -26,41 +26,30 @@ /* we only use one fatal error for now, when allocation in the config system fail, something else is pretty wrong */ LUMIERA_ERROR_DEFINE (CONFIG_LOOKUP, "config lookup failure"); - -static size_t -h1 (const void* item, const uint32_t r); - -static size_t -h2 (const void* item, const uint32_t r); - -static size_t -h3 (const void* item, const uint32_t r); - +/* + support functions for the splay tree +*/ static int -cmp (const void* keya, const void* keyb); +cmp_fn (const void* a, const void* b); static void -dtor (void* item); - -static void -mov (void* dest, void* src, size_t size); +delete_fn (PSplaynode node); +static const void* +key_fn (const PSplaynode node); /** * @file - * Implementation of the lookup of configuration keys using a cuckoo hash. + * Implementation of the lookup of configuration keys */ + LumieraConfigLookup lumiera_config_lookup_init (LumieraConfigLookup self) { TRACE (config_lookup); - self->hash = cuckoo_new (sizeof (lumiera_config_lookupentry), &(struct cuckoo_vtable){h1, h2, h3, cmp, dtor, mov}); - - if (!self->hash) - LUMIERA_DIE (CONFIG_LOOKUP); - + psplay_init (&self->tree, cmp_fn, key_fn, delete_fn); return self; } @@ -70,7 +59,7 @@ lumiera_config_lookup_destroy (LumieraConfigLookup self) { TRACE (config_lookup); if (self) - cuckoo_delete (self->hash); + psplay_destroy (&self->tree); return self; } @@ -84,20 +73,14 @@ lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item) REQUIRE (item->key); REQUIRE (item->key_size); - lumiera_config_lookupentry tmp; FIXME ("implement section prefix/suffix for the key"); - lumiera_config_lookupentry_init (&tmp, lumiera_tmpbuf_strcat3 (NULL, 0, item->key, item->key_size, NULL, 0)); - - LumieraConfigLookupentry entry = cuckoo_find (self->hash, &tmp); + const char* key = lumiera_tmpbuf_strcat3 (NULL, 0, item->key, item->key_size, NULL, 0); + LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100); if (!entry) - entry = cuckoo_insert (self->hash, &tmp); - - if (entry) - llist_insert_head (&entry->configitems, &item->lookup); - else - LUMIERA_DIE (CONFIG_LOOKUP); + entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100); + llist_insert_head (&entry->configitems, &item->lookup); return entry; } @@ -111,19 +94,13 @@ lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigite REQUIRE (item->key); REQUIRE (item->key_size); - lumiera_config_lookupentry tmp; - lumiera_config_lookupentry_init (&tmp, lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s", item->key_size, item->key)); - - LumieraConfigLookupentry entry = cuckoo_find (self->hash, &tmp); - + const char* key = lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s", item->key_size, item->key); + LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100); if (!entry) - entry = cuckoo_insert (self->hash, &tmp); - - if (entry) - llist_insert_tail (&entry->configitems, &item->lookup); - else - LUMIERA_DIE (CONFIG_LOOKUP); + entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100); + TODO ("else check that no 'default' item already exists, that is, the tail element's parent points to the 'defaults' in config"); + llist_insert_tail (&entry->configitems, &item->lookup); return entry; } @@ -132,14 +109,14 @@ LumieraConfigitem lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) { TRACE (config_lookup); - REQUIRE (!llist_is_empty (&item->lookup), "item is not in a lookup hash"); + REQUIRE (!llist_is_empty (&item->lookup), "item is not in a lookup"); if (llist_is_single (&item->lookup)) { - /* last item in lookup, remove it from hash */ - LumieraConfigLookupentry entry = (LumieraConfigLookupentry)llist_next (&item->lookup); + /* last item in lookup, remove it from the splay tree */ + LumieraConfigLookupentry entry = LLIST_TO_STRUCTP (llist_next (&item->lookup), lumiera_config_lookupentry, configitems); llist_unlink (&item->lookup); - cuckoo_remove (self->hash, entry); + psplay_remove (&self->tree, (PSplaynode)entry); } else { @@ -150,16 +127,12 @@ lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) return item; } + LumieraConfigLookupentry lumiera_config_lookup_find (LumieraConfigLookup self, const char* key) { TRACE (config_lookup); - - /* fast temporary init without strdup */ - lumiera_config_lookupentry tmp; - tmp.full_key = (char*)key; - - return cuckoo_find (self->hash, &tmp); + return (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100); } @@ -177,6 +150,7 @@ lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key) return NULL; } + LumieraConfigitem lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) { @@ -194,15 +168,39 @@ lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) /* - Hash table entries + Lookup entries */ LumieraConfigLookupentry lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key) { TRACE (config_lookup, "key = %s", key); - self->full_key = lumiera_strndup (key, SIZE_MAX); - llist_init (&self->configitems); + if (self) + { + psplaynode_init (&self->node); + llist_init (&self->configitems); + self->full_key = lumiera_strndup (key, SIZE_MAX); + } + return self; +} + + +LumieraConfigLookupentry +lumiera_config_lookupentry_new (const char* key) +{ + return lumiera_config_lookupentry_init (lumiera_malloc (sizeof (lumiera_config_lookupentry)), key); +} + + +LumieraConfigLookupentry +lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self) +{ + TRACE (config_lookup); + if (self) + { + REQUIRE (llist_is_empty (&self->configitems), "lookup node still in use"); + lumiera_free (self->full_key); + } return self; } @@ -210,79 +208,27 @@ lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key) void lumiera_config_lookupentry_delete (LumieraConfigLookupentry self) { - TRACE (config_lookup); - REQUIRE (llist_is_empty (&self->configitems), "lookup node still in use"); - lumiera_free (self->full_key); -} - - - - -/* - Support functions for the cuckoo hash -*/ - -static size_t -h1 (const void* item, const uint32_t r) -{ - REQUIRE (item); - REQUIRE (((LumieraConfigLookupentry)item)->full_key); - size_t hash = r; - for (const char* s = ((LumieraConfigLookupentry)item)->full_key; *s; ++s) - hash = *s ^ ~(*s << 5) ^ (hash << 3) ^ (hash >> 7); - return hash; -} - -static size_t -h2 (const void* item, const uint32_t r) -{ - REQUIRE (item); - REQUIRE (((LumieraConfigLookupentry)item)->full_key); - size_t hash = r; - for (const char* s = ((LumieraConfigLookupentry)item)->full_key; *s; ++s) - hash = *s ^ ~(*s << 7) ^ (hash << 3) ^ (hash >> 5); - return hash; -} - -static size_t -h3 (const void* item, const uint32_t r) -{ - REQUIRE (item); - REQUIRE (((LumieraConfigLookupentry)item)->full_key); - size_t hash = r; - for (const char* s = ((LumieraConfigLookupentry)item)->full_key; *s; ++s) - hash = *s ^ ~(*s << 3) ^ (hash << 5) ^ (hash >> 7); - return hash; + lumiera_free (lumiera_config_lookupentry_destroy (self)); } static int -cmp (const void* keya, const void* keyb) +cmp_fn (const void* a, const void* b) { - REQUIRE (keya); - REQUIRE (((LumieraConfigLookupentry)keya)->full_key); - REQUIRE (keyb); - REQUIRE (((LumieraConfigLookupentry)keyb)->full_key); - return !strcmp (((LumieraConfigLookupentry)keya)->full_key, ((LumieraConfigLookupentry)keyb)->full_key); + return strcmp ((const char*)a, (const char*)b); } static void -dtor (void* item) +delete_fn (PSplaynode node) { - if (((LumieraConfigLookupentry)item)->full_key) - { - REQUIRE (llist_is_empty (&((LumieraConfigLookupentry)item)->configitems), "lookup node still in use"); - lumiera_free (((LumieraConfigLookupentry)item)->full_key); - } + lumiera_config_lookupentry_delete ((LumieraConfigLookupentry) node); } -static void -mov (void* dest, void* src, size_t size) -{ - ((LumieraConfigLookupentry)dest)->full_key = ((LumieraConfigLookupentry)src)->full_key; - llist_init (&((LumieraConfigLookupentry)dest)->configitems); - llist_insertlist_next (&((LumieraConfigLookupentry)dest)->configitems, &((LumieraConfigLookupentry)src)->configitems); -} +static const void* +key_fn (const PSplaynode node) +{ + return ((LumieraConfigLookupentry) node)->full_key; +} /* // Local Variables: diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h index 42c06842e..a0ec20dd5 100644 --- a/src/backend/config_lookup.h +++ b/src/backend/config_lookup.h @@ -22,7 +22,7 @@ #ifndef LUMIERA_CONFIG_LOOKUP_H #define LUMIERA_CONFIG_LOOKUP_H -#include "lib/cuckoo.h" +#include "lib/psplay.h" #include "lib/llist.h" #include "lib/error.h" @@ -41,8 +41,8 @@ typedef lumiera_config_lookupentry* LumieraConfigLookupentry; /** * @file - * Lookup of configuration keys. Configuration key are dynamically stored in a hashtable - * this happens for defaults, loaded config files and entries which are set explicitly. + * Lookup of configuration keys. Configuration keys are dynamically stored in a splay tree. + * This happens for defaults, loaded config files and entries which are set explicitly. * The system maintains no central registry of all possible keys. * We store here the full keys of configentries as well as the keys of section prefixes. * Section prefixes are stored with a trailing dot to disambiguate them from entry keys. @@ -56,7 +56,7 @@ LUMIERA_ERROR_DECLARE (CONFIG_LOOKUP); */ struct lumiera_config_lookup_struct { - Cuckoo hash; + psplay tree; }; /** @@ -153,12 +153,15 @@ lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) */ struct lumiera_config_lookupentry_struct { - /* stack of all configitems stored under this key MUST BE FIRST IN THIS STRUCT */ + psplaynode node; + /* stack of all configitems stored under this key */ llist configitems; + /* we store a copy of the full key here configentry keys are complete as expected - section keys are the prefix stored with a trailing dot, suffixes will be found by iteration + section keys are the prefix stored with a trailing dot, + suffixes will be found by iterative search */ char* full_key; }; @@ -168,11 +171,17 @@ struct lumiera_config_lookupentry_struct LumieraConfigLookupentry lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key); +LumieraConfigLookupentry +lumiera_config_lookupentry_new (const char* key); + /* internal */ LumieraConfigLookupentry lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self); +void +lumiera_config_lookupentry_delete (LumieraConfigLookupentry self); + #endif /* // Local Variables: From 21db988e18c514fb0014b86d3a4a0553c096d7b7 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 5 Sep 2008 06:43:26 +0200 Subject: [PATCH 092/102] remove the default return in case an illegal config entry was found Fallback to a default in case of a already pending error is not needed. This would only obtruse error handling. If the default entry would be erroneous it would be silently ignored and make the thing worse. --- src/backend/config_typed.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c index 02e75d0db..07c2bb486 100644 --- a/src/backend/config_typed.c +++ b/src/backend/config_typed.c @@ -80,9 +80,6 @@ lumiera_config_number_get (const char* key, long long* value) else { LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE); - /* try default instead */ - if (!lumiera_config_get_default (key, &raw_value)) - sscanf (raw_value, "%Li", value); } } else From fa54fb9bc2b6a304f0b9fd564d7181f174f2483a Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 5 Sep 2008 06:44:42 +0200 Subject: [PATCH 093/102] add a diagnostic config dump function --- src/backend/config.c | 19 +++++++++++++++++++ src/backend/config.h | 9 ++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/backend/config.c b/src/backend/config.c index 9cb532780..731567596 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -274,6 +274,25 @@ lumiera_config_setdefault (const char* line) } +void +lumiera_config_dump (FILE* out) +{ + fprintf (out, "# registered defaults:\n"); + + LLIST_FOREACH (&lumiera_global_config->defaults.childs, node) + fprintf (out, "%s\n", ((LumieraConfigitem) node)->line); + + fprintf (out, "# end of defaults\n\n"); + +#if 0 /*TODO UNIMPLEMENTED */ + fprintf (out, "# files:\n"); + lumiera_configitem files; + fprintf (out, "# volatiles:") + lumiera_configitem TODO_unknown; +#endif +} + + int lumiera_config_reset (const char* key) { diff --git a/src/backend/config.h b/src/backend/config.h index e5363796d..f0df796db 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -55,7 +55,7 @@ LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT); //TODO: System includes// #include - +#include /** * @file @@ -153,6 +153,13 @@ int lumiera_config_purge (const char* filename); +/** + * Does a diagnostic dump of the whole config database + */ +void +lumiera_config_dump (FILE* out); + + // * {{{ lumiera_config_get(...) }}} // * get a value by key // * handles internally everything as string:string key:value pair. From a95ae05ddbb9b3a45bb81ec1850db3c9352d2fe1 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Fri, 5 Sep 2008 06:47:10 +0200 Subject: [PATCH 094/102] some cosmetics --- src/backend/config.c | 4 ++-- src/backend/config.h | 2 +- src/backend/configitem.c | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index 731567596..ce6da174f 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -194,7 +194,7 @@ lumiera_config_get_default (const char* key, const char** value) int ret = -1; TODO ("follow '<' delegates?"); - TODO ("refactor _get and get_default to iterator access"); + TODO ("refactor _get and get_default to iterator access (return LList or Lookupentry)"); LumieraConfigitem item = lumiera_config_lookup_item_tail_find (&lumiera_global_config->keys, key); if (item && item->parent == &lumiera_global_config->defaults) @@ -220,7 +220,7 @@ lumiera_config_set (const char* key, const char* delim_value) TODO (" find matching suffix"); TODO (" find proper prefix indentation, else use config.indent"); TODO (" create configitem with prefix/suffix removed"); - + // * set a value by key diff --git a/src/backend/config.h b/src/backend/config.h index f0df796db..fea04b3b6 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -80,7 +80,7 @@ struct lumiera_config_struct 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 transaction al yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair + 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; }; diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 0d7830b87..917676251 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -146,6 +146,7 @@ lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source) self->key_size = source->key_size; self->delim = source->delim; self->vtable = source->vtable; + return self; } @@ -296,20 +297,20 @@ lumiera_configitem_parse (LumieraConfigitem self, const char* line) /* skip blanks */ itr += self->key_size; - while (*itr && isspace(*itr)) + while (*itr && isspace (*itr)) itr++; if (self->key_size && *itr == '=') { /*this configentry assigns a value to a key*/ self->delim = itr; - self->vtable = &lumiera_configentry_funcs; + self->vtable = &lumiera_configentry_funcs; } else if (self->key_size && *itr == '<') { /*this configentry is a redirect*/ self->delim = itr; - self->vtable = &lumiera_configentry_funcs; + self->vtable = &lumiera_configentry_funcs; } else { From b94e615291bd6012c5cf4e945b969c809b161a0c Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 6 Sep 2008 07:52:55 +0200 Subject: [PATCH 095/102] just psplay_remove leaked, do psplay_delete_node --- src/backend/config_lookup.c | 2 +- src/backend/configitem.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c index 12f8ae023..96c62c880 100644 --- a/src/backend/config_lookup.c +++ b/src/backend/config_lookup.c @@ -116,7 +116,7 @@ lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item) /* last item in lookup, remove it from the splay tree */ LumieraConfigLookupentry entry = LLIST_TO_STRUCTP (llist_next (&item->lookup), lumiera_config_lookupentry, configitems); llist_unlink (&item->lookup); - psplay_remove (&self->tree, (PSplaynode)entry); + psplay_delete_node (&self->tree, (PSplaynode)entry); } else { diff --git a/src/backend/configitem.c b/src/backend/configitem.c index 917676251..6252b0bcf 100644 --- a/src/backend/configitem.c +++ b/src/backend/configitem.c @@ -74,17 +74,17 @@ lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup) if (self) { + LLIST_WHILE_HEAD (&self->childs, node) + lumiera_configitem_delete ((LumieraConfigitem) node, lookup); + + ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); + if (self->vtable && self->vtable->destroy) self->vtable->destroy (self); if (!llist_is_empty (&self->lookup)) lumiera_config_lookup_remove (lookup, self); - LLIST_WHILE_HEAD (&self->childs, node) - lumiera_configitem_delete ((LumieraConfigitem) node, lookup); - - ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs"); - llist_unlink (&self->link); lumiera_free (self->line); } From 477ecd39742c30041307061fcc57ca792287d231 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sat, 6 Sep 2008 08:00:55 +0200 Subject: [PATCH 096/102] Remove the 'path' member from the config and bootstrap the config system * the path parameter given to config_init becomes a registered default value for 'config.path' itself thus the config system finds its data path on itself. * the printf formatting string for representing values are also bootstrapped as default entries in the config system. This is just a prelimary example and will be refined later --- src/backend/config.c | 42 +++++++++++++++++++++++++++++++++++++++--- src/backend/config.h | 2 -- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/backend/config.c b/src/backend/config.c index ce6da174f..276088673 100644 --- a/src/backend/config.c +++ b/src/backend/config.c @@ -52,6 +52,39 @@ LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_VALUE, "syntax error in value"); LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "no configuration entry"); LUMIERA_ERROR_DEFINE (CONFIG_DEFAULT, "illegal default value"); +/** + * defaults for the configuraton system itself + */ +const char* lumiera_config_defaults[] = + { + /* Low level formating, don't change these */ + "config.formatstr.link = '< %s'", + "config.formatstr.number.dec = '= %lld'", + "config.formatstr.number.hex = '= 0x%llX'", + "config.formatstr.number.oct = '= 0%llo'", + "config.formatstr.real = '= %Lg'", + "config.formatstr.real.dec = '= %Lf'", + "config.formatstr.real.sci = '= %Le'", + "config.formatstr.string = '=%s'", + "config.formatstr.string.dquoted = '= \"%s\"'", + "config.formatstr.string.quoted = '= ''%s'''", + "config.formatstr.word = '= %s'", + "config.formatstr.bool = '= %d'", + + /* default representations per type */ + "config.formatdef.link < config.formatstr.link", + "config.formatdef.number < config.formatstr.number.dec", + "config.formatdef.real < config.formatstr.real", + "config.formatdef.string < config.formatstr.string", + "config.formatdef.word < config.formatstr.word", + "config.formatdef.bool < config.formatstr.bool", + + /* per key formatting override stored under */ + "config.formatkey ='config.format.%s'", + + NULL + }; + /* singleton config */ LumieraConfig lumiera_global_config = NULL; @@ -72,7 +105,6 @@ lumiera_config_init (const char* path) NOBUG_INIT_FLAG (config_lookup); lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config)); - lumiera_global_config->path = lumiera_strndup (path, SIZE_MAX); lumiera_config_lookup_init (&lumiera_global_config->keys); lumiera_configitem_init (&lumiera_global_config->defaults); @@ -81,7 +113,12 @@ lumiera_config_init (const char* path) lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config)); - TODO ("register path as config.path itself"); + lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "config.path = %s", path)); + + for (const char** itr = lumiera_config_defaults; *itr; ++itr) + { + lumiera_config_setdefault (*itr); + } return 0; } @@ -98,7 +135,6 @@ lumiera_config_destroy () lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys); lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys); lumiera_config_lookup_destroy (&lumiera_global_config->keys); - lumiera_free (lumiera_global_config->path); lumiera_free (lumiera_global_config); lumiera_global_config = NULL; } diff --git a/src/backend/config.h b/src/backend/config.h index fea04b3b6..7667f26f1 100644 --- a/src/backend/config.h +++ b/src/backend/config.h @@ -73,8 +73,6 @@ 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 */ - char* path; - /* all access is protected with rwlock's. We use rwlocks here since concurrent reads are likely common. From 5f5f8298bce662ac4f7cf9d8ccb398592e8214c3 Mon Sep 17 00:00:00 2001 From: Michael Ploujnikov Date: Sat, 6 Sep 2008 16:36:18 -0400 Subject: [PATCH 097/102] don't need to use builddir, yet All objects are dumped in the same directory at the moment. --- tests/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 564c8a454..f128693c1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,12 +39,12 @@ test_llist_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-safeclib test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_safeclib_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_safeclib_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-uuid test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -test_uuid_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm +test_uuid_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm check_PROGRAMS += test-references test_references_SOURCES = $(tests_srcdir)/library/test-references.c From 115620fbb5f55ee935d04fd3db0d5dc983d872a0 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 7 Sep 2008 03:41:37 +0200 Subject: [PATCH 098/102] FIX: luid tests, forgotten to rename uuid to luid --- tests/15luid.tests | 6 +++--- tests/library/test-luid.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/15luid.tests b/tests/15luid.tests index 072b2545e..84e50c6de 100644 --- a/tests/15luid.tests +++ b/tests/15luid.tests @@ -1,10 +1,10 @@ -TESTING "UUID's" ./test-uuid +TESTING "LUID's" ./test-luid -TEST "uuid generate" uuidgen_2 < Date: Sun, 7 Sep 2008 20:55:14 +0200 Subject: [PATCH 099/102] some tweaks to the Doxygen, to improve the arrangement of the various sections within the documentation of one class --- doc/devel/Doxyfile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/devel/Doxyfile b/doc/devel/Doxyfile index f43b69042..9b276233e 100644 --- a/doc/devel/Doxyfile +++ b/doc/devel/Doxyfile @@ -5,12 +5,12 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = Lumiera -PROJECT_NUMBER = 3.0+alpha +PROJECT_NUMBER = 0.1+pre OUTPUT_DIRECTORY = CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = NO +REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ @@ -22,7 +22,7 @@ ABBREVIATE_BRIEF = "The $name class" \ a \ an \ the -ALWAYS_DETAILED_SEC = NO +ALWAYS_DETAILED_SEC = YES INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = ../../src/ \ @@ -32,7 +32,7 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = NO +DETAILS_AT_TOP = YES INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 @@ -66,7 +66,7 @@ CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = NO SORT_BRIEF_DOCS = YES SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO @@ -90,7 +90,7 @@ WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = +WARN_LOGFILE = warnings.txt #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- @@ -182,7 +182,7 @@ HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDNAME = "Lumiera Doxygen docs" DOCSET_BUNDLE_ID = org.doxygen.Project HTML_DYNAMIC_SECTIONS = NO CHM_FILE = From 7415752f191e03df6e96f0368fefe7743b260cab Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 7 Sep 2008 23:10:29 +0200 Subject: [PATCH 100/102] scons: change test for NoBug to use pkg-config --- SConstruct | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index 9c56cece3..9660003ef 100644 --- a/SConstruct +++ b/SConstruct @@ -183,8 +183,10 @@ def configurePlatform(env): if not conf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'): problems.append('Functions for runtime dynamic loading not available.') - if not conf.CheckLibWithHeader('nobugmt', 'nobug.h', 'C'): + if not conf.CheckPkgConfig('nobugmt', 0.3): problems.append('Did not find NoBug [http://www.pipapo.org/pipawiki/NoBug].') + else: + conf.env.mergeConf('nobugmt') if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'C'): problems.append('Did not find the pthread lib or pthread.h.') From deec68422cd0d787b64a554d5438b8334d908f76 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 7 Sep 2008 23:43:06 +0200 Subject: [PATCH 101/102] scons: simplify how library tests are built --- tests/SConscript | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/SConscript b/tests/SConscript index e662ca044..0abf7d393 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -5,6 +5,7 @@ from os import path from Buildhelper import srcSubtree +from Buildhelper import scanSubtree from Buildhelper import globRootdirs Import('env','artifacts','core') @@ -31,6 +32,15 @@ def testExecutable(env,tree, exeName=None, obj=None): return env.Program('#$BINDIR/'+exeName, obj + core) +def testCollection(env,dir): + """ treat a Directory containing a collection of standalone tests. + Link each of them into an independent executable + """ + exeName = lambda p: path.basename(path.splitext(p)[0]) + buildIt = lambda p: env.Program("#$BINDIR/"+exeName(p), [p] + core) + return [buildIt(f) for f in scanSubtree(dir)] + + def treatPluginTestcase(env): """ Special case: the test-plugin executable """ @@ -56,19 +66,14 @@ def treatPluginTestcase(env): moduledirs = globRootdirs('*') # but have to treat some subdirs individually. -specials = ['plugin','locking','library','backend'] +specials = ['plugin','library','backend'] artifacts['testsuite'] = ts = ( [ testExecutable(env, dir) for dir in moduledirs if not dir in specials] + treatPluginTestcase(env) - + testExecutable(env, 'locking', obj=['test-locking.c','mutex.c','condition.c']) - + testExecutable(env, 'library', exeName='test-llist', obj=['test-llist.c']) - + testExecutable(env, 'library', exeName='test-references', obj=['test-references.c']) - + testExecutable(env, 'library', exeName='test-safeclib', obj=['test-safeclib.c']) - + testExecutable(env, 'library', exeName='test-uuid', obj=['test-uuid.c']) - + testExecutable(env, 'backend', exeName='test-filedescriptors', obj=['test-filedescriptors.c']) - + testExecutable(env, 'backend', exeName='test-filehandles', obj=['test-filehandles.c']) + + testCollection(env, 'library') + + testCollection(env, 'backend') ) From 998da8a221250e53637419b082e286cea1c7458e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 8 Sep 2008 01:02:14 +0200 Subject: [PATCH 102/102] migrated TODOs from the TiddlyWiki to the lumiera-work Mailinglist --- src/proc/asset/proc.cpp | 2 +- src/proc/asset/proc.hpp | 2 +- wiki/todo.html | 55 ++++++++++++++++------------------------- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/proc/asset/proc.cpp b/src/proc/asset/proc.cpp index 3720f0993..61dd228b7 100644 --- a/src/proc/asset/proc.cpp +++ b/src/proc/asset/proc.cpp @@ -1,5 +1,5 @@ /* - Proc(Asset) - key abstraction: media-like assets + Proc(Asset) - key abstraction: data-processing assets Copyright (C) Lumiera.org 2008, Hermann Vosseler diff --git a/src/proc/asset/proc.hpp b/src/proc/asset/proc.hpp index 724c8a786..5b68d3d0f 100644 --- a/src/proc/asset/proc.hpp +++ b/src/proc/asset/proc.hpp @@ -1,5 +1,5 @@ /* - PROC.hpp - key abstraction: media-like assets + PROC.hpp - key abstraction: data-processing assets Copyright (C) Lumiera.org 2008, Hermann Vosseler diff --git a/wiki/todo.html b/wiki/todo.html index 763c8a80a..73d716def 100644 --- a/wiki/todo.html +++ b/wiki/todo.html @@ -1979,7 +1979,7 @@ see : <<tag RSSFeed>> for the full list. -
+
! Foundations, not really a milestone yet
 
 We need following in a basically working / mockup state:
@@ -2007,6 +2007,11 @@ We need following in a basically working / mockup state:
 !!! Next Goals
 
 # Make a [[video player mockup]]
+# Integrate a ''Version 0.1'' able to
+#* load a simple media
+#* put a clip to the EDL
+#* build the corresponding low-level model
+#* run a render process
 
 ! Second round
 //all rather brainstorming for now, feel free to modify...//
@@ -3279,32 +3284,25 @@ function addKeyDownHandlers(e)
 }
 //}}}
-
+
! Proc layer
  by ichtho
-!! Asset Manager, Asset and ~MObject
-Design roughly finished, mem management with smart-ptrs and object dependencies working, Asset Manager (automatic registry) working. Relation of Assets and MObjects needs some clarification. Object creation could use some refactoring (work in progress)
-!! Support for Media Bins, high-level Resource manager
-not even concrete plans yet. Needing a volounteer to take this subsystem
-!! Session, EDL, edit operations
-Session Manager (access point/interface) done. Basic operations (how to address objects in the EDL, how to add objects...) only drafted, need detailed design (but is difficult before the builder is more clear, so I'll probably work bottom up here)
-!! Framework for storing/loading objects
-Just a draft in a separate branch, nothing finished.
-!! Defaults Manager ~ConfigQuery subsystem
-Defaults Manager done, using a mock implementation of for config queries. Need to understand better what queries we need to support, what predicates to define, how to describe capabilities. Basically it's too early to nail down a design
-!! integrating YAP Prolog or another resolution system
-blocked because of the preceeding. But it would be possible to implement the basics (i.e. calling in, passing rule code....)
-!! create Fixture from all ~EDLs
-Design partially done, nothing implemented yet.
-!! create Partitioning of Fixture
-Some ideas; blocked because of incomplete design of the EDL
+//the following were migrated to the lumiera-work Mailinglist as of 9/08 //
+* Asset Manager, Asset and ~MObject
+* Support for Media Bins, high-level Resource manager
+* Session, EDL, edit operations
+* Framework for storing/loading objects
+* Defaults Manager ~ConfigQuery subsystem
+* integrating YAP Prolog or another resolution system
+* create Fixture from all ~EDLs
+* create Partitioning of Fixture
+* Automation handling
+
+
 !! Builder core
 support framework done. Design/planning of node creater tool partially done, implementation just started
 !! Render nodes
-nothing but a preliminary object hierarchy. Need to work out the interface.
-!! Automation handling
-just a draft. Need to work out interface for describing automatable "parameters"
-
+Interface and outline of the "operaton protocol" is done as of 8/08. Details of the implementation in work.
 
 ! Backend
  by cehteh
@@ -3330,24 +3328,13 @@ Basic implementation finished, not final yet.
 !! Testsuite
 Needs some improvements, see [[Tasks]]
 !! Website
-A mockup website is online, raffa experimenting with asciidoc which looks good so far. git integration and automatic generation on push to be done see [[Tasks]]
+A mockup website is online, raffa experimenting with asciidoc which looks good so far. See [[Tasks]]
 !! git / mob repos
 gitweb is up, git repos are established, mob repos are not yet up.
 !! automatic generation and checkout of tiddlywikis and doxygen docs on the server
 currently only a manual rsync script in admin/
 !! automatic builds/test on server, status page
 will be done on the 'devel' vserver. nothing done yet.
-!! Developer Documentation
-Someone might pickup a Doxygen-Maintainer. This is not writing actual documentation but bringing the Documentation comments in the source to a good shape, add formatting tags, ensureing that all docs are properly generated, maintaining a glossary and index, define the order etc.
-
-
-
-
Use the backend, gmerlin/avdecoder and a Player widget to playback videos. This should be a small application which can open and playback many videos from one instance in parallel. Later on scrubbing for this videos might be supported.
-
-The idea here is to show and measure backend and scheduler performance
-  and beeing a proof of concept for the design. It will run
-  independent of the Proc layer but needs quite some work on the
-  backend to be done.