From da23204bf307ff8fcb6cab91b8d12f2f033d9341 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Sun, 7 Mar 2010 13:52:57 +0100 Subject: [PATCH] Exclusive file locking This adds global exclusive advisory file locks on a per-thread basis. Only exclusive locking for a whole file is supported to setup headers etc. Finer grained locking will be handled somewhere else. --- src/backend/file.c | 34 +++++++ src/backend/file.h | 43 +++++++++ src/backend/filedescriptor.c | 153 +++++++++++++++++++++++++++++++ src/backend/filedescriptor.h | 30 ++++++ src/backend/filehandle.c | 7 -- src/backend/filehandle.h | 11 +++ tests/20filehandle.tests | 5 + tests/backend/test-filehandles.c | 28 ++++++ 8 files changed, 304 insertions(+), 7 deletions(-) diff --git a/src/backend/file.c b/src/backend/file.c index a2db9723f..3303cae5d 100644 --- a/src/backend/file.c +++ b/src/backend/file.c @@ -191,6 +191,40 @@ lumiera_file_release_mmap (LumieraFile self, LumieraMMap map) lumiera_mmapings_release_mmap (lumiera_file_mmapings (self), map); } + + +LumieraFile +lumiera_file_rdlock (LumieraFile self) +{ + if (self && !lumiera_filedescriptor_rdlock (self->descriptor)) + return NULL; + + return self; +} + + +LumieraFile +lumiera_file_wrlock (LumieraFile self) +{ + if (self && !lumiera_filedescriptor_wrlock (self->descriptor)) + return NULL; + + return self; +} + + +LumieraFile +lumiera_file_unlock (LumieraFile self) +{ + if (self && !lumiera_filedescriptor_unlock (self->descriptor)) + return NULL; + + return self; +} + + + + /* // Local Variables: // mode: C diff --git a/src/backend/file.h b/src/backend/file.h index 1833f0f54..d70525004 100644 --- a/src/backend/file.h +++ b/src/backend/file.h @@ -234,6 +234,49 @@ size_t lumiera_file_bias_get (LumieraFile self); + + +/** + * Place and remove locks on a file + * This locks are per thread and lock the file across multiple lumiera processes + * (or any other programm which repects advisory file locking). + * Only exclusive locks over the whole file are supported for initially accessing + * a file, other locking is done somewhere else. + */ + +LumieraFile +lumiera_file_rdlock (LumieraFile self); + +LumieraFile +lumiera_file_wrlock (LumieraFile self); + + +LumieraFile +lumiera_file_unlock (LumieraFile self); + + +#define LUMIERA_FILE_RDLOCK_SECTION(nobugflag, file) \ + for (LumieraFile filelock_##__LINE__ = \ + lumiera_file_rdlock (file); \ + filelock_##__LINE__; \ + ({ \ + lumiera_file_unlock (filelock_##__LINE__); \ + filelock_##__LINE__ = NULL; \ + })) + +#define LUMIERA_FILE_WRLOCK_SECTION(nobugflag, file) \ + for (LumieraFile filelock_##__LINE__ = \ + lumiera_file_wrlock (file); \ + filelock_##__LINE__; \ + ({ \ + lumiera_file_unlock (filelock_##__LINE__); \ + filelock_##__LINE__ = NULL; \ + })) + + + + + #endif /* diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c index 621b7d74f..49eec291f 100644 --- a/src/backend/filedescriptor.c +++ b/src/backend/filedescriptor.c @@ -200,8 +200,13 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template) self->mmapings = NULL; llist_init (&self->files); + RESOURCE_USER_INIT(self->filelock_rh); + lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); + lumiera_rwlock_init (&self->filelock, "filelock", &NOBUG_FLAG (filedescriptor_dbg), NOBUG_CONTEXT); + self->lock_cnt = 0; + return self; } @@ -211,6 +216,7 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self, const char* name) { TRACE (filedescriptor_dbg, "%p %s", self, name); + REQUIRE (!self->lock_cnt, "File still locked"); REQUIRE (llist_is_empty (&self->files)); lumiera_filedescriptorregistry_remove (self); @@ -230,6 +236,153 @@ lumiera_filedescriptor_delete (LumieraFiledescriptor self, const char* name) TODO ("really release filehandle"); } + lumiera_rwlock_destroy (&self->filelock, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (mutex_dbg), NOBUG_CONTEXT); + lumiera_free (self); } + + +LumieraFiledescriptor +lumiera_filedescriptor_rdlock (LumieraFiledescriptor self) +{ + TRACE (filedescriptor_dbg); + + if (self) + { + lumiera_rwlock_rdlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT); + + int fd = lumiera_filedescriptor_handle_acquire (self); + int err = 0; + + LUMIERA_MUTEX_SECTION (mutex_dbg, &self->lock) + { + if (!self->lock_cnt) + { + + struct flock lock; + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + while ((err = fcntl (fd, F_SETLKW, &lock)) == -1 && errno == EINTR) + ; + + } + if (!err) + ++self->lock_cnt; + } + + if (err) + { + lumiera_filedescriptor_handle_release (self); + lumiera_rwlock_unlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT); + + LUMIERA_ERROR_SET_WARNING (filedescriptor_dbg, ERRNO, lumiera_filedescriptor_name (self)); + self = NULL; + } + } + + return self; +} + + + +LumieraFiledescriptor +lumiera_filedescriptor_wrlock (LumieraFiledescriptor self) +{ + TRACE (filedescriptor_dbg); + + if (self) + { + lumiera_rwlock_wrlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT); + + int fd = lumiera_filedescriptor_handle_acquire (self); + int err = 0; + + LUMIERA_MUTEX_SECTION(mutex_dbg, &self->lock) + { + + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + while ((err = fcntl (fd, F_SETLKW, &lock)) == -1 && errno == EINTR) + ; + + if (!err) + self->lock_cnt = -1; + + } + + if (err) + { + lumiera_filedescriptor_handle_release (self); + lumiera_rwlock_unlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT); + LUMIERA_ERROR_SET_WARNING (filedescriptor_dbg, ERRNO, lumiera_filedescriptor_name (self)); + self = NULL; + } + } + + return self; +} + + +LumieraFiledescriptor +lumiera_filedescriptor_unlock (LumieraFiledescriptor self) +{ + TRACE (filedescriptor_dbg); + + if (self) + { + int fd = lumiera_filehandle_get (self->handle); + REQUIRE (fd >= 0, "was not locked?"); + int err = 0; + + LUMIERA_MUTEX_SECTION(mutex_dbg, &self->lock) + { + if (self->lock_cnt == -1) + self->lock_cnt = 0; + else + --self->lock_cnt; + + if (!self->lock_cnt) + { + + struct flock lock; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + while ((err = fcntl (fd, F_SETLK, &lock)) == -1 && errno == EINTR) + ; + } + } + + if (err) + { + LUMIERA_ERROR_SET_WARNING (filedescriptor_dbg, ERRNO, lumiera_filedescriptor_name (self)); + self = NULL; + } + else + { + lumiera_filedescriptor_handle_release (self); + lumiera_rwlock_unlock (&self->filelock, &NOBUG_FLAG (filedescriptor_dbg), &self->filelock_rh, NOBUG_CONTEXT); + } + } + + return self; +} + + +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/filedescriptor.h b/src/backend/filedescriptor.h index b06839c1b..89306cab8 100644 --- a/src/backend/filedescriptor.h +++ b/src/backend/filedescriptor.h @@ -23,6 +23,7 @@ #define LUMIERA_FILEDESCRIPTOR_H #include "lib/mutex.h" +#include "lib/rwlock.h" #include "lib/psplay.h" #include "lib/llist.h" @@ -73,6 +74,12 @@ struct lumiera_filedescriptor_struct /** list of all attached 'file' structures, that are the names of the files */ llist files; + + /** file locking, a rwlock for thread locking */ + lumiera_rwlock filelock; + /** readlock counter for releasing the file lock, -1 for write lock, 0 = unlocked */ + int lock_cnt; + RESOURCE_USER (filelock_rh); }; @@ -125,4 +132,27 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template); void lumiera_filedescriptor_delete (LumieraFiledescriptor self, const char* name); + + +LumieraFiledescriptor +lumiera_filedescriptor_rdlock (LumieraFiledescriptor self); + + +LumieraFiledescriptor +lumiera_filedescriptor_wrlock (LumieraFiledescriptor self); + + +LumieraFiledescriptor +lumiera_filedescriptor_unlock (LumieraFiledescriptor self); + + + + #endif +/* +// Local Variables: +// mode: C +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +*/ diff --git a/src/backend/filehandle.c b/src/backend/filehandle.c index c988ca0b9..37944ba26 100644 --- a/src/backend/filehandle.c +++ b/src/backend/filehandle.c @@ -66,13 +66,6 @@ lumiera_filehandle_destroy_node (LList node) } -int -lumiera_filehandle_get (LumieraFilehandle self) -{ - REQUIRE (self->descriptor); - return -1; -} - int lumiera_filehandle_handle (LumieraFilehandle self) diff --git a/src/backend/filehandle.h b/src/backend/filehandle.h index 21d1f11ad..6ad9c5832 100644 --- a/src/backend/filehandle.h +++ b/src/backend/filehandle.h @@ -83,4 +83,15 @@ lumiera_filehandle_destroy_node (LList node); int lumiera_filehandle_handle (LumieraFilehandle self); + +/** + * just accessor, no saftey net + */ +static inline int +lumiera_filehandle_get (LumieraFilehandle self) +{ + REQUIRE (self->descriptor); + return self->fd; +} + #endif diff --git a/tests/20filehandle.tests b/tests/20filehandle.tests index 0365bbffc..c93ff2e35 100644 --- a/tests/20filehandle.tests +++ b/tests/20filehandle.tests @@ -11,3 +11,8 @@ rm -rf ,tmpdir TEST "using many filehandles" more <