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.
This commit is contained in:
Christian Thaeter 2010-03-07 13:52:57 +01:00
parent 2dfef6cac4
commit da23204bf3
8 changed files with 304 additions and 7 deletions

View file

@ -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

View file

@ -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
/*

View file

@ -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:
*/

View file

@ -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:
*/

View file

@ -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)

View file

@ -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

View file

@ -11,3 +11,8 @@ rm -rf ,tmpdir
TEST "using many filehandles" more <<END
return: 0
END
TEST "file locking" file_locking <<END
return: 0
END

View file

@ -87,4 +87,32 @@ TEST ("more")
lumiera_config_destroy ();
}
TEST (file_locking)
{
lumiera_backend_init ();
LumieraFile file = lumiera_file_new (",tmp_testfile", LUMIERA_FILE_RECREATE);
LumieraFile locked = lumiera_file_wrlock (file);
CHECK (locked);
CHECK (lumiera_file_unlock (locked));
lumiera_file_delete (file);
lumiera_backend_destroy ();
lumiera_config_destroy ();
}
PLANNED_TEST (file_locking_blocked)
{
}
TESTS_END