diff --git a/Makefile.am b/Makefile.am index bf7ebec19..e6f29bf97 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,8 @@ SUBDIRS = include $(top_srcdir)/admin/Makefile.am # core +include $(top_srcdir)/src/proc/Makefile.am +include $(top_srcdir)/src/common/Makefile.am include $(top_srcdir)/src/lib/Makefile.am include $(top_srcdir)/src/backend/Makefile.am @@ -40,6 +42,8 @@ include $(top_srcdir)/src/backend/Makefile.am #include $(top_srcdir)/src... # tests +include $(top_srcdir)/tests/common/Makefile.am +include $(top_srcdir)/tests/components/Makefile.am include $(top_srcdir)/tests/Makefile.am include $(top_srcdir)/tests/plugin/Makefile.am diff --git a/admin/vgsuppression.c b/admin/vgsuppression.c index 0e1f41fca..cad026e52 100644 --- a/admin/vgsuppression.c +++ b/admin/vgsuppression.c @@ -18,7 +18,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define _GNU_SOURCE /* just place any problematic calls where valgrind whines about in main (with comments please) diff --git a/configure.ac b/configure.ac index 78d76c136..b72b7dfee 100644 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,8 @@ AC_COPYRIGHT([ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ]) +AC_GNU_SOURCE + # # Required programs # @@ -37,11 +39,12 @@ AC_PROG_LIBTOOL # test for headers # AC_STDC_HEADERS -AC_CHECK_HEADER([nobug.h], AC_DEFINE(HAVE_NOBUG_H)) -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)) ACX_PTHREAD +LIBS="$PTHREAD_LIBS $LIBS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +CC="$PTHREAD_CC" + ##AM_CONDITIONAL([HAVE_THREADING], [test x"$acx_pthread_ok" = xyes]) @@ -71,9 +74,62 @@ AC_ARG_ENABLE(release, AC_HELP_STRING([--enable-release], [select NoBug RELEASE nobug_level=alpha AC_DEFINE(EBUG_ALPHA) )])]) -AC_MSG_RESULT([NoBug build level: $nobug_level]) # END NoBug +# 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)) + +AC_LANG_POP([C]) + + +# C++ headers and libraries +AC_LANG_PUSH([C++]) + +AC_CHECK_HEADER([tr1/memory], + , + AC_MSG_ERROR([std::tr1 proposed standard extension for shared_ptr missing]) + ) + +AC_CHECK_HEADER([boost/shared_ptr.hpp], + , + AC_MSG_ERROR([boost::shared_ptr missing (http://www.boost.org/)]) + ) + +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? + +AC_CHECK_HEADER([boost/regex.hpp], + , + AC_MSG_ERROR([boost::regex missing (http://www.boost.org/)]) + ) + +AC_LANG_POP([C++]) + + +# Print a summary +AC_MSG_RESULT([ +Configuration Summary:]) +AC_MSG_RESULT([ NoBug build level: $nobug_level]) +# Add more summary results here + +AC_MSG_RESULT([ +Configuration complete, you can now build Lumiera with 'make' +]) AC_CONFIG_FILES(Makefile) AC_OUTPUT diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 5f693f8bf..8b33df06a 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -21,17 +21,20 @@ 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)/backend.c \ - $(liblumibackend_a_srcdir)/file.c \ - $(liblumibackend_a_srcdir)/filehandle.c \ - $(liblumibackend_a_srcdir)/filedescriptor.c \ +liblumibackend_a_SOURCES = \ + $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ + $(liblumibackend_a_srcdir)/backend.c \ + $(liblumibackend_a_srcdir)/file.c \ + $(liblumibackend_a_srcdir)/filehandle.c \ + $(liblumibackend_a_srcdir)/filedescriptor.c \ $(liblumibackend_a_srcdir)/filehandlecache.c -noinst_HEADERS += \ - $(liblumibackend_a_srcdir)/backend.h \ - $(liblumibackend_a_srcdir)/file.h \ - $(liblumibackend_a_srcdir)/filehandle.h \ - $(liblumibackend_a_srcdir)/filedescriptor.h \ + +noinst_HEADERS += \ + $(liblumibackend_a_srcdir)/mediaaccessfacade.cpp \ + $(liblumibackend_a_srcdir)/backend.h \ + $(liblumibackend_a_srcdir)/file.h \ + $(liblumibackend_a_srcdir)/filehandle.h \ + $(liblumibackend_a_srcdir)/filedescriptor.h \ $(liblumibackend_a_srcdir)/filehandlecache.h diff --git a/src/backend/backend.c b/src/backend/backend.c new file mode 100644 index 000000000..024f7e6f8 --- /dev/null +++ b/src/backend/backend.c @@ -0,0 +1,53 @@ +/* + backend - common lumiera backend things + + 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 "backend/backend.h" +#include "backend/filehandlecache.h" +#include "backend/filedescriptor.h" + +//NOBUG_DEFINE_FLAG_PARENT (backend, lumiera); TODO +NOBUG_DEFINE_FLAG (backend); +NOBUG_DEFINE_FLAG_PARENT (file_all, backend); + +int +lumiera_backend_init (void) +{ + NOBUG_INIT_FLAG (backend); + NOBUG_INIT_FLAG (file_all); + NOBUG_INIT_FLAG (file); + TRACE (backend); + lumiera_filedescriptor_registry_init (); + + int max_entries = 10; TODO("determine by sysconf (_SC_OPEN_MAX) minus some (big) safety margin " + "add some override to run tests with few filehandles"); + + lumiera_filehandlecache_new (max_entries); + + return 0; +} + +void +lumiera_backend_destroy (void) +{ + TRACE (backend); + lumiera_filedescriptor_registry_destroy (); + lumiera_filehandlecache_delete (); +} diff --git a/src/backend/backend.h b/src/backend/backend.h new file mode 100644 index 000000000..bd4c86815 --- /dev/null +++ b/src/backend/backend.h @@ -0,0 +1,36 @@ +/* + backend - common lumiera backend things + + 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_BACKEND_H +#define LUMIERA_BACKEND_H + +#include + +NOBUG_DECLARE_FLAG (backend); +NOBUG_DECLARE_FLAG (file_all); +NOBUG_DECLARE_FLAG (file); + +int +lumiera_backend_init (void); + +void +lumiera_backend_destroy (void); + +#endif diff --git a/src/backend/file.c b/src/backend/file.c new file mode 100644 index 000000000..9af608567 --- /dev/null +++ b/src/backend/file.c @@ -0,0 +1,130 @@ +/* + file.c - file handling + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "lib/mutex.h" +#include "lib/safeclib.h" + +#include "backend/file.h" +#include "backend/filehandlecache.h" +#include "backend/filedescriptor.h" + +#include +#include + +NOBUG_DEFINE_FLAG_PARENT (file, file_all); + +LUMIERA_ERROR_DEFINE(FILE_CHANGED, "File changed unexpected"); + + +LumieraFile +lumiera_file_init (LumieraFile self, const char* name, int flags) +{ + TRACE (file); + if (!(self->descriptor = lumiera_filedescriptor_acquire (name, flags))) + return NULL; + self->name = lumiera_strndup (name, PATH_MAX); + + return self; +} + +LumieraFile +lumiera_file_destroy (LumieraFile self) +{ + TRACE (file); + lumiera_filedescriptor_release (self->descriptor); + free ((void*)self->name); + return self; +} + + +LumieraFile +lumiera_file_new (const char* name, int flags) +{ + TRACE (file); + LumieraFile self = lumiera_malloc (sizeof (lumiera_file)); + return lumiera_file_init (self, name, flags); +} + +void +lumiera_file_delete (LumieraFile self) +{ + TRACE (file); + free (lumiera_file_destroy (self)); +} + + +int +lumiera_file_handle_acquire (LumieraFile self) +{ + TRACE (file); + REQUIRE (self); + REQUIRE (self->descriptor); + REQUIRE (lumiera_fhcache); + + LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock) + { + if (!self->descriptor->handle) + /* no handle yet, get a new one */ + lumiera_filehandlecache_handle_acquire (lumiera_fhcache, self->descriptor); + else + lumiera_filehandlecache_checkout (lumiera_fhcache, self->descriptor->handle); + + if (self->descriptor->handle->fd == -1) + { + int fd; + fd = open (self->name, self->descriptor->flags & LUMIERA_FILE_MASK); + if (fd == -1) + { + LUMIERA_ERROR_SET (file, ERRNO); + } + else + { + struct stat st; + if (fstat (fd, &st) == -1) + { + close (fd); + LUMIERA_ERROR_SET (file, ERRNO); + } + else if (self->descriptor->stat.st_dev != st.st_dev || self->descriptor->stat.st_ino != st.st_ino) + { + close (fd); + /* Woops this is not the file we expected to use */ + LUMIERA_ERROR_SET (file, FILE_CHANGED); + } + } + self->descriptor->handle->fd = fd; + } + } + + return self->descriptor->handle->fd; +} + + +void +lumiera_file_handle_release (LumieraFile self) +{ + TRACE (file); + + LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock) + { + lumiera_filehandlecache_checkin (lumiera_fhcache, self->descriptor->handle); + } +} diff --git a/src/backend/file.h b/src/backend/file.h new file mode 100644 index 000000000..bba12a167 --- /dev/null +++ b/src/backend/file.h @@ -0,0 +1,123 @@ +/* + file.h - interface to files by filename + + 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_FILE_H +#define LUMIERA_FILE_H + + +#include "lib/mutex.h" +#include "lib/llist.h" +#include "lib/error.h" + +NOBUG_DECLARE_FLAG (file); + +LUMIERA_ERROR_DECLARE(FILE_CHANGED); + +/** + * @file + * File management + * Handling Files is splitted into different classes: + * 1. The 'lumiera_file' class which acts as interface to the outside for managing files. + * 'lumiera_file' is addressed by the name of the file. Since files can have more than one name (hardlinks) + * many 'lumiera_file' can point to a single 'lumiera_filedescriptor' + * 2. The 'lumiera_filedescriptor' class which does the real work managing the file in the back. + * 3. Since OS-filehandles are a limited resource we access the lazily as 'lumiera_filehandle' which are + * managed in a 'lumiera_filehandlecache' + */ + +typedef struct lumiera_file_struct lumiera_file; +typedef lumiera_file* LumieraFile; + + +#include "backend/filehandle.h" +#include "backend/filedescriptor.h" + +#define LUMIERA_FILE_READONLY (O_RDONLY | O_LARGEFILE | O_NOATIME) +#define LUMIERA_FILE_READWRITE (O_RDWR | O_LARGEFILE | O_NOATIME) +#define LUMIERA_FILE_CREATE (O_RDWR | O_LARGEFILE | O_NOATIME | O_CREAT | O_EXCL) +#define LUMIERA_FILE_RECREATE (O_RDWR | O_LARGEFILE | O_NOATIME | O_CREAT | O_TRUNC) + +/* creat and excl flags will be masked out for descriptor lookup */ +#define LUMIERA_FILE_MASK ~(O_CREAT | O_EXCL | O_TRUNC) + +struct lumiera_file_struct +{ + const char* name; + LumieraFiledescriptor descriptor; +}; + +/** + * Initialize a file structure. + * @param self pointer to the file structure + * @param name filename + * @param flags open flags + * @return self + */ +LumieraFile +lumiera_file_init (LumieraFile self, const char* name, int flags); + +/** + * Destroy a file structure. + * frees all associated resources, releases the filedescriptor etc. + * @param self file structure to be destroyed + * @return self + */ +LumieraFile +lumiera_file_destroy (LumieraFile self); + +/** + * Allocate a new file structure. + * @param name filename + * @param flags open flags + * @return new file structure + */ +LumieraFile +lumiera_file_new (const char* name, int flags); + +/** + * Frees a file structure. + * @param self file structure to be freed + */ +void +lumiera_file_delete (LumieraFile self); + +/** + * Get a POSIX filehandle for a file. + * Filehandles are opened on demand and must be acquired for use. + * Using filehandles is refcounted and might be nested. + * After using them they must be released which puts them back into filehandlecache aging. + * @param self file structure + * @return POSIX filehandle or -1 on error, check lumiera_error() to retrieve the errorcode + * Currently only LUMIERA_ERROR_ERRNO will be raised but this might change in future. + * Opening files can fail for many reasons and at any time! + */ +int +lumiera_file_handle_acquire (LumieraFile self); + +/** + * Put filehandle back into cache aging. + * @param self file which handle to be released + */ +void +lumiera_file_handle_release (LumieraFile self); + +#endif + diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c new file mode 100644 index 000000000..b9608984f --- /dev/null +++ b/src/backend/filedescriptor.c @@ -0,0 +1,240 @@ +/* + filedescriptor.c - file handling + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "lib/mutex.h" +#include "lib/safeclib.h" +#include "lib/cuckoo.h" + +#include "backend/file.h" +#include "backend/filedescriptor.h" +#include "backend/filehandle.h" +#include "backend/filehandlecache.h" + +#include +#include +#include +#include + + +NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all); + +/* + Filedescriptor registry + + This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore. + */ +static Cuckoo 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) +{ + 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); +} + +void +lumiera_filedescriptor_registry_init (void) +{ + NOBUG_INIT_FLAG (filedescriptor); + TRACE (filedescriptor); + REQUIRE (!registry); + + registry = cuckoo_new (h1, h2, h3, cmp, + sizeof (LumieraFiledescriptor), + 3); + if (!registry) + LUMIERA_DIE (NO_MEMORY); +} + +void +lumiera_filedescriptor_registry_destroy (void) +{ + TRACE (filedescriptor); + REQUIRE (!cuckoo_nelements (registry)); + if (registry) + cuckoo_free (registry); + registry = NULL; +} + + +LumieraFiledescriptor +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); + + lumiera_filedescriptor fdesc; + fdesc.flags = flags; + + if (stat (name, &fdesc.stat) != 0) + { + if (errno == ENOENT && flags&O_CREAT) + { + 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 efile; + } + *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 */ + 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; +} + + +void +lumiera_filedescriptor_release (LumieraFiledescriptor self) +{ + TRACE (filedescriptor); + if (!--self->refcount) + lumiera_filedescriptor_delete (self); +} + + +LumieraFiledescriptor +lumiera_filedescriptor_new (LumieraFiledescriptor template) +{ + LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor)); + TRACE (filedescriptor, "at %p", self); + + 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->rh); + + return self; +} + + +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); + + RESOURCE_FORGET (filedescriptor, self->rh); + + cuckoo_remove (registry, cuckoo_find (registry, &self)); + + TODO ("destruct other members (WIP)"); + + + TODO ("release filehandle"); + + lumiera_mutex_destroy (&self->lock); + free (self); + + lumiera_mutexacquirer_unlock (®istry_lock); +} diff --git a/src/backend/filedescriptor.h b/src/backend/filedescriptor.h new file mode 100644 index 000000000..528be41e8 --- /dev/null +++ b/src/backend/filedescriptor.h @@ -0,0 +1,113 @@ +/* + filedescriptor.h - file handling + + 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_FILEDESCRIPTOR_H +#define LUMIERA_FILEDESCRIPTOR_H + +#include "lib/mutex.h" + + +#include +#include +#include + +typedef struct lumiera_filedescriptor_struct lumiera_filedescriptor; +typedef lumiera_filedescriptor* LumieraFiledescriptor; + + +#include "backend/filehandle.h" +#include "backend/file.h" + +/** + * @file + * Filedescriptors. + * Filedescriptors are the underlying working horse in accessing files. + * All information associated with managing a file is kept here. + */ + + + +struct lumiera_filedescriptor_struct +{ + struct stat stat; /* create after first open, maintained metadata, MUST BE FIRST! */ + 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 */ + + LumieraFilehandle handle; + //LumieraFileMap mappings; + //LumieraWriteBuffer writebuffer; + + RESOURCE_HANDLE (rh); +}; + +/** + * Initialize the global filedescriptor registry. + * All filedescriptors are looked up by dev/ino/open-flags in a hashtable. Opening hardlinked + * files will be targeted to the same filedescriptor. + * This function never fails but dies on error. + */ +void +lumiera_filedescriptor_registry_init (void); + +/** + * Destroy and free the global filedescriptor registry. + * Never fails. + */ +void +lumiera_filedescriptor_registry_destroy (void); + + +/** + * Find existing filedescriptor or create one + * @param name name of the file + * @param flags opening flags for the filedescriptor + * @return descriptor on success or NULL on error + */ +LumieraFiledescriptor +lumiera_filedescriptor_acquire (const char* name, int flags); + + +/** + * Release a filedescriptor. + * @param self filedescriptor to be released + */ +void +lumiera_filedescriptor_release (LumieraFiledescriptor self); + + +/** + * Allocate a new filedescriptor cloned from a template + * @param template the source filedescriptor + * @return the constrccted filedescriptor + */ +LumieraFiledescriptor +lumiera_filedescriptor_new (LumieraFiledescriptor template); + +/** + * Delete a filedescriptor + * Called whenever its reference count drops to zero. + * @param self the filedescriptor to be deleted + */ +void +lumiera_filedescriptor_delete (LumieraFiledescriptor self); + +#endif diff --git a/src/backend/filehandle.c b/src/backend/filehandle.c new file mode 100644 index 000000000..60d54cf82 --- /dev/null +++ b/src/backend/filehandle.c @@ -0,0 +1,70 @@ +/* + filehandle - filehandle management and caching + + 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/llist.h" +#include "lib/safeclib.h" + +#include "backend/file.h" +#include "backend/filehandle.h" +#include "backend/filedescriptor.h" + +#include + +NOBUG_DEFINE_FLAG_PARENT (filehandle, file_all); + +LumieraFilehandle +lumiera_filehandle_new () +{ + LumieraFilehandle self = lumiera_malloc (sizeof (lumiera_filehandle)); + TRACE (filehandle, "%p", self); + + llist_init (&self->cachenode); + self->fd = -1; + self->use_cnt = 1; + self->descriptor = NULL; + + return self; +} + + +void* +lumiera_filehandle_destroy_node (LList node) +{ + TRACE (filehandle); + REQUIRE (llist_is_empty (node)); + LumieraFilehandle self = (LumieraFilehandle)node; + REQUIRE (self->use_cnt == 0); + + if (self->fd >= 0) + close (self->fd); + self->fd = -1; + self->descriptor = NULL; + return self; +} + + +int +lumiera_filehandle_get (LumieraFilehandle self) +{ + REQUIRE (self->descriptor); + return -1; +} + diff --git a/src/backend/filehandle.h b/src/backend/filehandle.h new file mode 100644 index 000000000..e1b02b2e4 --- /dev/null +++ b/src/backend/filehandle.h @@ -0,0 +1,69 @@ +/* + filehandle - filehandle management and caching + + 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_FILEHANDLE_H +#define LUMIERA_FILEHANDLE_H + +#include "lib/error.h" +#include "lib/llist.h" + +typedef struct lumiera_filehandle_struct lumiera_filehandle; +typedef lumiera_filehandle* LumieraFilehandle; + +#include "backend/filedescriptor.h" + +/** + * @file + * Filehandles. + * Filehandles manage the underlying POSIX filehandle for a filedescriptor. + * Since we want to support handling of more files than POSIX filehandles are available on a common system + * the filehandles are opened, cached and closed on demand, see 'filehandlecache'. + */ + + +/** + * File handles + */ +struct lumiera_filehandle_struct +{ + llist cachenode; + int fd; + unsigned use_cnt; + LumieraFiledescriptor descriptor; +}; + +/** + * Allocate a new filehandle structure. + * @return new filehandle structure + */ +LumieraFilehandle +lumiera_filehandle_new (); + + +/** + * destroy the resources associated eith a filehandle structure. + * This function is used by the filehandlecache to recycle filehandle structs. + * @param node pointer to the cachenode member of a struct filehandle + * @return pointer to the start of the memory of the destroyed filehandle + */ +void* +lumiera_filehandle_destroy_node (LList node); + +#endif diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c new file mode 100644 index 000000000..181807661 --- /dev/null +++ b/src/backend/filehandlecache.c @@ -0,0 +1,138 @@ +/* + filehandlecache - filehandle management and caching + + 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/safeclib.h" + +#include "backend/file.h" +#include "backend/filehandlecache.h" + +NOBUG_DEFINE_FLAG_PARENT (filehandlecache, file_all); + +/* errors */ + +LUMIERA_ERROR_DEFINE (FILEHANDLECACHE_NOHANDLE, "No filehandle available"); + + +LumieraFilehandlecache lumiera_fhcache = NULL; + + +void +lumiera_filehandlecache_new (int max_entries) +{ + REQUIRE (!lumiera_fhcache, "Filehandlecache already initialized"); + + NOBUG_INIT_FLAG (filehandlecache); + lumiera_fhcache = lumiera_malloc (sizeof (lumiera_filehandlecache)); + 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->rh); +} + + +void +lumiera_filehandlecache_delete (void) +{ + if (lumiera_fhcache) + { + REQUIRE (!lumiera_fhcache->checked_out, "Filehandles in use at shutdown"); + RESOURCE_FORGET (filehandlecache, lumiera_fhcache->rh); + lumiera_mrucache_destroy (&lumiera_fhcache->cache); + lumiera_mutex_destroy (&lumiera_fhcache->lock); + free (lumiera_fhcache); + lumiera_fhcache = NULL; + } +} + + +LumieraFilehandle +lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFiledescriptor desc) +{ + TRACE (filehandlecache); + LumieraFilehandle ret = NULL; + LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock) + { + if (self->available <= 0 && self->cache.cached) + { + /* pop a filehandle from cache */ + ret = lumiera_mrucache_pop (&self->cache); + if (self->available < 0) + /* try to free overallocated filehandles */ + self->available -= self->available + lumiera_mrucache_age (&self->cache, -self->available); + } + else + { + /* allocate new filehandle if we are below the limit or no cached handles are available (overallocating) */ + ret = lumiera_filehandle_new (); + if (!ret) + LUMIERA_ERROR_SET (filehandlecache, FILEHANDLECACHE_NOHANDLE); + else + --self->available; + } + ret->use_cnt = 1; + ret->descriptor = desc; + desc->handle = ret; + ++self->checked_out; + } + return ret; +} + + +LumieraFilehandle +lumiera_filehandlecache_checkout (LumieraFilehandlecache self, LumieraFilehandle handle) +{ + REQUIRE (self); + REQUIRE (handle); + /* This function is called with the associated descriptor locked, nothing can modify 'handle' */ + if (!handle->use_cnt) + { + /* lock cache and checkout */ + LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock) + { + lumiera_mrucache_checkout (&self->cache, &handle->cachenode); + } + } + ++handle->use_cnt; + ++self->checked_out; + + return handle; +} + +void +lumiera_filehandlecache_checkin (LumieraFilehandlecache self, LumieraFilehandle handle) +{ + REQUIRE (self); + REQUIRE (handle); + REQUIRE (handle->use_cnt); + + /* This function is called with the associated descriptor locked, nothing can modify 'self' */ + if (!--handle->use_cnt) + { + /* lock cache and checin */ + LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock) + { + --self->checked_out; + lumiera_mrucache_checkin (&self->cache, &handle->cachenode); + } + } +} + diff --git a/src/backend/filehandlecache.h b/src/backend/filehandlecache.h new file mode 100644 index 000000000..37c2a416b --- /dev/null +++ b/src/backend/filehandlecache.h @@ -0,0 +1,108 @@ +/* + filehandlecache - filehandle management and caching + + 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_FILEHANDLECACHE_H +#define LUMIERA_FILEHANDLECACHE_H + +#include "lib/error.h" +#include "lib/mrucache.h" +#include "lib/mutex.h" + +typedef struct lumiera_filehandlecache_struct lumiera_filehandlecache; +typedef lumiera_filehandlecache* LumieraFilehandlecache; + +#include "backend/filehandle.h" + +/** + * @file + * Filehandle management and caching + * The number of filehandles a program can held open is usually limited, since we want to support + * using a less limited number of files and closing/opening for each operation is expensive, we + * provide a cache to keep the most frequent used files open and gracefully close/recycle unused filehandles. + * The filehandlecache defined here protects all operations on the cache with a mutex. + */ + + +/* + File handle cache manages file handles + */ +struct lumiera_filehandlecache_struct +{ + lumiera_mrucache cache; + int available; + int checked_out; + lumiera_mutex lock; + RESOURCE_HANDLE (rh); +}; + +extern LumieraFilehandlecache lumiera_fhcache; + +/** + * Initializes the filehandle cache. + * @param max_entries number how much filehandles shall be managed + * The number of elements the cache can hold is static and should be + * determined by sysconf (_SC_OPEN_MAX) minus some (big) safety margin. + */ +void +lumiera_filehandlecache_new (int max_entries); + +/** + * Delete the filehandle cache. + * No filehandles in the cache must be locked, this would be a fatal error. + * The handles are closed automatically. + */ +void +lumiera_filehandlecache_delete (void); + +/** + * Get a fresh filehandle. + * @param self pointer to the cache + * @return the new filehandle + */ +LumieraFilehandle +lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFiledescriptor desc); + +/** + * Add filehande back to cache, the filehandle becomes subject of aging. + * @param self pointer to the cache + * @param handle filehandle to be put back + */ +void +lumiera_filehandlecache_add_filehandle (LumieraFilehandlecache self, LumieraFilehandle handle); + +/** + * Remove a filehandle from cache aging + * Filehandles which are subject of cache aging must be checked out before they can be used. + * @param self the filehandlecache + * @param handle the filehandle to be checked out + */ +LumieraFilehandle +lumiera_filehandlecache_checkout (LumieraFilehandlecache self, LumieraFilehandle handle); + +/** + * Put a filehandle into the cache + * Filehandles which are checked in are subject of cache aging and might get destroyed and reused. + * @param self the filehandlecache + * @param handle the filehandle to be checked in + */ +void +lumiera_filehandlecache_checkin (LumieraFilehandlecache self, LumieraFilehandle handle); + +#endif diff --git a/src/backend/mmap.h b/src/backend/mmap.h new file mode 100644 index 000000000..608e40133 --- /dev/null +++ b/src/backend/mmap.h @@ -0,0 +1,88 @@ +/* + mmap.h - memory mapped acces to files + + 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_MMAP_H +#define LUMIERA_MMAP_H + +#include "lib/llist.h" + + +typedef struct lumiera_mmap_struct lumiera_mmap; +typedef lumiera_mmap* LumieraMMap; + + +#include "backend/filedescriptor.h" + + +#include +#include + +NOBUG_DECLARE_FLAG (mmap); + +/** + * @file + * MMap objects cover a memory maped range in a file + */ + + + +/** + * mmaped area + * + */ +struct lumiera_mmap_struct +{ + /** used for the mrucache when checked in the cache OR for attaching owners when checked out **/ + llist cachenode; + + /** all mmaps of a file are chained in this list, used to find ranges **/ + llist searchnode; + + off_t start; + size_t size; + void* address; + + /** array with refcounters per page **/ + unsigned short* refmap; + + /** 0 when this mmap is in cache, else the count of attached owners **/ + unsigned use_cnt; + //RESOURCE_HANDLE (rh); +}; + + +LumieraMMap +lumiera_mmap_init (LumieraMMap self, LumieraFile file, LList acquirer, off_t start, size_t size, size_t chunksize); + +LumieraMMap +lumiera_mmap_new (LumieraFile file, LList acquirer, off_t start, size_t size, size_t chunksize); + +void* +lumiera_mmap_destroy_node (LList node); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/mmapcache.h b/src/backend/mmapcache.h new file mode 100644 index 000000000..ed2efcb43 --- /dev/null +++ b/src/backend/mmapcache.h @@ -0,0 +1,136 @@ +/* + mmapcache.h - handle aging of mmap objects + + 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_MMAPCACHE_H +#define LUMIERA_MMAPCACHE_H + +#include "lib/error.h" +#include "lib/mrucache.h" +#include "lib/mutex.h" + + +typedef struct lumiera_mmapcache_struct lumiera_mmapcache; +typedef lumiera_mmapcache* LumieraMMapcache; + +#include "backend/mmap.h" + +#include + +/** + * @file + * Mmapcache stores a MRU cache of all established mmaped memory regions which are currently not in use. + * The mmapcache also manages the upper limit about how much memory can be mmaped. + */ + +struct lumiera_mmapcache_struct +{ + lumiera_mrucache cache; + size_t limit; + size_t total; + size_t cached; + lumiera_mutex lock; + RESOURCE_HANDLE (rh); +}; + +extern LumieraMMapcache lumiera_mcache; + + +/** + * Initializes the mmapcache. + * @param limit the mmapcache will drop elements when the sum of all mmapings gives over limit + */ +void +lumiera_mmapcache_new (size_t limit); + +/** + * Delete the mmap cache. + * No mmaps in the cache must be locked, this would be a fatal error. + * The handles are closed automatically. + */ +void +lumiera_mmapcache_delete (void); + +/** + * Get a fresh mmap object. + * when mmaped_limit is reached, the oldest mmap object gets dropped else a new allocated object + * is returned + * @param self pointer to the cache + * @return the new mmap + */ +LumieraMMap +lumiera_mmapcache_mmap_acquire (LumieraMMapcache self); + + +/** + * Announce a new mmap object to the cache quotas. + * Update the statistics kept in the cache, + * the map object is still considered to be checked out + * @param self pointer to the cache + * @param map object to be announced + */ +void +lumiera_mmapcache_announce (LumieraMMapcache self, LumieraMMap map); + +/** + * Remove a mmap object from the cache quotas. + * Update the statistics kept in the cache, + * called by mmap's destructor only + * @param self pointer to the cache + * @param map object to be removed + */ +void +lumiera_mmapcache_forget (LumieraMMapcache self, LumieraMMap map); + +/** + * Destroy and free the nelem oldest elements. + * Used to free up resources and memory. + * @param self cache where to free elements. + * @return nelem-(numer of elements which got freed), that is 0 if all requested elements got freed + */ +int +lumiera_mmapcache_age (LumieraMMapcache self); + +/** + * Remove a mmap from cache aging + * Mmaps which are subject of cache aging must be checked out before they can be used. + * @param self the mmapcache + * @param handle the mmap to be checked out + */ +LumieraMMap +lumiera_mmapcache_checkout (LumieraMMapcache self, LumieraMMap handle); + +/** + * Put a mmap into the cache + * Mmaps which are checked in are subject of cache aging and might get destroyed and reused. + * @param self the mmapcache + * @param handle the mmap to be checked in + */ +void +lumiera_mmapcache_checkin (LumieraMMapcache self, LumieraMMap handle); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/mmapings.h b/src/backend/mmapings.h new file mode 100644 index 000000000..234ab280b --- /dev/null +++ b/src/backend/mmapings.h @@ -0,0 +1,118 @@ +/* + mmapings.h - manage ranges of mmaped areas on a filedescriptor + + 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_MMAPINGS_H +#define LUMIERA_MMAPINGS_H + +#include "lib/mutex.h" +#include "lib/llist.h" + +typedef struct lumiera_mmapings_struct lumiera_mmapings; +typedef lumiera_mmapings* LumieraMMapings; + +#include "backend/filedescriptor.h" +#include "backend/mmap.h" + +#include + + +/** + * @file + * Keeps all mmaped areas + * + */ + +struct lumiera_mmapings_struct +{ + /** mmaped ranges are kept in an list sorted by the size of the mmaping, might be improved to a tree someday **/ + llist mmaps; + + /** sum of all mmaped areas, areas might be overlapping **/ + // size_t vsz; + + /** + * chunkssize is the smallest granularity which is used for mmapping files, it + * should reflect the intended file usage, that is 'pagesize' for small or non growing + * files and some MB for media files. Must be a 2's exponent of pagesize. + **/ + size_t chunksize; + + LumieraFiledescriptor descriptor; + lumiera_mutex lock; + RESOURCE_HANDLE (rh); +}; + +/** + * initialize mmapings container + * + */ +LumieraMMapings +lumiera_mmapings_init (LumieraMMapings self, LumieraFile file, size_t chunksize); + +/** + * destroy mmapings container and free all resources. + * + */ +LumieraMMapings +lumiera_mmapings_destroy (LumieraMMapings self); + +/** + * allocate and initialize new mmapings container + * + */ +LumieraMMapings +lumiera_mmapings_new (LumieraFile file, size_t chunksize); + +/** + * destroy and free mmapings container and all its resources + * + */ +void +lumiera_mmapings_delete (LumieraMMapings self); + +/** + * acquire a mmap which covers the given range + * @param self mmapings where to search + * @param acquirer list node of the new owner which will registered in the mmap + * @param start begin of the required range + * @param size requested size + * @return MMap object covering the requested range or NULL on error + */ +LumieraMMap +lumiera_mmapings_mmap_acquire (LumieraMMapings self, LumieraFile file, LList acquirer, off_t start, size_t size); + +/** + * release a previously acquired MMap object + * @param self mmapings to which the map belongs + * @param acquirer holding node + * @param map object to be released + */ +void +lumiera_mmapings_release_mmap (LumieraMMapings self, LList acquirer, LumieraMMap map); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/common/Makefile.am b/src/common/Makefile.am new file mode 100644 index 000000000..06082da31 --- /dev/null +++ b/src/common/Makefile.am @@ -0,0 +1,65 @@ +# 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 use -Wextra -Werror + +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)/time.cpp \ + $(liblumicommon_a_srcdir)/util.cpp \ + $(liblumicommon_a_srcdir)/visitor.cpp \ + $(liblumicommon_a_srcdir)/cmdline.cpp \ + $(liblumicommon_a_srcdir)/configrules.cpp \ + $(liblumicommon_a_srcdir)/error.cpp \ + $(liblumicommon_a_srcdir)/query.cpp \ + $(liblumicommon_a_srcdir)/query/mockconfigrules.cpp \ + $(liblumicommon_a_srcdir)/test/suite.cpp \ + $(liblumicommon_a_srcdir)/test/testoption.cpp + + +noinst_HEADERS += \ + $(liblumicommon_a_srcdir)/cmdline.hpp \ + $(liblumicommon_a_srcdir)/factory.hpp \ + $(liblumicommon_a_srcdir)/singleton.hpp \ + $(liblumicommon_a_srcdir)/singletonpolicies.hpp \ + $(liblumicommon_a_srcdir)/singletonpreconfigure.hpp \ + $(liblumicommon_a_srcdir)/time.hpp \ + $(liblumicommon_a_srcdir)/typelist.hpp \ + $(liblumicommon_a_srcdir)/visitor.hpp \ + $(liblumicommon_a_srcdir)/visitordispatcher.hpp \ + $(liblumicommon_a_srcdir)/visitorpolicies.hpp \ + $(liblumicommon_a_srcdir)/configrules.hpp \ + $(liblumicommon_a_srcdir)/error.hpp \ + $(liblumicommon_a_srcdir)/multithread.hpp \ + $(liblumicommon_a_srcdir)/p.hpp \ + $(liblumicommon_a_srcdir)/query.hpp \ + $(liblumicommon_a_srcdir)/query/mockconfigrules.hpp \ + $(liblumicommon_a_srcdir)/singletonfactory.hpp \ + $(liblumicommon_a_srcdir)/singletonsubclass.hpp \ + $(liblumicommon_a_srcdir)/typelistutil.hpp \ + $(liblumicommon_a_srcdir)/util.hpp \ + $(liblumicommon_a_srcdir)/test/mockinjector.hpp \ + $(liblumicommon_a_srcdir)/test/suite.hpp \ + $(liblumicommon_a_srcdir)/test/testoption.hpp \ + $(liblumicommon_a_srcdir)/test/run.hpp + diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 77fc26d90..ffdb9a176 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -21,23 +21,30 @@ 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 \ - $(liblumi_a_srcdir)/error.c \ - $(liblumi_a_srcdir)/framerate.c \ - $(liblumi_a_srcdir)/mutex.c \ - $(liblumi_a_srcdir)/rwlock.c \ - $(liblumi_a_srcdir)/condition.c \ - $(liblumi_a_srcdir)/references.c - - -noinst_HEADERS += \ - $(liblumi_a_srcdir)/plugin.h \ - $(liblumi_a_srcdir)/error.h \ - $(liblumi_a_srcdir)/framerate.h \ - $(liblumi_a_srcdir)/locking.h \ - $(liblumi_a_srcdir)/mutex.h \ - $(liblumi_a_srcdir)/rwlock.h \ - $(liblumi_a_srcdir)/condition.h \ - $(liblumi_a_srcdir)/references.h +liblumi_a_SOURCES = \ + $(liblumi_a_srcdir)/plugin.c \ + $(liblumi_a_srcdir)/error.c \ + $(liblumi_a_srcdir)/mutex.c \ + $(liblumi_a_srcdir)/rwlock.c \ + $(liblumi_a_srcdir)/condition.c \ + $(liblumi_a_srcdir)/references.c \ + $(liblumi_a_srcdir)/uuid.c \ + $(liblumi_a_srcdir)/safeclib.c \ + $(liblumi_a_srcdir)/cuckoo.c \ + $(liblumi_a_srcdir)/mrucache.c \ + $(liblumi_a_srcdir)/appconfig.cpp +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 \ + $(liblumi_a_srcdir)/references.h \ + $(liblumi_a_srcdir)/uuid.h \ + $(liblumi_a_srcdir)/safeclib.h \ + $(liblumi_a_srcdir)/cuckoo.h \ + $(liblumi_a_srcdir)/mrucache.h \ + $(liblumi_a_srcdir)/appconfig.hpp \ + $(liblumi_a_srcdir)/lifecycleregistry.hpp diff --git a/src/lib/condition.c b/src/lib/condition.c index 7427b431d..60e8b6f10 100644 --- a/src/lib/condition.c +++ b/src/lib/condition.c @@ -22,9 +22,12 @@ #include "lib/condition.h" /** - * @file Condition variables + * @file + * Condition variables */ +LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed"); + /** * Initialize a condition variable * @param self is a pointer to the condition variable to be initialized @@ -53,9 +56,9 @@ lumiera_condition_destroy (LumieraCondition self) if (self) { if (pthread_mutex_destroy (&self->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_DESTROY); else if (pthread_cond_destroy (&self->cond)) - LUMIERA_DIE; + LUMIERA_DIE (CONDITION_DESTROY); } return self; } diff --git a/src/lib/condition.h b/src/lib/condition.h index b2fd76c63..dd92f326b 100644 --- a/src/lib/condition.h +++ b/src/lib/condition.h @@ -25,9 +25,11 @@ #include "lib/locking.h" /** - * @file Condition variables, header + * @file + * Condition variables, header */ +LUMIERA_ERROR_DECLARE (CONDITION_DESTROY); /** * Condition variables. @@ -59,10 +61,10 @@ lumiera_condition_signal (LumieraCondition self) { REQUIRE (self); if (pthread_mutex_lock (&self->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_LOCK); pthread_cond_signal (&self->cond); if (pthread_mutex_unlock (&self->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_UNLOCK); } /** @@ -74,10 +76,10 @@ lumiera_condition_broadcast (LumieraCondition self) { REQUIRE (self); if (pthread_mutex_lock (&self->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_LOCK); pthread_cond_broadcast (&self->cond); if (pthread_mutex_unlock (&self->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_UNLOCK); } @@ -124,7 +126,7 @@ lumiera_conditionacquirer_init (LumieraConditionacquirer self, LumieraCondition self->state = state; if (state == LUMIERA_LOCKED) if (pthread_mutex_lock (&cond->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_LOCK); return self; } @@ -141,7 +143,7 @@ lumiera_conditionacquirer_lock (LumieraConditionacquirer self) REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked"); if (pthread_mutex_lock (&self->cond->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_LOCK); self->state = LUMIERA_LOCKED; } @@ -166,13 +168,13 @@ lumiera_conditionacquirer_wait (LumieraConditionacquirer self) * a conditionacquirer must be unlocked before leaving scope * @param self conditionacquirer associated with a condition variable */ -static inline int +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; + LUMIERA_DIE (MUTEX_UNLOCK); self->state = LUMIERA_UNLOCKED; } @@ -194,7 +196,7 @@ lumiera_conditionacquirer_signal (LumieraConditionacquirer self) * signal all waiting threads * @param self conditionacquirer associated with the condition variable to be signaled */ -static inline int +static inline void lumiera_conditionacquirer_broadcast (LumieraConditionacquirer self) { REQUIRE (self); diff --git a/src/lib/cuckoo.c b/src/lib/cuckoo.c new file mode 100644 index 000000000..bbcb0e71a --- /dev/null +++ b/src/lib/cuckoo.c @@ -0,0 +1,504 @@ +/* + A cuckoo hash implementation + + Copyright (C) + 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 "cuckoo.h" + +#include + +enum compact_state + { + COMPACTING_OFF, + COMPACTING_AUTO, + COMPACTED + }; + +struct cuckoo_struct +{ + size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */ + size_t itemsize; + + cuckoo_hashfunc h1; /* hash function */ + uint32_t r1; /* random, reset for each rehash */ + cuckoo_hashfunc h2; + uint32_t r2; + cuckoo_hashfunc h3; + uint32_t r3; + + cuckoo_cmpfunc cmp; + + void* t1; + void* t2; + void* t3; + + unsigned maxloops; /* sqrt (4 * size) */ + + enum compact_state autocompact; + size_t elements; +}; + + +static inline uint32_t cuckoo_fast_prng () +{ + static uint32_t rnd = 0xbabeface; + return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1); +} + +Cuckoo +cuckoo_init (Cuckoo self, + cuckoo_hashfunc h1, + cuckoo_hashfunc h2, + cuckoo_hashfunc h3, + cuckoo_cmpfunc cmp, + size_t itemsize, + unsigned startsize) +{ + if (!self) + return NULL; + + self->size = 1<itemsize = itemsize; + self->h1 = h1; + self->r1 = cuckoo_fast_prng (); + self->h2 = h2; + self->r2 = cuckoo_fast_prng (); + self->h3 = h3; + self->r3 = cuckoo_fast_prng (); + + self->cmp = cmp; + + self->t1 = calloc (self->size * 4, itemsize); + self->t2 = calloc (self->size * 2, itemsize); + self->t3 = calloc (self->size, itemsize); + if (!self->t1 || !self->t2 || !self->t3) + { + free (self->t1); + free (self->t2); + free (self->t3); + return NULL; + } + + self->maxloops = 1; + while (self->maxloops * self->maxloops < self->size * 4) + ++self->maxloops; + + self->autocompact = COMPACTING_AUTO; + self->elements = 0; + return self; +} + +Cuckoo +cuckoo_new (cuckoo_hashfunc h1, + cuckoo_hashfunc h2, + cuckoo_hashfunc h3, + cuckoo_cmpfunc cmp, + size_t itemsize, + unsigned startsize) +{ + Cuckoo self = malloc (sizeof (struct cuckoo_struct)); + if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize)) + { + free (self); + return NULL; + } + return self; +} + +Cuckoo +cuckoo_destroy (Cuckoo self) +{ + if (self) + { + free (self->t1); + free (self->t2); + free (self->t3); + } + return self; +} + + +void +cuckoo_free (Cuckoo self) +{ + free (cuckoo_destroy (self)); +} + + +static inline int +iszero (void* mem, size_t size) +{ + while (size && !*(int*)mem) + { + size -= sizeof (int); + mem += sizeof (int); + } + return !size; +} + +static inline void +xmemcpy (void* dst, void* src, size_t size) +{ + while (size) + { + size -= sizeof (int); + *(int*)(dst + size) = *(int*)(src + size); + } +} + + +static int +cuckoo_insert_internal_ (Cuckoo self, void* item) +{ + void* pos; + char tmp[self->itemsize]; + + for (unsigned n = 0; n < self->maxloops; ++n) + { + /* find nest */ + pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size)); + /* kick old egg out */ + xmemcpy (tmp, pos, self->itemsize); + /* lay egg */ + xmemcpy (pos, item, self->itemsize); + + if (iszero (tmp, self->itemsize)) + return 1; + + /* find nest */ + pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size)); + /* kick old egg out */ + xmemcpy (item, pos, self->itemsize); + /* lay egg */ + xmemcpy (pos, tmp, self->itemsize); + + if (iszero (item, self->itemsize)) + return 1; + + /* find nest */ + pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size); + /* kick old egg out */ + xmemcpy (tmp, pos, self->itemsize); + /* lay egg */ + xmemcpy (pos, item, self->itemsize); + + if (iszero (tmp, self->itemsize)) + return 1; + + /* copy tmp to item, which will be reinserted on next interation / after rehashing */ + xmemcpy (item, tmp, self->itemsize); + } + return 0; +} + + +size_t +cuckoo_nelements (Cuckoo self) +{ + return self->elements; +} + + +static void +cuckoo_rehash (Cuckoo self) +{ + retry1: + + self->r1 = cuckoo_fast_prng (); + + for (size_t i = 0; i < 4*self->size; ++i) + { + unsigned n; + void* pos = self->t1 + self->itemsize * i; + if (!iszero (pos, self->itemsize)) + { + for (n = 0; n < self->maxloops; ++n) + { + unsigned hash = self->h1 (pos, self->r1) % (4*self->size); + if (hash != i) + { + char t[self->itemsize]; + void* hpos = self->t1 + self->itemsize * hash; + xmemcpy (t, hpos, self->itemsize); + xmemcpy (hpos, pos, self->itemsize); + xmemcpy (pos, t, self->itemsize); + if (iszero (t, self->itemsize)) + break; + } + else + break; + } + if (n == self->maxloops) + goto retry1; + } + } + + retry2: + self->r2 = cuckoo_fast_prng (); + + for (size_t i = 0; i < 2*self->size; ++i) + { + unsigned n; + void* pos = self->t2 + self->itemsize * i; + if (!iszero (pos, self->itemsize)) + { + for (n = 0; n < self->maxloops; ++n) + { + unsigned hash = self->h2 (pos, self->r2) % (2*self->size); + if (hash != i) + { + char t[self->itemsize]; + void* hpos = self->t2 + self->itemsize * hash; + xmemcpy (t, hpos, self->itemsize); + xmemcpy (hpos, pos, self->itemsize); + xmemcpy (pos, t, self->itemsize); + if (iszero (t, self->itemsize)) + break; + } + else + break; + } + if (n == self->maxloops) + goto retry2; + } + } + + retry3: + self->r3 = cuckoo_fast_prng (); + + for (size_t i = 0; i < self->size; ++i) + { + unsigned n; + void* pos = self->t3 + self->itemsize * i; + if (!iszero (pos, self->itemsize)) + { + for (n = 0; n < self->maxloops; ++n) + { + unsigned hash = self->h3 (pos, self->r3) % self->size; + if (hash != i) + { + char t[self->itemsize]; + void* hpos = self->t3 + self->itemsize * hash; + xmemcpy (t, hpos, self->itemsize); + xmemcpy (hpos, pos, self->itemsize); + xmemcpy (pos, t, self->itemsize); + if (iszero (t, self->itemsize)) + break; + } + else + break; + } + if (n == self->maxloops) + goto retry3; + } + } +} + +static int +cuckoo_grow (Cuckoo self) +{ + /* rotate hashfuncs, tables, randoms */ + cuckoo_hashfunc th = self->h3; + self->h3 = self->h2; + self->h2 = self->h1; + self->h1 = th; + + uint32_t tr = self->r3; + self->r3 = self->r2; + self->r2 = self->r1; + self->r1 = tr; + + void* tt = self->t3; + self->t3 = self->t2; + self->t2 = self->t1; + + /* double new base size */ + self->size *= 2; + while (self->maxloops * self->maxloops < self->size * 4) + ++self->maxloops; + + /* alloc new t1 */ + self->t1 = calloc (self->size * 4, self->itemsize); + if (!self->t1) + { + self->t1 = tt; + return 0; + } + + /* reinsert tt */ + size_t ttsize = self->size / 2; + for (size_t i = 0; i < ttsize; ++i) + { + void* pos = tt + i * self->itemsize; + if (!iszero (pos, self->itemsize)) + { + while (!cuckoo_insert_internal_ (self, pos)) + cuckoo_rehash (self); + } + } + free (tt); + + self->autocompact = COMPACTING_AUTO; + return 1; +} + + +int +cuckoo_reserve (Cuckoo self, size_t more) +{ + int ret = 1; + if (more) + while (self->elements+self->maxloops+more >= 6*self->size) + ret = cuckoo_grow (self); + + self->autocompact = COMPACTING_OFF; + return ret; +} + + +int +cuckoo_compact (Cuckoo self) +{ + if (self->autocompact == COMPACTED) + return 1; + + if (self->size > 2 && self->elements < self->size * 3) + { + cuckoo_hashfunc th = self->h1; + self->h1 = self->h2; + self->h2 = self->h3; + self->h3 = th; + + uint32_t tr = self->r1; + self->r1 = self->r2; + self->r2 = self->r3; + self->r3 = tr; + + void* tt = self->t1; + self->t1 = self->t2; + self->t2 = self->t3; + + /* halve base size */ + self->size /= 2; + while (self->maxloops * self->maxloops >= self->size * 4) + --self->maxloops; + + /* alloc new t3 */ + self->t3 = calloc (self->size, self->itemsize); + if (!self->t3) + { + self->t3 = tt; + return 0; + } + + /* reinsert tt */ + size_t ttsize = self->size * 8; + for (size_t i = 0; i < ttsize; ++i) + { + void* pos = tt + i * self->itemsize; + if (!iszero (pos, self->itemsize)) + { + --self->elements; + cuckoo_insert (self, pos); + } + } + free (tt); + self->autocompact = COMPACTED; + } + return 1; +} + + +int +cuckoo_insert (Cuckoo self, void* item) +{ + char tmp[self->itemsize]; + + void* found; + if ((found = cuckoo_find (self, item))) + { + xmemcpy (found, item, self->itemsize); + return 1; + } + + xmemcpy (tmp, item, self->itemsize); + + for (unsigned n = 6; n; --n) /* rehash/grow loop */ + { + if (cuckoo_insert_internal_ (self, tmp)) + { + ++self->elements; + return 1; + } + + if (self->elements > n*self->size) + { + n = 6; + if (!cuckoo_grow (self)) + return 0; + } + else + cuckoo_rehash (self); + } + return 0; +} + + +void* +cuckoo_find (Cuckoo self, void* item) +{ + void* pos; + + pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size)); + if (!iszero (pos, self->itemsize) && self->cmp (item, pos)) + return pos; + + pos = self->t2 + self->itemsize * (self->h2 (item, self->r2) % (2*self->size)); + if (!iszero (pos, self->itemsize) && self->cmp (item, pos)) + return pos; + + pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size); + if (!iszero (pos, self->itemsize) && self->cmp (item, pos)) + return pos; + + return NULL; +} + + +void +cuckoo_remove (Cuckoo self, void* item) +{ + if (item) + { + memset (item, 0, self->itemsize); + --self->elements; + + if (self->autocompact == COMPACTING_AUTO && self->size > 2 && self->elements <= self->size*2) + cuckoo_compact (self); + } +} + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/cuckoo.h b/src/lib/cuckoo.h new file mode 100644 index 000000000..323b5cc75 --- /dev/null +++ b/src/lib/cuckoo.h @@ -0,0 +1,175 @@ +/* + A cuckoo hash implementation + + Copyright (C) + 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 CUCKOO_H +#define CUCKOO_H + +/** + * @file + * Cuckoo hashing + * This hashing gives guaranteed O(1) lookup complexity and amortized O(1) insert and remove complexity. + * Hash tables by default grow and shrink automatically. It is posible to preallocate entries and turn + * automatic shrinking off taking out the memory management factors for insert and remove operations. + * This implementation uses 3 Tables which exponential growing sizes. + */ + +#include +#include + +struct cuckoo_struct; +typedef struct cuckoo_struct * Cuckoo; + +/** + * Hash function. + * User supplied universal hash function + * @param item address of the item to be hashed + * @param r pseudo random number, 31 significant bits, regenerated on each rehash + * @return hash value + */ +typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r); + +/** + * Compare function. + * User supplied compare function + * @param item1 address of the first item + * @param item2 address of the second item + * @return 1 when the items are identical, 0 otherwise + */ +typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2); + +/** + * Initialize a cuckoo hash. + * @param self pointer to a uninitialized cuckoo datastructure + * @param h1 hash function for the first table + * @param h2 hash function for the second table + * @param h3 hash function for the third table + * @param cmp function which compares two keys + * @param startsize initial size of table t3, as 2's exponent + * @return The initialized hashtable or NULL at allocation failure + */ +Cuckoo +cuckoo_init (Cuckoo self, + cuckoo_hashfunc h1, + cuckoo_hashfunc h2, + cuckoo_hashfunc h3, + cuckoo_cmpfunc cmp, + size_t itemsize, + unsigned startsize); + +/** + * Allocate a new cuckoo hash. + * @param h1 hash function for the first table + * @param h2 hash function for the second table + * @param h3 hash function for the third table + * @param cmp function which compares two keys + * @param startsize initial size of table t3, as 2's exponent + * @return The initialized hashtable or NULL at allocation failure + */ +Cuckoo +cuckoo_new (cuckoo_hashfunc h1, + cuckoo_hashfunc h2, + cuckoo_hashfunc h3, + cuckoo_cmpfunc cmp, + size_t itemsize, + unsigned startsize); + +/** + * Destroy a cuckoo hash. + * Frees internal used resources. + * @param self cuckoo hash to destroy + * @return The now uninitialized hashtable + */ +Cuckoo +cuckoo_destroy (Cuckoo self); + +/** + * Deallocate a cuckoo hash. + * @param self handle of the hash table to be freed + */ +void +cuckoo_free (Cuckoo self); + +/** + * Get the number of elements stored in a hash. + * @return number of elements, 0 when empty + */ +size_t +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. + * @param self handle to the hash table + * @param item pointer to a item to be inserted + * @return 1 on successful insert, 0 on allocation failure + * Note: at failure there is one arbitary hash cell lost! + */ +int +cuckoo_insert (Cuckoo self, void* item); + +/** + * Find a value by key in a hash. + * @param self handle to the hash table + * @param item pointer to an item to be looked up + * @return found object or NULL if not present + */ +void* +cuckoo_find (Cuckoo self, void* item); + +/** + * Remove a item from a hash. + * amortized O(1) complexity when it automatically shrink its tables. + * guaranteed O(1) complexity when automatic shrinking is turned off. + * see cuckoo_reserve() about how turn automatic shrinking off. + * @param self handle to the hash table + * @param item pointer to the item to be removed + */ +void +cuckoo_remove (Cuckoo self, void* item); + +/** + * Shrink the hash sizes when possible and turn autocompacting on. + * only useful when autmatic shrinking is turned off. + * see cuckoo_reserve() about how turn shrinking off. + * @param self handle to the hash table + */ +int +cuckoo_compact (Cuckoo self); + +/** + * Prereserve hash entries and turn autocompacting off. + * @param self handle to the hash table + * @param more number of entries to be additionally reserved + * In rare circumstances inserting into a hash which has reserved some entries + * it may still need to rehash (or even rarer) to grow the table. + * While autocompacting is turned off, removing is completely O(1). + */ +int +cuckoo_reserve (Cuckoo self, size_t more); + +#endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/lib/error.c b/src/lib/error.c index 81e24bad8..b2bc390b6 100644 --- a/src/lib/error.c +++ b/src/lib/error.c @@ -24,7 +24,8 @@ #include "lib/error.h" /** - * @file C Error handling in Lumiera. + * @file + * C Error handling in Lumiera. */ diff --git a/src/lib/error.h b/src/lib/error.h index 24c73f0a5..1eeb42dda 100644 --- a/src/lib/error.h +++ b/src/lib/error.h @@ -31,7 +31,8 @@ extern "C" { #include /** - * @file C Error handling in Lumiera, header. + * @file + * C Error handling in Lumiera, header. */ @@ -39,7 +40,8 @@ extern "C" { * Abort unconditionally with a 'Fatal Error!' message. * This macro is used whenever the program end up in a invalid state from which no runtime recovery is possible */ -#define LUMIERA_DIE do { NOBUG_ERROR(NOBUG_ON, "Fatal Error!"); abort(); } while(0) +#define LUMIERA_DIE(err) \ + do { NOBUG_ERROR(NOBUG_ON, "Fatal Error: %s ", strchr(LUMIERA_ERROR_##err, ':')); abort(); } while(0) /** * Forward declare an error constant. @@ -58,7 +60,8 @@ extern const char* LUMIERA_ERROR_##err #define LUMIERA_ERROR_DEFINE(err, msg) \ const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg -/** Helper macro to raise an error for the current thread. +/** + * Helper macro to raise an error for the current thread. * This macro eases setting an error. It adds NoBug logging support to the low level error handling. * @param flag NoBug flag describing the subsystem where the error was raised * @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY) diff --git a/src/lib/framerate.h b/src/lib/framerate.h deleted file mode 100644 index 581d7fa78..000000000 --- a/src/lib/framerate.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - framerate.h - framerate calculations - - 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_FRAMERATE_H -#define LUMIERA_FRAMERATE_H - -#include - -#include "lib/error.h" - -/** - * @file Framerate calculations, header. - */ - - -/** - * framerates are defined as a rational number - * for example NTSC with 30000/1001fps - */ -struct lumiera_framerate_struct -{ - unsigned n; //numerator - unsigned d; //denominator -}; - -typedef struct lumiera_framerate_struct lumiera_framerate; -typedef lumiera_framerate* LumieraFramerate; - -typedef signed long lumiera_framepos; - -LUMIERA_ERROR_DECLARE(FRAMERATE_ILLEGAL_TIME); -LUMIERA_ERROR_DECLARE(FRAMERATE_ILLEGAL_FRAME); - -#define LUMIERA_FRAMEPOS_ERROR LONG_MIN - -/** - * Get the frame number of a given time at a given frame rate. - * frame indexing starts with 1 - * @param framerate is a pointer to the framerate used, defined as rational number. Must be given. - * @param time is a pointer to a lumiera_time which shall be converted. - * @return frame at the given time or LUMIERA_FRAMEPOS_ERROR on error. - */ -static inline lumiera_framepos -lumiera_framerate_frame_get_time (const LumieraFramerate framerate, LumieraTime time) -{ - REQUIRE (framerate); - if (!time || time->tv_sec == (time_t)-1) - { - lumiera_error_set(LUMIERA_ERROR_FRAMERATE_ILLEGAL_TIME); - return LUMIERA_FRAMEPOS_ERROR; - } - - /* we add a magic microsecond for rounding, because of integer truncation frames may be calculated at most 1us earlier, - the idea is to compensate odd framerates which fall out off microsecond precision. - */ - return ((time->tv_sec * 1000000ULL + time->tv_usec + /*magic*/1) * framerate->n)/(framerate->d * 1000000ULL) + 1; -} - -/** - * Get the start time for a frame. - * frame indexing starts with 1 - * @param framerate is a pointer to the framerate used, defined as rational number. Must be given. - * @param time is a pointer to a lumiera_time which shall take the result. - * @param frame frame number to be converted to time. This frame number must be greater than 0. - * @return the pointer given in time or NULL on error (or when it was given as time). - */ -static inline LumieraTime -lumiera_framerate_time_get_time_frame (const LumieraFramerate framerate, - LumieraTime time, - lumiera_framepos frame) -{ - REQUIRE (framerate); - if (time) - { - if (frame < 1) - { - lumiera_error_set(LUMIERA_ERROR_FRAMERATE_ILLEGAL_FRAME); - return NULL; - } - - unsigned long long usec = ((frame-1) * framerate->d * 1000000ULL - (/*magic*/frame>1?1:0)) / framerate->n; - - time->tv_sec = usec / 1000000; - time->tv_usec = usec % 1000000; - } - return time; -} - -#endif diff --git a/src/lib/llist.h b/src/lib/llist.h index 4f77b20dc..128a3e826 100644 --- a/src/lib/llist.h +++ b/src/lib/llist.h @@ -27,7 +27,8 @@ #include /** - * @file Intrusive cyclic double linked list + * @file + * Intrusive cyclic double linked list * There is only one node type which contains a forward and a backward pointer. In a empty initialized node, * this pointers point to the node itself. Note that these pointers can never ever become NULL. * This lists are used by using one node as 'root' node where its both pointers are the head/tail pointer to the actual list. @@ -88,6 +89,7 @@ typedef llist * LList; typedef const llist * const_LList; typedef llist ** LList_ref; + /** * Macro to instantiate a local llist. * @param name of the llist node @@ -95,6 +97,14 @@ typedef llist ** LList_ref; #define LLIST_AUTO(name) llist name = {&name,&name} +/* + some macros for convenience +*/ +#define llist_insert_head(list, element) llist_insert_next (list, element) +#define llist_insert_tail(list, element) llist_insert_prev (list, element) +#define llist_head llist_next +#define llist_tail llist_prev + /** * cast back from a member of a structure to a pointer of the structure */ @@ -129,6 +139,30 @@ typedef llist ** LList_ref; ! llist_is_end (node, list); \ llist_backward (&node)) + +/** + * Iterate forward over a range. + * @param start first node to be interated + * @param end node after the last node be iterated + * @param node pointer to the iterated node + */ +#define LLIST_FORRANGE(start, end, node) \ + for (LList node = start; \ + node != end; \ + llist_forward (&node)) + +/** + * Iterate backward over a range. + * @param rstart first node to be interated + * @param rend node before the last node be iterated + * @param node pointer to the iterated node + */ +#define LLIST_FORRANGE_REV(rstart, rend, node) \ + for (LList node = rstart; \ + node != rend; \ + llist_backward (&node)) + + /** * Consume a list from head. * The body of this statement should remove the head from the list, else it would be a infinite loop @@ -290,7 +324,7 @@ LLIST_FUNC (LList llist_insert_next (LList self, LList next), /** * Insert a node before another. * @param self node before which we want to insert - * @param prev node which shall be inserted nefore self. Could already linked to a list from where it will be removed. + * @param prev node which shall be inserted before self. Could already linked to a list from where it will be removed. * @return self */ LLIST_FUNC (LList llist_insert_prev (LList self, LList prev), @@ -314,10 +348,9 @@ LLIST_FUNC (LList llist_insertlist_next (LList self, LList next), if (!llist_is_empty (next)) { self->next->prev = next->prev; - self->next = next->next; - - next->next->prev = self; next->prev->next = self->next; + self->next = next->next; + next->next->prev = self; next->prev = next->next = next; } @@ -335,10 +368,9 @@ LLIST_FUNC (LList llist_insertlist_prev (LList self, LList prev), if (!llist_is_empty (prev)) { self->prev->next = prev->next; - self->prev = prev->prev; - - prev->prev->next = self; prev->next->prev = self->prev; + self->prev = prev->prev; + prev->prev->next = self; prev->prev = prev->next = prev; } @@ -494,20 +526,45 @@ LLIST_FUNC (LList llist_get_nth_stop (LList self, int n, const_LList stop), return self; ); -/* - some macros for convenience -*/ -#define llist_insert_head(list, element) llist_insert_next (list, element) -#define llist_insert_tail(list, element) llist_insert_prev (list, element) -#define llist_head llist_next -#define llist_tail llist_prev + +/** + * Sort a list. + * @param self list to be sorted + * @param cmp function takeing 2 LLists + * simple recursive mergesort + */ +typedef int (*llist_cmpfn)(LList a, LList b); + +LLIST_FUNC (LList llist_sort (LList self, llist_cmpfn cmp), + llist left; + llist right; + llist_init (&left); + llist_init (&right); + unsigned n = 0; + if (!llist_is_single (self)) + { + LLIST_WHILE_HEAD (self, head) + llist_insert_prev (++n & 1 ? &left : &right, head); + + llist_sort (&left, cmp); + llist_sort (&right, cmp); + + while (!llist_is_empty (&left) && !llist_is_empty (&right)) + llist_insert_prev (self, cmp (left.next, right.next) < 0 ? left.next : right.next); + + if (!llist_is_empty (&left)) + llist_insertlist_prev (self, &left); + if (!llist_is_empty (&right)) + llist_insertlist_prev (self, &right); + } + return self; +) #endif /* LLIST_H */ /* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// End: -// arch-tag: e8fe4a59-fd55-4c45-b860-5cd1e0771213 -// end_of_file +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: */ diff --git a/src/lib/locking.h b/src/lib/locking.h index 01ad8bb29..3c4d497d8 100644 --- a/src/lib/locking.h +++ b/src/lib/locking.h @@ -28,8 +28,14 @@ #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. + * @file + * Shared declarations for all locking primitives. */ /** diff --git a/src/lib/mrucache.c b/src/lib/mrucache.c new file mode 100644 index 000000000..0f9bb86df --- /dev/null +++ b/src/lib/mrucache.c @@ -0,0 +1,58 @@ +/* + mrucache.h - most recent used cache + + 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/mrucache.h" + + +LumieraMruCache +lumiera_mrucache_init (LumieraMruCache self, lumiera_cache_destructor_fn destructor_cb) +{ + REQUIRE (self); + llist_init (&self->cache_list); + self->cached = 0; + self->destructor_cb = destructor_cb; + return self; +} + +LumieraMruCache +lumiera_mrucache_destroy (LumieraMruCache self) +{ + LLIST_WHILE_TAIL (&self->cache_list, node) + { + llist_unlink (node); + if (self->destructor_cb) + free (self->destructor_cb (node)); + else + free (node); + } + self->cached = 0; + return self; +} + +int +lumiera_mrucache_age (LumieraMruCache self, int nelem) +{ + REQUIRE (self); + while (self->cached && nelem--) + free (lumiera_mrucache_pop (self)); + + return nelem; +} diff --git a/src/lib/mrucache.h b/src/lib/mrucache.h new file mode 100644 index 000000000..08654754f --- /dev/null +++ b/src/lib/mrucache.h @@ -0,0 +1,178 @@ +/* + mrucache.h - most recent used cache + + 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_CACHE_H +#define LUMIERA_CACHE_H + +#include "lib/llist.h" + +#include + +/** + * @file + * Most recent used cache + * Elements (addressed by a LList node) are either checked in the cache and thereby subject of aging + * or checked out under control of the user. Most operations require that the chache is locked. This locking + * must be done from elsewhere. + */ + +/** + * Callback function used to destruct/cleanup aged elements. + * shall clean the element sufficiently up to be ready for being freed or reused, + * this callback function must be reentrant and prepared to be called twice. + * @param node the llist node used to link cache elements (will be empty at call) + * @return pointer to the begin of the element. + */ +typedef void* (*lumiera_cache_destructor_fn)(LList node); + +struct lumiera_mrucache_struct +{ + llist cache_list; + size_t cached; + lumiera_cache_destructor_fn destructor_cb; +}; +typedef struct lumiera_mrucache_struct lumiera_mrucache; +typedef lumiera_mrucache* LumieraMruCache; + +/** + * Initialize a cache. + * @param self cache to be initialized + * @param destructor_cb function for destructing a cache node, preparing for reuse. + * @return self + */ +LumieraMruCache +lumiera_mrucache_init (LumieraMruCache self, lumiera_cache_destructor_fn destructor_cb); + +/** + * Destroy a cache. + * frees all checked in items. + * @param self cache to be destroyed + * @return self + */ +LumieraMruCache +lumiera_mrucache_destroy (LumieraMruCache self); + + +/** + * Add an element to a mrucache. + * When added the element is subject of aging and must not be accessed anymore. + * To acces elements they have to be checked out again. + * Checkin and checkout operations must be protected by a lock over the cache. + * @param self cache where to checkin + * @param node a llist member in the cached data which is used as queue in the cache + */ +static inline void +lumiera_mrucache_checkin (LumieraMruCache self, LList node) +{ + REQUIRE (self); + REQUIRE (node && llist_is_empty (node)); + llist_insert_head (&self->cache_list, node); + ++self->cached; +} + + +/** + * Schedule an element for fast aging. + * When an element is not longer needed it can be placed at the end of the chache + * aging queue and thus become the first one to be reused when a new element is queried. + * This can be done on a checked out element as well as on an element which is in the cache. + * The cache must be locked for this operation. + * @param self cache + * @param node a llist member in the cached data which is used as queue in the cache + */ +static inline void +lumiera_mrucache_drop (LumieraMruCache self, LList node) +{ + REQUIRE (self); + REQUIRE (node); + + if (llist_is_empty (node)) + { + /* was not in list, we need to count it */ + ++self->cached; + } + else + { + /* speedup loop warning :P, this check is costly */ + REQUIRE (llist_is_member (&self->cache_list, node), "node must be empty or member of cache"); + } + llist_insert_tail (&self->cache_list, node); + + if (self->destructor_cb) + self->destructor_cb (node); +} + + +/** + * Checkout an element from a cache. + * A checked out element is not under cache control anymore until is gets checked in again. + * The code which checked the element out takes ownership of the element. + * The cache must be locked for this operation. + * @param self cache + * @param node a llist member in the cached data which is used as queue in the cache + */ +static inline void +lumiera_mrucache_checkout (LumieraMruCache self, LList node) +{ + REQUIRE (self); + REQUIRE (node && llist_is_member (&self->cache_list, node)); /* speedup loop warning :P, this check is costly */ + llist_unlink (node); + --self->cached; +} + + +/** + * Destroy the oldest element from the cache and return it. + * This function is used to get a new element by deleting the oldest least used one from the cache. + * The cache must be locked for this operation. + * @param self cache + * @return pointer to the uninitialized memory ready for being reused + */ +static inline void* +lumiera_mrucache_pop (LumieraMruCache self) +{ + REQUIRE (self); + if (llist_is_empty (&self->cache_list)) + return NULL; + + LList node = llist_tail (&self->cache_list); + llist_unlink (node); + --self->cached; + + if (self->destructor_cb) + return self->destructor_cb (node); + else + return node; +} + + +/** + * Destroy and free the nelem oldest elements. + * Used to free up resources and memory. + * @param self cache where to free elements. + * @param nelem number of elements wished to be freed + * @return nelem-(numer of elements which got freed), that is 0 if all requested elements got freed + */ +int +lumiera_mrucache_age (LumieraMruCache self, int nelem); + + +#endif diff --git a/src/lib/mutex.c b/src/lib/mutex.c index a08d89e51..b7c5f1844 100644 --- a/src/lib/mutex.c +++ b/src/lib/mutex.c @@ -22,9 +22,14 @@ #include "lib/mutex.h" /** - * @file Mutual exclusion locking. + * @file + * Mutual exclusion locking. */ +LUMIERA_ERROR_DEFINE (MUTEX_LOCK, "Mutex locking failed"); +LUMIERA_ERROR_DEFINE (MUTEX_UNLOCK, "Mutex unlocking failed"); +LUMIERA_ERROR_DEFINE (MUTEX_DESTROY, "Mutex destroy failed"); + /** * Initialize a mutex variable @@ -52,7 +57,7 @@ lumiera_mutex_destroy (LumieraMutex self) if (self) { if (pthread_mutex_destroy (&self->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_DESTROY); } return self; } diff --git a/src/lib/mutex.h b/src/lib/mutex.h index ced7118e2..f19058e7a 100644 --- a/src/lib/mutex.h +++ b/src/lib/mutex.h @@ -25,8 +25,18 @@ #include "lib/locking.h" /** - * @file Mutual exclusion locking, header. + * @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__##_);})) /** @@ -106,7 +116,7 @@ lumiera_mutexacquirer_init_mutex (LumieraMutexacquirer self, LumieraMutex mutex, self->state = state; if (state == LUMIERA_LOCKED) if (pthread_mutex_lock (&mutex->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_LOCK); return self; } @@ -124,7 +134,7 @@ lumiera_mutexacquirer_lock (LumieraMutexacquirer self) REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked"); if (pthread_mutex_lock (&self->mutex->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_LOCK); self->state = LUMIERA_LOCKED; } @@ -164,7 +174,7 @@ lumiera_mutexacquirer_try_mutex (LumieraMutexacquirer self, LumieraMutex mutex) case EBUSY: return LUMIERA_UNLOCKED; default: - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_LOCK); } } @@ -180,7 +190,7 @@ lumiera_mutexacquirer_unlock (LumieraMutexacquirer self) REQUIRE (self); REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked"); if (pthread_mutex_unlock (&self->mutex->mutex)) - LUMIERA_DIE; + LUMIERA_DIE (MUTEX_UNLOCK); self->state = LUMIERA_UNLOCKED; } diff --git a/src/lib/plugin.c b/src/lib/plugin.c index 87939533d..1f5e8576e 100644 --- a/src/lib/plugin.c +++ b/src/lib/plugin.c @@ -25,11 +25,14 @@ #include #include #include +#include #include "plugin.h" +#include "safeclib.h" /** - * @file Plugin loader. + * @file + * Plugin loader. */ @@ -159,8 +162,8 @@ lumiera_plugin_lookup (struct lumiera_plugin* self, const char* path) { /* got it */ TRACE (lumiera_plugin, "found %s", pathname); - self->pathname = strdup (pathname); - if (!self->pathname) LUMIERA_DIE; + self->pathname = lumiera_strndup (pathname, PATH_MAX); + self->type = lumiera_plugin_extensions[i].type; return 0; } @@ -195,21 +198,20 @@ lumiera_interface_open (const char* name, const char* interface, size_t min_revi plugin.name = name; /* for searching */ found = tsearch (&plugin, &lumiera_plugin_registry, lumiera_plugin_name_cmp); - if (!found) LUMIERA_DIE; + if (!found) + LUMIERA_DIE (NO_MEMORY); if (*found == &plugin) { NOTICE (lumiera_plugin, "new plugin"); /* now really create new item */ - *found = malloc (sizeof (struct lumiera_plugin)); - if (!*found) LUMIERA_DIE; + *found = lumiera_malloc (sizeof (struct lumiera_plugin)); if (name) /* NULL is main app, no lookup needed */ { /*lookup for $LUMIERA_PLUGIN_PATH*/ - (*found)->name = strdup (name); - if (!(*found)->name) LUMIERA_DIE; + (*found)->name = lumiera_strndup (name, PATH_MAX); if (!!lumiera_plugin_lookup (*found, getenv("LUMIERA_PLUGIN_PATH")) #ifdef LUMIERA_PLUGIN_PATH diff --git a/src/lib/plugin.h b/src/lib/plugin.h index f8916ae96..54dad6372 100644 --- a/src/lib/plugin.h +++ b/src/lib/plugin.h @@ -33,7 +33,8 @@ extern "C" { #include "error.h" /** - * @file Plugin loader, header. + * @file + * Plugin loader, header. */ diff --git a/src/lib/references.c b/src/lib/references.c index ad4f9562f..925258377 100644 --- a/src/lib/references.c +++ b/src/lib/references.c @@ -19,9 +19,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "lib/references.h" +#include "lib/safeclib.h" /** - * @file Strong and Weak references + * @file + * Strong and Weak references * Strong references keep some object alive while they existing * Weak references become invalidated when the referenced object gets destroyed * @@ -43,8 +45,7 @@ LumieraReference lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*)) { - LumieraReftarget target = malloc (sizeof(lumiera_reftarget)); - if (!target) LUMIERA_DIE; + LumieraReftarget target = lumiera_malloc (sizeof(lumiera_reftarget)); target->object = obj; target->dtor = dtor; diff --git a/src/lib/references.h b/src/lib/references.h index 3e00457e7..6ad65d62f 100644 --- a/src/lib/references.h +++ b/src/lib/references.h @@ -25,7 +25,8 @@ #include /** - * @file Strong and Weak references, header. + * @file + * Strong and Weak references, header. */ diff --git a/src/lib/rwlock.c b/src/lib/rwlock.c index c7ee3a37d..077ff9766 100644 --- a/src/lib/rwlock.c +++ b/src/lib/rwlock.c @@ -18,16 +18,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define _GNU_SOURCE - #include #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"); /** - * @file Read/write locks. + * @file + * Read/write locks. */ @@ -57,7 +60,7 @@ lumiera_rwlock_destroy (LumieraRWLock self) if (self) { if (pthread_rwlock_destroy (&self->rwlock)) - LUMIERA_DIE; + LUMIERA_DIE (RWLOCK_DESTROY); } return self; } @@ -95,7 +98,7 @@ lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, e lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); return NULL; default: - LUMIERA_DIE; + LUMIERA_DIE (RWLOCK_RLOCK); } case LUMIERA_WRLOCKED: switch (pthread_rwlock_wrlock (&rwlock->rwlock)) @@ -106,7 +109,7 @@ lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, e lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); return NULL; default: - LUMIERA_DIE; + LUMIERA_DIE (RWLOCK_WLOCK); } default: break; @@ -138,7 +141,7 @@ lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self) lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); return NULL; default: - LUMIERA_DIE; + LUMIERA_DIE (RWLOCK_RLOCK); } self->state = LUMIERA_RDLOCKED; @@ -166,7 +169,7 @@ lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self) lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK); return NULL; default: - LUMIERA_DIE; + LUMIERA_DIE (RWLOCK_WLOCK); } self->state = LUMIERA_WRLOCKED; diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h index 922a05e7b..d58627dda 100644 --- a/src/lib/rwlock.h +++ b/src/lib/rwlock.h @@ -33,9 +33,14 @@ LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN); LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK); +LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY); +LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK); +LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK); +LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK); /** - * @file Read/write locks, header. + * @file + * Read/write locks, header. */ @@ -106,7 +111,7 @@ lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self) REQUIRE (self); REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked"); if (pthread_rwlock_unlock (&self->rwlock->rwlock)) - LUMIERA_DIE; + LUMIERA_DIE (RWLOCK_UNLOCK); self->state = LUMIERA_UNLOCKED; } diff --git a/src/lib/safeclib.c b/src/lib/safeclib.c new file mode 100644 index 000000000..f500ea71c --- /dev/null +++ b/src/lib/safeclib.c @@ -0,0 +1,225 @@ +/* + safe_clib.c - Portable and safe wrapers around some clib functions and some tools + + 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 "error.h" + +#include +#include +#include +#include +#include + +/** + * @file + * Portable and safe wrapers around some clib functions and some tools + */ + +LUMIERA_ERROR_DEFINE (NO_MEMORY, "Out of Memory!"); + +/** + * Allocate memory. + * always succeeds or dies + * @param size memory to be allocated + * @return pointer to the allocated memory + */ +void* +lumiera_malloc (size_t size) +{ + void* o = size ? malloc (size) : NULL; + if (!o) + LUMIERA_DIE (NO_MEMORY); + return o; +} + + +/** + * Allocate cleared memory for an array. + * always succeeds or dies + * @param n number of elements + * @param size memory to be allocated + * @return pointer to the allocated memory + */ +void* +lumiera_calloc (size_t n, size_t size) +{ + void* o = (n&&size)? calloc (n, size) : NULL; + if (!o) + LUMIERA_DIE (NO_MEMORY); + return o; +} + + +/** + * Duplicate a C string. + * always succeeds or dies + * @param str string to be copied + * @param len maximal length to be copied + * @return pointer to the new string, "" if NULL was passed as str + */ +char* +lumiera_strndup (const char* str, size_t len) +{ + char* o; + if (str) + o = strndup (str, len); + else + o = strdup (""); + + if (!o) + LUMIERA_DIE (NO_MEMORY); + return o; +} + + +/** + * Compare two C strings. + * Handles NULL pointers as "", shortcut for same addresses + * @param a first string for comparsion + * @param b second string for comparsion + * @param len maximal length for the comparsion + * @return 0 if the strings are identical, -1 if smaller 1 if bigger. + */ +int +lumiera_strncmp (const char* a, const char* b, size_t len) +{ + return a == b ? 0 : strncmp (a?a:"", b?b:"", len); +} + + +/** + * check 2 strings for identity. + * @param a first string for comparsion + * @param b second string for comparsion + * @return 1 when the strings are the the same, 0 if not. + */ +int +lumiera_streq (const char* a, const char* b) +{ + return !lumiera_strncmp (a, b, SIZE_MAX); +} + + +/** + * Round robin temporary buffers. + * This provides 64 buffers per thread which are recycled with each use. + * The idea here is to have fast buffers for temporal data without need for explicit heap management. + */ +struct lumiera_tmpbuf_struct +{ + void* buffers[64]; + size_t sizes[64]; + unsigned idx; +}; + +static pthread_once_t lumiera_tmpbuf_tls_once = PTHREAD_ONCE_INIT; +static pthread_key_t lumiera_tmpbuf_tls_key; + +void +lumiera_tmpbuf_freeall (void); + +static void +lumiera_tmpbuf_destroy (void* buf) +{ + lumiera_tmpbuf_freeall (); +} + +static void +lumiera_tmpbuf_init (void) +{ + pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy); +} + + +/** + * free all buffers associated with this thread. + * This function is called automatically, usually one doesnt need to call it. + */ +void +lumiera_tmpbuf_freeall (void) +{ + pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init); + struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key); + if (buf) + { + pthread_setspecific (lumiera_tmpbuf_tls_key, NULL); + for (int idx = 0; idx < 64; ++idx) + free (buf->buffers[idx]); + free (buf); + } +} + + +/** + * Query a thread local buffer. + * @param size minimal needed size for the buffer + * @return the buffer + */ +void* +lumiera_tmpbuf_provide (size_t size) +{ + pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init); + struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key); + if (!buf) + pthread_setspecific (lumiera_tmpbuf_tls_key, + buf = lumiera_calloc (1, sizeof (struct lumiera_tmpbuf_struct))); + + buf->idx = (buf->idx + 1) & 0x3f; + + if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size) + { + free (buf->buffers[buf->idx]); + buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1); + buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]); + } + return buf->buffers[buf->idx]; +} + + +char* +lumiera_tmpbuf_strndup (const char* src, size_t size) +{ + size_t len = strlen (src); + len = len > size ? size : len; + + char* buf = lumiera_tmpbuf_provide (len + 1); + strncpy (buf, src, len); + buf[len] = '\0'; + + return buf; +} + + +char* +lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...) +{ + va_list args; + + va_start (args, fmt); + size_t len = vsnprintf (NULL, 0, fmt, args); + va_end (args); + + len = len > size ? size : len; + char* buf = lumiera_tmpbuf_provide (len+1); + va_start (args, fmt); + vsnprintf (buf, len+1, fmt, args); + va_end (args); + + return buf; +} diff --git a/src/lib/safeclib.h b/src/lib/safeclib.h new file mode 100644 index 000000000..6fc532239 --- /dev/null +++ b/src/lib/safeclib.h @@ -0,0 +1,125 @@ +/* + safe_clib.h - Portable and safe wrapers around some clib functions and some tools + + 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 "error.h" + +#include + +/** + * @file + * Portable and safe wrapers around some clib functions and some tools + */ +LUMIERA_ERROR_DECLARE(NO_MEMORY); + +/** + * Allocate memory. + * always succeeds or dies + * @param size memory to be allocated + * @return pointer to the allocated memory + */ +void* +lumiera_malloc (size_t sz); + + +/** + * Allocate cleared memory for an array. + * always succeeds or dies + * @param n number of elements + * @param size memory to be allocated + * @return pointer to the allocated memory + */ +void* +lumiera_calloc (size_t n, size_t size); + + +/** + * Duplicate a C string. + * always succeeds or dies + * @param str string to be copied + * @param len maximal length to be copied + * @return pointer to the new string, "" if NULL was passed as str + */ +char* +lumiera_strndup (const char* str, size_t len); + + +/** + * Compare two C strings. + * Handles NULL pointers as "", shortcut for same addresses + * @param a first string for comparsion + * @param b second string for comparsion + * @param len maximal length for the comparsion + * @return 0 if the strings are identical, -1 if smaller 1 if bigger. + */ +int +lumiera_strncmp (const char* a, const char* b, size_t len); + + +/** + * check 2 strings for identity. + * @param a first string for comparsion + * @param b second string for comparsion + * @return 1 when the strings are the the same, 0 if not. + */ +int +lumiera_streq (const char* a, const char* b); + + +/** + * Round robin temporary buffers. + * This provides 64 buffers per thread which are recycled with each use. + * The idea here is to have fast buffers for temporal data without need for explicit heap management. + */ + +/** + * free all buffers associated with this thread. + * This function is called automatically, usually one doesnt need to call it. + */ +void +lumiera_tmpbuf_freeall (void); + +/** + * Query a thread local tmpbuf. + * @param size minimal needed size for the tmpbuf + * @return the tmpbuf + */ +void* +lumiera_tmpbuf_provide (size_t size); + +/** + * Duplicate string to a tmpbuf. + * @param src string to be duplicated + * @param size maximal length to be copied + * @return temporary buffer containing a copy of the string + */ +char* +lumiera_tmpbuf_strndup (const char* src, size_t size); + +/** + * Construct a string in a tmpbuf. + * @param size maximal length for the string + * @param fmt printf like formatstring + * @param ... parameters + * @return temporary buffer containing the constructed of the string + */ +char* +lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...); + diff --git a/src/lib/uuid.c b/src/lib/uuid.c new file mode 100644 index 000000000..d4eee69be --- /dev/null +++ b/src/lib/uuid.c @@ -0,0 +1,95 @@ +/* + 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 new file mode 100644 index 000000000..d4cf8ce9d --- /dev/null +++ b/src/lib/uuid.h @@ -0,0 +1,67 @@ +/* + 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/proc/Makefile.am b/src/proc/Makefile.am new file mode 100644 index 000000000..603f4d825 --- /dev/null +++ b/src/proc/Makefile.am @@ -0,0 +1,251 @@ +# 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 use -Wextra -Werror + +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 \ + $(liblumiproc_a_srcdir)/frame.cpp \ + $(liblumiproc_a_srcdir)/stateproxy.cpp \ + $(liblumiproc_a_srcdir)/asset.cpp \ + $(liblumiproc_a_srcdir)/assetmanager.cpp \ + $(liblumiproc_a_srcdir)/nobugcfg.cpp + + + +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 \ + $(liblumiprocasset_a_srcdir)/compoundmedia.cpp \ + $(liblumiprocasset_a_srcdir)/dataset.cpp \ + $(liblumiprocasset_a_srcdir)/effect.cpp \ + $(liblumiprocasset_a_srcdir)/preview.cpp \ + $(liblumiprocasset_a_srcdir)/unknown.cpp \ + $(liblumiprocasset_a_srcdir)/clip.cpp \ + $(liblumiprocasset_a_srcdir)/meta.cpp \ + $(liblumiprocasset_a_srcdir)/category.cpp \ + $(liblumiprocasset_a_srcdir)/media.cpp \ + $(liblumiprocasset_a_srcdir)/pipe.cpp \ + $(liblumiprocasset_a_srcdir)/proc.cpp \ + $(liblumiprocasset_a_srcdir)/procpatt.cpp \ + $(liblumiprocasset_a_srcdir)/struct.cpp \ + $(liblumiprocasset_a_srcdir)/track.cpp + + + +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)/aframe.cpp \ + $(liblumiprocengine_a_srcdir)/arender.cpp \ + $(liblumiprocengine_a_srcdir)/codecadapter.cpp \ + $(liblumiprocengine_a_srcdir)/exitnode.cpp \ + $(liblumiprocengine_a_srcdir)/glbuf.cpp \ + $(liblumiprocengine_a_srcdir)/glpipe.cpp \ + $(liblumiprocengine_a_srcdir)/glrender.cpp \ + $(liblumiprocengine_a_srcdir)/hub.cpp \ + $(liblumiprocengine_a_srcdir)/link.cpp \ + $(liblumiprocengine_a_srcdir)/mask.cpp \ + $(liblumiprocengine_a_srcdir)/pluginadapter.cpp \ + $(liblumiprocengine_a_srcdir)/processor.cpp \ + $(liblumiprocengine_a_srcdir)/procnode.cpp \ + $(liblumiprocengine_a_srcdir)/projector.cpp \ + $(liblumiprocengine_a_srcdir)/renderengine.cpp \ + $(liblumiprocengine_a_srcdir)/source.cpp \ + $(liblumiprocengine_a_srcdir)/trafo.cpp \ + $(liblumiprocengine_a_srcdir)/vframe.cpp \ + $(liblumiprocengine_a_srcdir)/vrender.cpp + + + +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 \ + $(liblumiprocmobject_a_srcdir)/interpolator.cpp \ + $(liblumiprocmobject_a_srcdir)/mobject.cpp \ + $(liblumiprocmobject_a_srcdir)/parameter.cpp \ + $(liblumiprocmobject_a_srcdir)/paramprovider.cpp \ + $(liblumiprocmobject_a_srcdir)/placement.cpp + + + +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 \ + $(liblumiprocmobjectbuilder_a_srcdir)/conmanager.cpp \ + $(liblumiprocmobjectbuilder_a_srcdir)/nodecreatertool.cpp \ + $(liblumiprocmobjectbuilder_a_srcdir)/segmentationtool.cpp \ + $(liblumiprocmobjectbuilder_a_srcdir)/toolfactory.cpp + + +liblumiprocmobjectcontroller_a_srcdir = $(top_srcdir)/src/proc/mobject/controller +noinst_LIBRARIES += liblumiprocmobjectcontroller.a + +liblumiprocmobjectcontroller_a_CXXFLAGS = $(CXXFLAGS) -Wall +liblumiprocmobjectcontroller_a_CPPFLAGS = -I$(top_srcdir)/src/ + +liblumiprocmobjectcontroller_a_SOURCES = \ + $(liblumiprocmobjectcontroller_a_srcdir)/pathmanager.cpp \ + $(liblumiprocmobjectcontroller_a_srcdir)/renderstate.cpp + + +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 \ + $(liblumiprocmobjectsession_a_srcdir)/allocation.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/auto.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/compoundclip.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/effect.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/fixedlocation.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/label.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/meta.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/relativelocation.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/segment.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/simpleclip.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/plug.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/sessionimpl.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/sessmanagerimpl.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/edl.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/session.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/track.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/clip.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/constraint.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/defsmanager.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/fixture.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/locatingpin.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/mobjectfactory.cpp \ + $(liblumiprocmobjectsession_a_srcdir)/wish.cpp + + + + +noinst_HEADERS += \ + $(liblumiproc_a_srcdir)/asset/category.hpp \ + $(liblumiproc_a_srcdir)/asset/clip.hpp \ + $(liblumiproc_a_srcdir)/asset/codec.hpp \ + $(liblumiproc_a_srcdir)/asset/compoundmedia.hpp \ + $(liblumiproc_a_srcdir)/asset/dataset.hpp \ + $(liblumiproc_a_srcdir)/asset/effect.hpp \ + $(liblumiproc_a_srcdir)/asset/preview.hpp \ + $(liblumiproc_a_srcdir)/asset/db.hpp \ + $(liblumiproc_a_srcdir)/asset/buildinstruct.hpp \ + $(liblumiproc_a_srcdir)/asset/media.hpp \ + $(liblumiproc_a_srcdir)/asset/meta.hpp \ + $(liblumiproc_a_srcdir)/asset/pipe.hpp \ + $(liblumiproc_a_srcdir)/asset/proc.hpp \ + $(liblumiproc_a_srcdir)/asset/procpatt.hpp \ + $(liblumiproc_a_srcdir)/asset/struct.hpp \ + $(liblumiproc_a_srcdir)/asset/structfactoryimpl.hpp \ + $(liblumiproc_a_srcdir)/asset/track.hpp \ + $(liblumiproc_a_srcdir)/asset/unknown.hpp \ + $(liblumiproc_a_srcdir)/controllerfacade.hpp \ + $(liblumiproc_a_srcdir)/engine/aframe.hpp \ + $(liblumiproc_a_srcdir)/engine/arender.hpp \ + $(liblumiproc_a_srcdir)/engine/codecadapter.hpp \ + $(liblumiproc_a_srcdir)/engine/exitnode.hpp \ + $(liblumiproc_a_srcdir)/engine/glbuf.hpp \ + $(liblumiproc_a_srcdir)/engine/glpipe.hpp \ + $(liblumiproc_a_srcdir)/engine/glrender.hpp \ + $(liblumiproc_a_srcdir)/engine/hub.hpp \ + $(liblumiproc_a_srcdir)/engine/link.hpp \ + $(liblumiproc_a_srcdir)/engine/mask.hpp \ + $(liblumiproc_a_srcdir)/engine/pluginadapter.hpp \ + $(liblumiproc_a_srcdir)/engine/procnode.hpp \ + $(liblumiproc_a_srcdir)/engine/projector.hpp \ + $(liblumiproc_a_srcdir)/engine/renderengine.hpp \ + $(liblumiproc_a_srcdir)/engine/source.hpp \ + $(liblumiproc_a_srcdir)/engine/trafo.hpp \ + $(liblumiproc_a_srcdir)/engine/vframe.hpp \ + $(liblumiproc_a_srcdir)/engine/vrender.hpp \ + $(liblumiproc_a_srcdir)/engine/processor.hpp \ + $(liblumiproc_a_srcdir)/frame.hpp \ + $(liblumiproc_a_srcdir)/mobject/builder/assembler.hpp \ + $(liblumiproc_a_srcdir)/mobject/builder/buildertool.hpp \ + $(liblumiproc_a_srcdir)/mobject/builder/conmanager.hpp \ + $(liblumiproc_a_srcdir)/mobject/builder/nodecreatertool.hpp \ + $(liblumiproc_a_srcdir)/mobject/builder/segmentationtool.hpp \ + $(liblumiproc_a_srcdir)/mobject/builder/toolfactory.hpp \ + $(liblumiproc_a_srcdir)/mobject/builderfacade.hpp \ + $(liblumiproc_a_srcdir)/mobject/controller/pathmanager.hpp \ + $(liblumiproc_a_srcdir)/mobject/controller/renderstate.hpp \ + $(liblumiproc_a_srcdir)/mobject/interpolator.hpp \ + $(liblumiproc_a_srcdir)/mobject/parameter.hpp \ + $(liblumiproc_a_srcdir)/mobject/paramprovider.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/abstractmo.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/allocation.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/auto.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/compoundclip.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/effect.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/fixedlocation.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/label.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/meta.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/relativelocation.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/simpleclip.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/mobjectfactory.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/segment.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/track.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/wish.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/clip.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/constraint.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/defsmanager.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/edl.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/fixture.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/locatingpin.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/plug.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/sessionimpl.hpp \ + $(liblumiproc_a_srcdir)/mobject/session/defsregistry.hpp \ + $(liblumiproc_a_srcdir)/mobject/explicitplacement.hpp \ + $(liblumiproc_a_srcdir)/mobject/mobject.hpp \ + $(liblumiproc_a_srcdir)/mobject/placement.hpp \ + $(liblumiproc_a_srcdir)/mobject/session.hpp \ + $(liblumiproc_a_srcdir)/stateproxy.hpp \ + $(liblumiproc_a_srcdir)/asset.hpp \ + $(liblumiproc_a_srcdir)/assetmanager.hpp \ + $(liblumiproc_a_srcdir)/lumiera.hpp \ + $(liblumiproc_a_srcdir)/nobugcfg.hpp + diff --git a/tests/15safeclib.tests b/tests/15safeclib.tests new file mode 100644 index 000000000..7e4039ead --- /dev/null +++ b/tests/15safeclib.tests @@ -0,0 +1,28 @@ + +TESTING "Safe clib and tools" ./test-safeclib + +TEST "Allocating 0 bytes" allocation0 < ,tmp_testfile + +TEST "acquire existing file" acquire_existing < +# 2007-2008, Christian Thaeter # Hermann Vosseler # # This program is free software; you can redistribute it and/or @@ -36,14 +36,29 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ test_llist_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm +check_PROGRAMS += test-safeclib +test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c +test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_safeclib_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm + +check_PROGRAMS += test-uuid +test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c +test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ +test_uuid_LDADD = $(builddir)/liblumi.a -lnobugmt -lpthread -ldl -lm + check_PROGRAMS += test-references test_references_SOURCES = $(tests_srcdir)/library/test-references.c test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ test_references_LDADD = liblumi.a -lnobugmt -lpthread -ldl -lm -lrt -#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_LDADD = liblumibackend.a liblumi.a -lnobugmt -lpthread -ldl -lm +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_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_LDADD = liblumibackend.a liblumi.a -lnobugmt -lpthread -ldl -lm TESTS = $(tests_srcdir)/test.sh diff --git a/tests/backend/test-filedescriptors.c b/tests/backend/test-filedescriptors.c new file mode 100644 index 000000000..3e14ead1d --- /dev/null +++ b/tests/backend/test-filedescriptors.c @@ -0,0 +1,89 @@ +/* + test-filedescriptors.c + + 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/safeclib.h" + +#include "backend/backend.h" +#include "backend/filedescriptor.h" + +#include "tests/test.h" + +TESTS_BEGIN + +TEST ("acquire_existing") +{ + lumiera_backend_init (); + LumieraFiledescriptor descriptor = lumiera_filedescriptor_acquire (",tmp_testfile", LUMIERA_FILE_READONLY); + if (descriptor) + { + lumiera_filedescriptor_release (descriptor); + lumiera_backend_destroy (); + return 0; + } + else + return 1; +} + +TEST ("acquire_existing_again") +{ + lumiera_backend_init (); + LumieraFiledescriptor descriptor = lumiera_filedescriptor_acquire (",tmp_testfile", LUMIERA_FILE_READONLY); + if (descriptor) + { + LumieraFiledescriptor descriptor2 = lumiera_filedescriptor_acquire (",tmp_testfile", LUMIERA_FILE_READONLY); + lumiera_filedescriptor_release (descriptor2); + lumiera_filedescriptor_release (descriptor); + lumiera_backend_destroy (); + return 0; + } + else + return 1; +} + +TEST ("acquire_create") +{ + lumiera_backend_init (); + LumieraFiledescriptor descriptor = lumiera_filedescriptor_acquire (",tmp_testfile", LUMIERA_FILE_CREATE); + if (descriptor) + { + lumiera_filedescriptor_release (descriptor); + lumiera_backend_destroy (); + return 0; + } + else + return 1; +} + +TEST ("acquire_create_dir") +{ + lumiera_backend_init (); + LumieraFiledescriptor descriptor = + lumiera_filedescriptor_acquire (",tmp_testdir/nested/,tmp_testfile", LUMIERA_FILE_CREATE); + if (descriptor) + { + lumiera_filedescriptor_release (descriptor); + lumiera_backend_destroy (); + return 0; + } + else + return 1; +} + +TESTS_END diff --git a/tests/backend/test-filehandles.c b/tests/backend/test-filehandles.c new file mode 100644 index 000000000..17c237d4f --- /dev/null +++ b/tests/backend/test-filehandles.c @@ -0,0 +1,87 @@ +/* + test-filehandles.c - test filehandle management + + 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/llist.h" +#include "lib/safeclib.h" + +#include "backend/backend.h" +#include "backend/filehandlecache.h" + +#include "tests/test.h" + +TESTS_BEGIN + +TEST ("basic") +{ + lumiera_backend_init (); + LumieraFile file = lumiera_file_new (",tmp_testfile", LUMIERA_FILE_CREATE); + + /* get the filehandle */ + int fd = lumiera_file_handle_acquire (file); + + /* we now 'own'it and can use it */ + ENSURE (fd > -1); + printf ("got filehandle #%d\n", fd); + + /* put it into aging, can't use anymore */ + lumiera_file_handle_release (file); + + lumiera_file_delete (file); + lumiera_backend_destroy (); +} + + +TEST ("more") +{ + lumiera_backend_init (); + + LumieraFile files[100]; + int fds[100]; + + /*create 100 files*/ + for (int i=0; i<100; ++i) + { + files[i]= lumiera_file_new (lumiera_tmpbuf_snprintf (256, ",tmpdir/testfile%d", i), LUMIERA_FILE_CREATE); + } + + /* get the filehandles, this gross overallocates filehandles */ + for (int i=0; i<100; ++i) + { + fds[i] = lumiera_file_handle_acquire (files[i]); + ENSURE (fds[i] > -1); + printf ("got filehandle #%d\n", fds[i]); + } + + /* put them into aging, can't use anymore */ + for (int i=0; i<100; ++i) + { + lumiera_file_handle_release (files[i]); + } + + /* cleanup */ + for (int i=0; i<100; ++i) + { + lumiera_file_delete (files[i]); + } + + lumiera_backend_destroy (); +} + +TESTS_END diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am new file mode 100644 index 000000000..cc027e477 --- /dev/null +++ b/tests/common/Makefile.am @@ -0,0 +1,61 @@ +# Copyright (C) Lumiera.org +# 2008, Christian Thaeter +# Hermann Vosseler +# +# 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. + +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_LDADD = \ + liblumiproc.a \ + liblumiprocengine.a \ + liblumiprocmobjectbuilder.a \ + liblumiprocmobjectsession.a \ + liblumiprocasset.a \ + liblumiprocmobject.a \ + liblumiprocmobjectcontroller.a \ + liblumi.a \ + liblumicommon.a \ + liblumibackend.a \ + -lnobugmt -lpthread -ldl -lboost_program_options-mt -lboost_regex-mt + +test_common_SOURCES = \ + $(testcommon_srcdir)/appconfigtest.cpp \ + $(testcommon_srcdir)/customsharedptrtest.cpp \ + $(testcommon_srcdir)/exceptionerrortest.cpp \ + $(testcommon_srcdir)/factoryspecialtest.cpp \ + $(testcommon_srcdir)/factorytest.cpp \ + $(testcommon_srcdir)/helloworldtest.cpp \ + $(testcommon_srcdir)/lifecycletest.cpp \ + $(testcommon_srcdir)/mainsuite.cpp \ + $(testcommon_srcdir)/query/queryutilstest.cpp \ + $(testcommon_srcdir)/removefromsettest.cpp \ + $(testcommon_srcdir)/sanitizedidentifiertest.cpp \ + $(testcommon_srcdir)/singletonsubclasstest.cpp \ + $(testcommon_srcdir)/singletontest.cpp \ + $(testcommon_srcdir)/singletontestmocktest.cpp \ + $(testcommon_srcdir)/test/cmdlinewrappertest.cpp \ + $(testcommon_srcdir)/test/testoptiontest.cpp \ + $(testcommon_srcdir)/typelisttest.cpp \ + $(testcommon_srcdir)/typelistutiltest.cpp \ + $(testcommon_srcdir)/visitingtoolconcept.cpp \ + $(testcommon_srcdir)/visitingtoolextendedtest.cpp \ + $(testcommon_srcdir)/visitingtooltest.cpp + +noinst_HEADERS += \ + $(testcommon_srcdir)/query/querydiagnostics.hpp \ + $(testcommon_srcdir)/testtargetobj.hpp diff --git a/tests/components/Makefile.am b/tests/components/Makefile.am new file mode 100644 index 000000000..088dbe668 --- /dev/null +++ b/tests/components/Makefile.am @@ -0,0 +1,72 @@ +# Copyright (C) Lumiera.org +# 2008, Christian Thaeter +# Hermann Vosseler +# +# 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. + +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_LDADD = \ + liblumiproc.a \ + liblumiprocengine.a \ + liblumiprocmobjectbuilder.a \ + liblumiprocmobjectsession.a \ + liblumiprocasset.a \ + liblumiprocmobject.a \ + liblumiprocmobjectcontroller.a \ + liblumi.a \ + liblumicommon.a \ + liblumibackend.a \ + -lnobugmt -lpthread -ldl -lboost_program_options-mt -lboost_regex-mt + +test_components_SOURCES = \ + $(testcomponents_srcdir)/backend/mediaaccessmock.cpp \ + $(testcomponents_srcdir)/backend/mediaaccessmocktest.cpp \ + $(testcomponents_srcdir)/proc/asset/assetcategorytest.cpp \ + $(testcomponents_srcdir)/proc/asset/compoundmediatest.cpp \ + $(testcomponents_srcdir)/proc/asset/deleteassettest.cpp \ + $(testcomponents_srcdir)/proc/asset/identityofassetstest.cpp \ + $(testcomponents_srcdir)/proc/asset/mediastructurequerytest.cpp \ + $(testcomponents_srcdir)/proc/asset/basicpipetest.cpp \ + $(testcomponents_srcdir)/proc/asset/createassettest.cpp \ + $(testcomponents_srcdir)/proc/asset/dependantassetstest.cpp \ + $(testcomponents_srcdir)/proc/asset/makecliptest.cpp \ + $(testcomponents_srcdir)/proc/asset/orderingofassetstest.cpp \ + $(testcomponents_srcdir)/proc/asset/testasset.cpp \ + $(testcomponents_srcdir)/proc/engine/sourcenodetest.cpp \ + $(testcomponents_srcdir)/proc/mobject/builder/buildertooltest.cpp \ + $(testcomponents_srcdir)/proc/mobject/builder/buildsegmenttest.cpp \ + $(testcomponents_srcdir)/proc/mobject/controller/rendersegmenttest.cpp \ + $(testcomponents_srcdir)/proc/mobject/placementbasictest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/addcliptest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/deletecliptest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/rebuildfixturetest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/sessionmanagertest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/testclip.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/defsmanagerimpltest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/defsmanagertest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/defsregistryimpltest.cpp \ + $(testcomponents_srcdir)/proc/mobject/session/sessionstructuretest.cpp \ + $(testcomponents_srcdir)/mainsuite.cpp + +noinst_HEADERS += \ + $(testcomponents_srcdir)/backend/mediaaccessmock.hpp \ + $(testcomponents_srcdir)/proc/asset/testclipasset.hpp \ + $(testcomponents_srcdir)/proc/asset/assetdiagnostics.hpp \ + $(testcomponents_srcdir)/proc/asset/testasset.hpp \ + $(testcomponents_srcdir)/proc/mobject/session/testclip.hpp \ + $(testcomponents_srcdir)/proc/mobject/session/testsession1.hpp diff --git a/tests/library/test-llist.c b/tests/library/test-llist.c index 12592aa4a..66bfa614d 100644 --- a/tests/library/test-llist.c +++ b/tests/library/test-llist.c @@ -23,173 +23,166 @@ //#include #include "lib/llist.h" -#include "lib/error.h" +#include "tests/test.h" +TESTS_BEGIN -LUMIERA_ERROR_DEFINE(TEST, "test error"); - -int -main (int argc, char** argv) +TEST ("basic") { - NOBUG_INIT; + LLIST_AUTO (node1); - if (argc == 1) - return 0; + llist node2; + llist_init (&node2); - if (!strcmp(argv[1], "basic")) - { - LLIST_AUTO (node1); - - llist node2; - llist_init (&node2); - - printf ("%d\n", llist_is_empty (&node1)); - printf ("%d\n", llist_is_empty (&node2)); - } - else if (!strcmp(argv[1], "nodeinsert")) - { - LLIST_AUTO (list); - LLIST_AUTO (node1); - LLIST_AUTO (node2); - LLIST_AUTO (node3); - - llist_insert_next (&list, &node1); - printf ("%d\n", llist_is_empty (&list)); - printf ("%d\n", llist_is_empty (&node1)); - printf ("%d\n", llist_is_single (&node1)); - llist_insert_next (&node1, &node2); - printf ("%d\n", llist_is_single (&node1)); - llist_insert_prev (&node1, &node3); - printf ("%d\n", llist_next (&list) == &node3); - printf ("%d\n", llist_next (&node3) == &node1); - printf ("%d\n", llist_next (&node1) == &node2); - printf ("%d\n", llist_prev (&list) == &node2); - printf ("%d\n", llist_count (&list)); - } - else if (!strcmp(argv[1], "predicates")) - { - LLIST_AUTO (list); - LLIST_AUTO (node1); - LLIST_AUTO (node2); - LLIST_AUTO (node3); - LLIST_AUTO (node4); - LLIST_AUTO (nil); - - llist_insert_tail (&list, &node2); - llist_insert_tail (&list, &node3); - llist_insert_tail (&list, &node4); - llist_insert_head (&list, &node1); - - printf ("%d\n", llist_is_head (&list, &node1)); - printf ("%d\n", llist_is_tail (&list, &node4)); - printf ("%d\n", llist_is_head (&list, &node4)); - printf ("%d\n", llist_is_tail (&list, &node1)); - printf ("%d\n", llist_is_end (&list, &list)); - printf ("%d\n", llist_is_member (&list, &node3)); - printf ("%d\n", llist_is_member (&list, &nil)); - - printf ("%d\n", llist_is_before_after (&list, &node1, &node3)); - printf ("%d\n", llist_is_before_after (&list, &node3, &node1)); - printf ("%d\n", llist_is_before_after (&list, &node1, &nil)); - } - else if (!strcmp(argv[1], "unlink")) - { - LLIST_AUTO (list); - LLIST_AUTO (node1); - LLIST_AUTO (node2); - LLIST_AUTO (node3); - LLIST_AUTO (node4); - LLIST_AUTO (nil); - - llist_insert_tail (&list, &node2); - llist_insert_tail (&list, &node3); - llist_insert_tail (&list, &node4); - llist_insert_head (&list, &node1); - - LLIST_FOREACH_REV (&list, itr) - { - if(itr == &node1) printf ("node1 "); - else if(itr == &node2) printf ("node2 "); - else if(itr == &node3) printf ("node3 "); - else if(itr == &node4) printf ("node4 "); - else printf ("unknown "); - } - printf (".\n"); - - llist_unlink (&nil); - llist_unlink (&node2); - llist_unlink (&node3); - - LLIST_FOREACH (&list, itr) - { - if(itr == &node1) printf ("node1 "); - else if(itr == &node2) printf ("node2 "); - else if(itr == &node3) printf ("node3 "); - else if(itr == &node4) printf ("node4 "); - else printf ("unknown "); - } - printf (".\n"); - printf ("%d\n", llist_is_empty (&node2)); - printf ("%d\n", llist_is_empty (&node3)); - printf ("%d\n", llist_is_empty (&nil)); - } - else if (!strcmp(argv[1], "whiles")) - { - LLIST_AUTO (list); - LLIST_AUTO (node1); - LLIST_AUTO (node2); - LLIST_AUTO (node3); - LLIST_AUTO (node4); - LLIST_AUTO (nil); - - llist_insert_tail (&list, &node2); - llist_insert_tail (&list, &node3); - llist_insert_tail (&list, &node4); - llist_insert_head (&list, &node1); - - LLIST_FOREACH_REV (&list, itr) - { - if(itr == &node1) printf ("node1 "); - else if(itr == &node2) printf ("node2 "); - else if(itr == &node3) printf ("node3 "); - else if(itr == &node4) printf ("node4 "); - else printf ("unknown "); - } - printf (".\n"); - - LLIST_WHILE_HEAD (&list, head) - llist_unlink (head); - - LLIST_FOREACH (&list, itr) - { - if(itr == &node1) printf ("node1 "); - else if(itr == &node2) printf ("node2 "); - else if(itr == &node3) printf ("node3 "); - else if(itr == &node4) printf ("node4 "); - else printf ("unknown "); - } - printf (".\n"); - - llist_insert_tail (&list, &node2); - llist_insert_tail (&list, &node3); - llist_insert_tail (&list, &node4); - llist_insert_head (&list, &node1); - - LLIST_WHILE_TAIL (&list, tail) - llist_unlink (tail); - - LLIST_FOREACH (&list, itr) - { - if(itr == &node1) printf ("node1 "); - else if(itr == &node2) printf ("node2 "); - else if(itr == &node3) printf ("node3 "); - else if(itr == &node4) printf ("node4 "); - else printf ("unknown "); - } - printf (".\n"); - } - else - return 1; - - return 0; + printf ("%d\n", llist_is_empty (&node1)); + printf ("%d\n", llist_is_empty (&node2)); } + +TEST ("nodeinsert") +{ + LLIST_AUTO (list); + LLIST_AUTO (node1); + LLIST_AUTO (node2); + LLIST_AUTO (node3); + + llist_insert_next (&list, &node1); + printf ("%d\n", llist_is_empty (&list)); + printf ("%d\n", llist_is_empty (&node1)); + printf ("%d\n", llist_is_single (&node1)); + llist_insert_next (&node1, &node2); + printf ("%d\n", llist_is_single (&node1)); + llist_insert_prev (&node1, &node3); + printf ("%d\n", llist_next (&list) == &node3); + printf ("%d\n", llist_next (&node3) == &node1); + printf ("%d\n", llist_next (&node1) == &node2); + printf ("%d\n", llist_prev (&list) == &node2); + printf ("%d\n", llist_count (&list)); +} + +TEST ("predicates") +{ + LLIST_AUTO (list); + LLIST_AUTO (node1); + LLIST_AUTO (node2); + LLIST_AUTO (node3); + LLIST_AUTO (node4); + LLIST_AUTO (nil); + + llist_insert_tail (&list, &node2); + llist_insert_tail (&list, &node3); + llist_insert_tail (&list, &node4); + llist_insert_head (&list, &node1); + + printf ("%d\n", llist_is_head (&list, &node1)); + printf ("%d\n", llist_is_tail (&list, &node4)); + printf ("%d\n", llist_is_head (&list, &node4)); + printf ("%d\n", llist_is_tail (&list, &node1)); + printf ("%d\n", llist_is_end (&list, &list)); + printf ("%d\n", llist_is_member (&list, &node3)); + printf ("%d\n", llist_is_member (&list, &nil)); + + printf ("%d\n", llist_is_before_after (&list, &node1, &node3)); + printf ("%d\n", llist_is_before_after (&list, &node3, &node1)); + printf ("%d\n", llist_is_before_after (&list, &node1, &nil)); +} + +TEST ("unlink") +{ + LLIST_AUTO (list); + LLIST_AUTO (node1); + LLIST_AUTO (node2); + LLIST_AUTO (node3); + LLIST_AUTO (node4); + LLIST_AUTO (nil); + + llist_insert_tail (&list, &node2); + llist_insert_tail (&list, &node3); + llist_insert_tail (&list, &node4); + llist_insert_head (&list, &node1); + + LLIST_FOREACH_REV (&list, itr) + { + if(itr == &node1) printf ("node1 "); + else if(itr == &node2) printf ("node2 "); + else if(itr == &node3) printf ("node3 "); + else if(itr == &node4) printf ("node4 "); + else printf ("unknown "); + } + printf (".\n"); + + llist_unlink (&nil); + llist_unlink (&node2); + llist_unlink (&node3); + + LLIST_FOREACH (&list, itr) + { + if(itr == &node1) printf ("node1 "); + else if(itr == &node2) printf ("node2 "); + else if(itr == &node3) printf ("node3 "); + else if(itr == &node4) printf ("node4 "); + else printf ("unknown "); + } + printf (".\n"); + printf ("%d\n", llist_is_empty (&node2)); + printf ("%d\n", llist_is_empty (&node3)); + printf ("%d\n", llist_is_empty (&nil)); +} + +TEST ("whiles") +{ + LLIST_AUTO (list); + LLIST_AUTO (node1); + LLIST_AUTO (node2); + LLIST_AUTO (node3); + LLIST_AUTO (node4); + LLIST_AUTO (nil); + + llist_insert_tail (&list, &node2); + llist_insert_tail (&list, &node3); + llist_insert_tail (&list, &node4); + llist_insert_head (&list, &node1); + + LLIST_FOREACH_REV (&list, itr) + { + if(itr == &node1) printf ("node1 "); + else if(itr == &node2) printf ("node2 "); + else if(itr == &node3) printf ("node3 "); + else if(itr == &node4) printf ("node4 "); + else printf ("unknown "); + } + printf (".\n"); + + LLIST_WHILE_HEAD (&list, head) + llist_unlink (head); + + LLIST_FOREACH (&list, itr) + { + if(itr == &node1) printf ("node1 "); + else if(itr == &node2) printf ("node2 "); + else if(itr == &node3) printf ("node3 "); + else if(itr == &node4) printf ("node4 "); + else printf ("unknown "); + } + printf (".\n"); + + llist_insert_tail (&list, &node2); + llist_insert_tail (&list, &node3); + llist_insert_tail (&list, &node4); + llist_insert_head (&list, &node1); + + LLIST_WHILE_TAIL (&list, tail) + llist_unlink (tail); + + LLIST_FOREACH (&list, itr) + { + if(itr == &node1) printf ("node1 "); + else if(itr == &node2) printf ("node2 "); + else if(itr == &node3) printf ("node3 "); + else if(itr == &node4) printf ("node4 "); + else printf ("unknown "); + } + printf (".\n"); +} + + +TESTS_END diff --git a/tests/library/test-safeclib.c b/tests/library/test-safeclib.c new file mode 100644 index 000000000..837e3d5fd --- /dev/null +++ b/tests/library/test-safeclib.c @@ -0,0 +1,85 @@ +/* + 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/safeclib.h" +#include "tests/test.h" + +#include +#include + +TESTS_BEGIN + +TEST ("allocation0") +{ + lumiera_malloc (0); + NOTREACHED; +} + +TEST ("allocation1024") +{ + void* data[1024]; + for (int i = 0; i < 1024; ++i) + { + data[i] = lumiera_malloc (1024); + ENSURE (data[i]); + } + for (int i = 0; i < 1024; ++i) + { + free (data[i]); + } +} + +TEST ("allocationtoobig") +{ + struct rlimit rl; + rl.rlim_cur = 100*1024*1024; + rl.rlim_max = 100*1024*1024; + setrlimit (RLIMIT_AS, &rl); + lumiera_malloc (200*1024*1024); + NOTREACHED; +} + +TEST ("streq") +{ + if (!lumiera_streq ("foo", "foo")) + LUMIERA_DIE (TEST); + if (!lumiera_streq (NULL, NULL)) + LUMIERA_DIE (TEST); + if (!!lumiera_streq (NULL, "foo")) + LUMIERA_DIE (TEST); + if (!!lumiera_streq ("foo", NULL)) + LUMIERA_DIE (TEST); + if (!!lumiera_streq ("foo", "bar")) + LUMIERA_DIE (TEST); +} + +TEST ("tmpbuf") +{ + for (int i = 0; i < 256; ++i) + { + char* buf = lumiera_tmpbuf_provide (1024); + + for (int j = 0; j < 1024; ++j) + { + buf[j] = i; + } + } +} + + +TESTS_END diff --git a/tests/library/test-uuid.c b/tests/library/test-uuid.c new file mode 100644 index 000000000..4a6050163 --- /dev/null +++ b/tests/library/test-uuid.c @@ -0,0 +1,73 @@ +/* + test-uuid.c - test the uuid lib + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +//#include "cinelerra-config.h" + +//#include + + +#include "lib/uuid.h" + +#include + +//CINELERRA_ERROR_DEFINE(TEST, "test error"); + +int +main (int argc, char** argv) +{ + NOBUG_INIT; + + if (argc == 1) + return 0; + + if (!strcmp(argv[1], "uuidgen_2")) + { + lumiera_uuid uuid1; + lumiera_uuid uuid2; + + lumiera_uuid_gen (&uuid1); + lumiera_uuid_gen (&uuid2); + + printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1)); + } + else if (!strcmp(argv[1], "uuidgen_copy")) + { + lumiera_uuid uuid1; + lumiera_uuid uuid2; + + lumiera_uuid_gen (&uuid1); + + lumiera_uuid_copy (&uuid2, &uuid1); + + printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1)); + } + else if (!strcmp(argv[1], "ptrs")) + { + lumiera_uuid uuid; + + lumiera_uuid_set_ptr (&uuid, &uuid); + + printf ("%d\n", lumiera_uuid_ptr_get (&uuid) == &uuid); + } + else + return 1; + + return 0; +} diff --git a/tests/locking/test-locking.c b/tests/locking/test-locking.c index 1b54d152e..b37c2c07f 100644 --- a/tests/locking/test-locking.c +++ b/tests/locking/test-locking.c @@ -21,33 +21,21 @@ #include #include - -#include "lib/error.h" - -LUMIERA_ERROR_DEFINE(TEST, "test error"); +#include "tests/test.h" int conditionforgotunlock (); int mutexforgotunlock (); +TESTS_BEGIN -int -main (int argc, char** argv) +TEST ("conditionforgotunlock") { - NOBUG_INIT; - - if (argc == 1) - return 0; - - if (!strcmp(argv[1], "conditionforgotunlock")) - { - return conditionforgotunlock (); - } - if (!strcmp(argv[1], "mutexforgotunlock")) - { - return mutexforgotunlock (); - } - else - return 1; - - return 0; + return conditionforgotunlock (); } + +TEST ("mutexforgotunlock") +{ + return mutexforgotunlock (); +} + +TESTS_END diff --git a/tests/plugin/plugin_main.c b/tests/plugin/plugin_main.c index 2efe32471..4b95ea60c 100644 --- a/tests/plugin/plugin_main.c +++ b/tests/plugin/plugin_main.c @@ -3,6 +3,7 @@ #include "lib/plugin.h" #include "hello_interface.h" +LUMIERA_ERROR_DEFINE(FAILURE, "test failure"); int main(int argc, char** argv) @@ -25,7 +26,7 @@ main(int argc, char** argv) LUMIERA_INTERFACE_TYPE(hello, 1)* hello_de = (LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin", "german_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1))); - if (!hello_de) LUMIERA_DIE; + if (!hello_de) LUMIERA_DIE (FAILURE); hello_de->hello(); hello_de->goodbye(argv[1]); @@ -33,7 +34,7 @@ main(int argc, char** argv) LUMIERA_INTERFACE_TYPE(hello, 1)* hello_en = (LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin", "english_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1))); - if (!hello_en) LUMIERA_DIE; + if (!hello_en) LUMIERA_DIE (FAILURE); hello_en->hello(); hello_en->goodbye(argv[1]); @@ -48,7 +49,7 @@ main(int argc, char** argv) LUMIERA_INTERFACE_TYPE(hello, 1)* hello_de = (LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin_cpp", "german_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1))); - if (!hello_de) LUMIERA_DIE; + if (!hello_de) LUMIERA_DIE (FAILURE); hello_de->hello(); hello_de->goodbye(argv[1]); @@ -56,7 +57,7 @@ main(int argc, char** argv) LUMIERA_INTERFACE_TYPE(hello, 1)* hello_en = (LUMIERA_INTERFACE_TYPE(hello, 1)*) lumiera_interface_open ("example_plugin_cpp", "english_1", sizeof(LUMIERA_INTERFACE_TYPE(hello, 1))); - if (!hello_en) LUMIERA_DIE; + if (!hello_en) LUMIERA_DIE (FAILURE); hello_en->hello(); hello_en->goodbye(argv[1]); diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 000000000..d25fa0a59 --- /dev/null +++ b/tests/test.h @@ -0,0 +1,52 @@ +/* + test.h - macros for running tests + + 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 TEST_H +#define TEST_H + +#include + +#include "lib/error.h" + +LUMIERA_ERROR_DEFINE (TEST, "test error"); + +#define TESTS_BEGIN \ +int \ +main (int argc, char** argv) \ +{ \ + NOBUG_INIT; \ + \ + if (argc == 1) \ + return 1; + +#define TEST(name) \ + else if (!strcmp(argv[1], name)) + + +#define TESTS_END \ + else \ + return 1; \ + \ + return 0; \ +} + + +#endif diff --git a/wiki/compatibility.html b/wiki/compatibility.html index 979f2301c..6eec84d85 100644 --- a/wiki/compatibility.html +++ b/wiki/compatibility.html @@ -2104,13 +2104,26 @@ if (oldText.indexOf("SplashScreen")==-1) } //}}} -
+
! Source code formatting
-http://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting
+We decided to use the 'gnu-style' for indenting (using spaces and never tabs!):
+ http://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting
+
+It is reasonable to be relaxed about soem formatting rules:
+ * line length might be longer when required
+ * inter expession spacing can be changed to the actual needed ex: (2*x + 2)
+
+Things we are pedantic about:
+ * use never ever tab characters in C/C++ sources
+ * be consistent
+ * source files should end with a newline
+ * no trailing or bogus whitespaces
+
+! Coding Practices
+
+! Writing Tests
 
 ! Contibuting
-
-! Tests
 
diff --git a/wiki/index.html b/wiki/index.html old mode 100755 new mode 100644 diff --git a/wiki/todo.html b/wiki/todo.html index d6caf66be..763c8a80a 100644 --- a/wiki/todo.html +++ b/wiki/todo.html @@ -3344,6 +3344,15 @@ Someone might pickup a Doxygen-Maintainer. This is not writing actual documentat
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.
+
+
+
+
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 on 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.