diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index fbfbed33e..30458418a 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -30,6 +30,7 @@ liblumierabackend_la_SOURCES = \ $(liblumierabackend_la_srcdir)/file.c \ $(liblumierabackend_la_srcdir)/filehandle.c \ $(liblumierabackend_la_srcdir)/filedescriptor.c \ + $(liblumierabackend_la_srcdir)/filedescriptorregistry.c \ $(liblumierabackend_la_srcdir)/filehandlecache.c \ $(liblumierabackend_la_srcdir)/mmap.c \ $(liblumierabackend_la_srcdir)/mmapings.c \ @@ -47,6 +48,7 @@ noinst_HEADERS += \ $(liblumierabackend_la_srcdir)/file.h \ $(liblumierabackend_la_srcdir)/filehandle.h \ $(liblumierabackend_la_srcdir)/filedescriptor.h \ + $(liblumierabackend_la_srcdir)/filedescriptorregistry.h \ $(liblumierabackend_la_srcdir)/filehandlecache.h \ $(liblumierabackend_la_srcdir)/mmap.h \ $(liblumierabackend_la_srcdir)/mmapings.h \ diff --git a/src/backend/backend.c b/src/backend/backend.c index 5440632a1..945024958 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -26,6 +26,7 @@ #include "common/config.h" #include "backend/filehandlecache.h" #include "backend/filedescriptor.h" +#include "backend/filedescriptorregistry.h" #include "backend/mmapcache.h" #include "backend/threadpool.h" @@ -65,9 +66,11 @@ lumiera_backend_init (void) TRACE (backend_dbg); + lumiera_mutex_init (&lumiera_filecreate_mutex, "fileaccess", &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); + lumiera_threadpool_init (); - lumiera_filedescriptor_registry_init (); + lumiera_filedescriptorregistry_init (); lumiera_backend_pagesize = sysconf(_SC_PAGESIZE); @@ -115,6 +118,9 @@ lumiera_backend_destroy (void) TRACE (backend_dbg); lumiera_mmapcache_delete (); lumiera_filehandlecache_delete (); - lumiera_filedescriptor_registry_destroy (); + lumiera_filedescriptorregistry_destroy (); lumiera_threadpool_destroy (); + + lumiera_mutex_destroy (&lumiera_filecreate_mutex, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); } + diff --git a/src/backend/backend.h b/src/backend/backend.h index 8bfa18db5..f1e68c85b 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -21,12 +21,21 @@ #ifndef LUMIERA_BACKEND_H #define LUMIERA_BACKEND_H +#include "lib/mutex.h" + #include //NOBUG_DECLARE_FLAG (backend); extern size_t lumiera_backend_pagesize; +/** + * Protect lookup and creation of files. + * Trying to access a nonexistent file with O_CREAT would be racy. + * Defined in filedescriptor.c + */ +extern lumiera_mutex lumiera_filecreate_mutex; + int lumiera_backend_init (void); diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index 849b2cd84..a0870e4eb 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -25,6 +25,7 @@ #include "backend/file.h" #include "backend/filedescriptor.h" +#include "backend/filedescriptorregistry.h" #include "backend/filehandle.h" #include "backend/filehandlecache.h" @@ -37,94 +38,19 @@ //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 PSplay registry = NULL; -static lumiera_mutex registry_mutex; - - -static int -cmp_fn (const void* keya, const void* keyb) -{ - const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya; - const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb; - - if (a->stat.st_dev < b->stat.st_dev) - return -1; - else if (a->stat.st_dev > b->stat.st_dev) - return 1; - - if (a->stat.st_ino < b->stat.st_ino) - return -1; - else if (a->stat.st_ino > b->stat.st_ino) - return 1; - - if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK)) - return -1; - else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK)) - return 1; - - return 0; -} - - -static void -delete_fn (PSplaynode node) -{ - TODO ("figure name out? or is the handle here always closed"); - lumiera_filedescriptor_delete ((LumieraFiledescriptor) node, NULL); -} - - -static const void* -key_fn (const PSplaynode node) -{ - return node; -} - - - -void -lumiera_filedescriptor_registry_init (void) -{ - //NOBUG_INIT_FLAG (filedescriptor); - TRACE (filedescriptor_dbg); - REQUIRE (!registry); - - registry = psplay_new (cmp_fn, key_fn, delete_fn); - if (!registry) - LUMIERA_DIE (NO_MEMORY); - - lumiera_mutex_init (®istry_mutex, "filedescriptor_registry", &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); -} - -void -lumiera_filedescriptor_registry_destroy (void) -{ - TRACE (filedescriptor_dbg); - REQUIRE (!psplay_nelements (registry)); - - lumiera_mutex_destroy (®istry_mutex, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); - - if (registry) - psplay_destroy (registry); - registry = NULL; -} +/* lookup and creation of files, initialized in backend.c */ +lumiera_mutex lumiera_filecreate_mutex; LumieraFiledescriptor lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode) { TRACE (filedescriptor_dbg, "%s", name); - REQUIRE (registry, "not initialized"); REQUIRE (llist_is_empty (filenode)); LumieraFiledescriptor dest = NULL; - LUMIERA_MUTEX_SECTION (mutex_sync, ®istry_mutex) + LUMIERA_MUTEX_SECTION (mutex_sync, &lumiera_filecreate_mutex) { lumiera_filedescriptor fdesc; fdesc.flags = flags; @@ -167,25 +93,21 @@ lumiera_filedescriptor_acquire (const char* name, int flags, LList filenode) } /* lookup/create descriptor */ - dest = (LumieraFiledescriptor) psplay_find (registry, &fdesc, 100); + dest = lumiera_filedescriptorregistry_ensure (&fdesc); - if (!dest) - { - dest = lumiera_filedescriptor_new (&fdesc); - if (!dest) - goto error; + if (dest) + llist_insert_head (&dest->files, filenode); - psplay_insert (registry, &dest->node, 100); - } - - llist_insert_head (&dest->files, filenode); - error: ; + error: + ; } return dest; } + + void lumiera_filedescriptor_release (LumieraFiledescriptor self, const char* name, LList filenode) { @@ -288,29 +210,25 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self, const char* name) { TRACE (filedescriptor_dbg, "%p %s", self, name); - LUMIERA_MUTEX_SECTION (mutex_sync, ®istry_mutex) + REQUIRE (llist_is_empty (&self->files)); + + lumiera_filedescriptorregistry_remove (self); + + TODO ("destruct other members (WIP)"); + + lumiera_mmapings_delete (self->mmapings); + + if (self->handle && name && ((self->flags & O_RDWR) == O_RDWR)) { - REQUIRE (llist_is_empty (&self->files)); - - psplay_remove (registry, &self->node); - - TODO ("destruct other members (WIP)"); - - if (self->handle && name && ((self->flags & O_RDWR) == O_RDWR)) - { - TRACE (filedescriptor_dbg, "truncate %s to %lld", name, (long long)self->realsize); - lumiera_filehandlecache_checkout (self->handle); - int dummy = ftruncate (lumiera_filehandle_handle (self->handle), self->realsize); - (void) dummy; /* this is present to silence a warning */ - TODO ("handle error case better"); - lumiera_filehandlecache_checkin (self->handle); - } - - lumiera_mmapings_delete (self->mmapings); - - TODO ("release filehandle"); - - lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); - lumiera_free (self); + TRACE (filedescriptor_dbg, "truncate %s to %lld", name, (long long)self->realsize); + lumiera_filehandlecache_checkout (self->handle); + int dummy = ftruncate (lumiera_filehandle_handle (self->handle), self->realsize); + (void) dummy; /* this is present to silence a warning */ + TODO ("handle error case better"); + lumiera_filehandlecache_checkin (self->handle); + TODO ("really release filehandle"); } + + lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); + lumiera_free (self); } diff --git a/src/backend/filedescriptor.h b/src/backend/filedescriptor.h index a74e8c47d..b06839c1b 100644 --- a/src/backend/filedescriptor.h +++ b/src/backend/filedescriptor.h @@ -75,22 +75,6 @@ struct lumiera_filedescriptor_struct llist files; }; -/** - * 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 diff --git a/src/backend/filedescriptorregistry.c b/src/backend/filedescriptorregistry.c new file mode 100644 index 000000000..557be2da1 --- /dev/null +++ b/src/backend/filedescriptorregistry.c @@ -0,0 +1,150 @@ +/* + filedescriptorregistry.c - register all files in use + + Copyright (C) Lumiera.org + 2008, 2010, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "include/logging.h" +#include "lib/safeclib.h" +#include "lib/mutex.h" +#include "lib/psplay.h" + +#include "backend/file.h" +#include "backend/filedescriptor.h" +#include "backend/filedescriptorregistry.h" + +//NOBUG_DEFINE_FLAG_PARENT (filedescriptorregistry, file_all); + +/* + Filedescriptor registry + + This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore. + */ +static PSplay filedescriptorregistry = NULL; +static lumiera_mutex filedescriptorregistry_mutex; + + +static int +cmp_fn (const void* keya, const void* keyb) +{ + const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya; + const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb; + + if (a->stat.st_dev < b->stat.st_dev) + return -1; + else if (a->stat.st_dev > b->stat.st_dev) + return 1; + + if (a->stat.st_ino < b->stat.st_ino) + return -1; + else if (a->stat.st_ino > b->stat.st_ino) + return 1; + + if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK)) + return -1; + else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK)) + return 1; + + return 0; +} + + +static void +delete_fn (PSplaynode node) +{ + TODO ("figure name out? or is the handle here always closed"); + lumiera_filedescriptor_delete ((LumieraFiledescriptor) node, NULL); +} + + +static const void* +key_fn (const PSplaynode node) +{ + return node; +} + + + +void +lumiera_filedescriptorregistry_init (void) +{ + TRACE (filedescriptor_dbg); + REQUIRE (!filedescriptorregistry); + + filedescriptorregistry = psplay_new (cmp_fn, key_fn, delete_fn); + if (!filedescriptorregistry) + LUMIERA_DIE (NO_MEMORY); + + lumiera_mutex_init (&filedescriptorregistry_mutex, "filedescriptorregistry", &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); +} + +void +lumiera_filedescriptorregistry_destroy (void) +{ + TRACE (filedescriptor_dbg); + REQUIRE (!psplay_nelements (filedescriptorregistry)); + + lumiera_mutex_destroy (&filedescriptorregistry_mutex, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); + + if (filedescriptorregistry) + psplay_destroy (filedescriptorregistry); + + filedescriptorregistry = NULL; +} + + +LumieraFiledescriptor +lumiera_filedescriptorregistry_ensure (LumieraFiledescriptor template) +{ + REQUIRE (filedescriptorregistry, "not initialized"); + + LumieraFiledescriptor ret = NULL; + + LUMIERA_MUTEX_SECTION (mutex_sync, &filedescriptorregistry_mutex) + { + /* lookup/create descriptor */ + ret = (LumieraFiledescriptor) psplay_find (filedescriptorregistry, template, 100); + + if (!ret) + { + ret = lumiera_filedescriptor_new (template); + if (!ret) + goto error; + + psplay_insert (filedescriptorregistry, &ret->node, 100); + } + + error: + ; + } + + return ret; +} + + +/** + * Removes a Filedescriptor from the registry. + */ +void +lumiera_filedescriptorregistry_remove (LumieraFiledescriptor self) +{ + LUMIERA_MUTEX_SECTION (mutex_sync, &filedescriptorregistry_mutex) + psplay_remove (filedescriptorregistry, &self->node); +} + + diff --git a/src/backend/filedescriptorregistry.h b/src/backend/filedescriptorregistry.h new file mode 100644 index 000000000..c3a03da83 --- /dev/null +++ b/src/backend/filedescriptorregistry.h @@ -0,0 +1,58 @@ +/* + filedescriptorregistry.h - register all files in use + + Copyright (C) Lumiera.org + 2008, 2010, 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_FILEDESCRIPTORREGISTRY_H +#define LUMIERA_FILEDESCRIPTORREGISTRY_H + +#include "backend/filedescriptor.h" + + +/** + * Initialize the global filedescriptor registry. + * Opening hardlinked files will be targeted to the same filedescriptor. + * This function never fails but dies on error. TODO backend/subsystem failure + */ +void +lumiera_filedescriptorregistry_init (void); + +/** + * Destroy and free the global filedescriptor registry. + * Never fails. + */ +void +lumiera_filedescriptorregistry_destroy (void); + +/** + * Ensures that a filedescriptor is in the registry. + * Looks template up and if not found, create a new one from template. + * @return filedescriptor from registry + */ +LumieraFiledescriptor +lumiera_filedescriptorregistry_ensure (LumieraFiledescriptor template); + +/** + * Removes a Filedescriptor from the registry. + */ +void +lumiera_filedescriptorregistry_remove (LumieraFiledescriptor self); + + +#endif