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:
parent
2dfef6cac4
commit
da23204bf3
8 changed files with 304 additions and 7 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue