improve the mmap handling
* add frontend interfaces to file to get a mmaping * SECTION macro to encapsulate mmap access * mmap_address() translating an actual offset to address * add some tests * some test cosmetics
This commit is contained in:
parent
f887ee81ff
commit
e0939e9469
6 changed files with 215 additions and 62 deletions
|
|
@ -154,3 +154,27 @@ lumiera_file_mmapings (LumieraFile self)
|
|||
|
||||
return self->descriptor->mmapings;
|
||||
}
|
||||
|
||||
|
||||
LumieraMMap
|
||||
lumiera_file_mmap_acquire (LumieraFile self, LList acquirer, off_t start, size_t size)
|
||||
{
|
||||
TRACE (file_dbg);
|
||||
return lumiera_mmapings_mmap_acquire (lumiera_file_mmapings (self), self, acquirer, start, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_file_release_mmap (LumieraFile self, LList acquirer, LumieraMMap map)
|
||||
{
|
||||
TRACE (file_dbg);
|
||||
lumiera_mmapings_release_mmap (lumiera_file_mmapings (self), acquirer, map);
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ typedef lumiera_file* LumieraFile;
|
|||
#include "backend/filedescriptor.h"
|
||||
#include "backend/filehandle.h"
|
||||
#include "backend/mmapings.h"
|
||||
#include "backend/mmap.h"
|
||||
|
||||
/**
|
||||
* File modes:
|
||||
|
|
@ -146,6 +147,50 @@ void
|
|||
lumiera_file_handle_release (LumieraFile self);
|
||||
|
||||
|
||||
/**
|
||||
* acquire a mmap which covers the given range
|
||||
* @param self file from where the mmap shall be acquired
|
||||
* @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
|
||||
* note: the chunksize for the file must be set prior accessing mmaps
|
||||
*/
|
||||
LumieraMMap
|
||||
lumiera_file_mmap_acquire (LumieraFile self, LList acquirer, off_t start, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* release a previously acquired MMap object
|
||||
* @param self file to which the map belongs
|
||||
* @param acquirer holding node, used on require
|
||||
* @param map object to be released
|
||||
*/
|
||||
void
|
||||
lumiera_file_release_mmap (LumieraFile self, LList acquirer, LumieraMMap map);
|
||||
|
||||
|
||||
/**
|
||||
* helper macro for acquireing and releasing maped regions
|
||||
* @param file the file from from where to acquire the mapped region
|
||||
* @param start the start offset for the mmaped region
|
||||
* @param size the length of the requested block
|
||||
* @param addr name of a void* variable pointing to the requested memory
|
||||
*/
|
||||
#define LUMIERA_FILE_MMAP_SECTION(file, start, size, addr) \
|
||||
for (LLIST_AUTO(user_##__LINE__); user_##__LINE__.next; user_##__LINE__.next = NULL) \
|
||||
for (LumieraMMap map_##__LINE__ = \
|
||||
lumiera_file_mmap_acquire (file, &user_##__LINE__, start, size); \
|
||||
map_##__LINE__; \
|
||||
({ \
|
||||
lumiera_file_release_mmap (file, &user_##__LINE__, map_##__LINE__); \
|
||||
map_##__LINE__ = NULL; \
|
||||
})) \
|
||||
for (void* addr = lumiera_mmap_address (map_##__LINE__, start); \
|
||||
addr; \
|
||||
addr = NULL)
|
||||
|
||||
|
||||
/**
|
||||
* Query the underlying mmapings object from a file
|
||||
* The MMapings only exists after a chunksize got set with lumiera_file_chunksize_set()
|
||||
|
|
@ -175,3 +220,10 @@ lumiera_file_chunksize_get (LumieraFile self);
|
|||
|
||||
#endif
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -78,13 +78,20 @@ LumieraMMap
|
|||
lumiera_mmap_new (LumieraFile file, off_t start, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Translate a 'external' offset to a address in memory
|
||||
* @param self MMap object to query
|
||||
* @param offset position on the mmaped file to get
|
||||
* @return address in memory which relates to offset
|
||||
*/
|
||||
static inline void*
|
||||
lumiera_mmap_address (LumieraMMap self)
|
||||
lumiera_mmap_address (LumieraMMap self, off_t offset)
|
||||
{
|
||||
return self->address;
|
||||
REQUIRE (offset >= self->start, "offset before mmaped region");
|
||||
REQUIRE (offset < self->start + (off_t)self->size, "offset after mmaped region");
|
||||
return self?(self->address + (offset - self->start)):NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_mmap_delete (LumieraMMap self);
|
||||
|
||||
|
|
|
|||
|
|
@ -93,66 +93,66 @@ lumiera_mmapings_mmap_acquire (LumieraMMapings self, LumieraFile file, LList acq
|
|||
|
||||
LumieraMMap ret = NULL;
|
||||
|
||||
LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock)
|
||||
{
|
||||
REQUIRE (llist_is_empty (acquirer));
|
||||
if (self)
|
||||
LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock)
|
||||
{
|
||||
REQUIRE (llist_is_empty (acquirer));
|
||||
|
||||
/* find first matching mmap, crude way */
|
||||
LLIST_FOREACH (&self->mmaps, node)
|
||||
{
|
||||
TODO ("improve this selection algorithm, choose mmaps by size, move mfu to head etc");
|
||||
/* find first matching mmap, crude way */
|
||||
LLIST_FOREACH (&self->mmaps, node)
|
||||
{
|
||||
TODO ("improve this selection algorithm, choose mmaps by size, move mfu to head etc");
|
||||
|
||||
LumieraMMap mmap = LLIST_TO_STRUCTP (node, lumiera_mmap, searchnode);
|
||||
LumieraMMap mmap = LLIST_TO_STRUCTP (node, lumiera_mmap, searchnode);
|
||||
|
||||
if (mmap->size >= size && mmap->start <= start && mmap->start+mmap->size >= start+size)
|
||||
{
|
||||
ret = mmap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mmap->size >= size && mmap->start <= start && mmap->start+mmap->size >= start+size)
|
||||
{
|
||||
ret = mmap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* found? */
|
||||
if (ret)
|
||||
{
|
||||
if (!ret->refcnt)
|
||||
/* in cache, needs to me checked out */
|
||||
lumiera_mmapcache_checkout (lumiera_mcache, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create new mmap */
|
||||
TRACE (mmapings_dbg, "mmap not found, creating");
|
||||
ret = lumiera_mmap_new (file, start, size);
|
||||
/* found? */
|
||||
if (ret)
|
||||
{
|
||||
if (!ret->refcnt)
|
||||
/* in cache, needs to me checked out */
|
||||
lumiera_mmapcache_checkout (lumiera_mcache, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create new mmap */
|
||||
TRACE (mmapings_dbg, "mmap not found, creating");
|
||||
ret = lumiera_mmap_new (file, start, size);
|
||||
|
||||
llist_insert_head (&self->mmaps, &ret->searchnode);
|
||||
llist_insert_head (&self->mmaps, &ret->searchnode);
|
||||
|
||||
TODO ("sort search list?");
|
||||
}
|
||||
TODO ("sort search list?");
|
||||
}
|
||||
|
||||
llist_insert_head (&ret->cachenode, acquirer);
|
||||
}
|
||||
llist_insert_head (&ret->cachenode, acquirer);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_mmapings_release_mmap (LumieraMMapings self, LList acquirer, LumieraMMap map)
|
||||
{
|
||||
TRACE (mmapings_dbg);
|
||||
|
||||
LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock)
|
||||
{
|
||||
llist_unlink (acquirer);
|
||||
if (llist_is_empty (&map->cachenode))
|
||||
{
|
||||
TRACE (mmapcache_dbg, "checkin");
|
||||
lumiera_mmapcache_checkin (lumiera_mcache, map);
|
||||
}
|
||||
}
|
||||
if (self)
|
||||
LUMIERA_MUTEX_SECTION (mutex_sync, &self->lock)
|
||||
{
|
||||
llist_unlink (acquirer);
|
||||
if (llist_is_empty (&map->cachenode))
|
||||
{
|
||||
TRACE (mmapcache_dbg, "checkin");
|
||||
lumiera_mmapcache_checkin (lumiera_mcache, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
|
|
|
|||
|
|
@ -36,4 +36,16 @@ TEST "readonly file" mmap_readonly_file <<END
|
|||
return: 0
|
||||
END
|
||||
|
||||
TEST "accessing file" file_access <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
TEST "mmaped secion" mmap_section <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
TEST "mmaped secion, error" mmap_section_err <<END
|
||||
return: !0
|
||||
END
|
||||
|
||||
rm ,tmp-filemmap 2>/dev/null
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "tests/test.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
|
@ -133,9 +134,9 @@ TEST ("mmap_forget_releasing")
|
|||
llist user;
|
||||
llist_init (&user);
|
||||
|
||||
LumieraMMap mmap = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
LumieraMMap map = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
|
||||
(void) mmap; //lumiera_mmapings_release_mmap (mmaps, &user, mmap);
|
||||
(void) map; //lumiera_mmapings_release_mmap (mmaps, &user, mmap);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
|
||||
|
|
@ -154,9 +155,9 @@ TEST ("mmap_simple")
|
|||
|
||||
llist user;
|
||||
llist_init (&user);
|
||||
LumieraMMap mmap = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
LumieraMMap map = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, mmap);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, map);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
|
||||
|
|
@ -181,17 +182,17 @@ TEST ("mmap_checkout_twice")
|
|||
|
||||
llist user;
|
||||
llist_init (&user);
|
||||
LumieraMMap mmap = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
LumieraMMap map = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
|
||||
llist user2;
|
||||
llist_init (&user2);
|
||||
LumieraMMap mmap2 = lumiera_mmapings_mmap_acquire (mmaps, file, &user2, 0, 100);
|
||||
LumieraMMap map2 = lumiera_mmapings_mmap_acquire (mmaps, file, &user2, 0, 100);
|
||||
|
||||
ENSURE (lumiera_mmap_address (mmap) == lumiera_mmap_address (mmap2));
|
||||
ENSURE (map->address == map2->address);
|
||||
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, mmap);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, map);
|
||||
|
||||
lumiera_mmapings_release_mmap (mmaps, &user2, mmap2);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user2, map2);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
|
||||
|
|
@ -216,13 +217,13 @@ TEST ("mmap_checkout_again")
|
|||
|
||||
llist user;
|
||||
llist_init (&user);
|
||||
LumieraMMap mmap = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, mmap);
|
||||
LumieraMMap map = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, map);
|
||||
|
||||
llist user2;
|
||||
llist_init (&user2);
|
||||
LumieraMMap mmap2 = lumiera_mmapings_mmap_acquire (mmaps, file, &user2, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user2, mmap2);
|
||||
LumieraMMap map2 = lumiera_mmapings_mmap_acquire (mmaps, file, &user2, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user2, map2);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
|
||||
|
|
@ -249,8 +250,8 @@ TEST ("mmap_grow_existing_file")
|
|||
llist user;
|
||||
llist_init (&user);
|
||||
|
||||
LumieraMMap mmap = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, mmap);
|
||||
LumieraMMap map = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, map);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
|
||||
|
|
@ -276,8 +277,8 @@ TEST ("mmap_readonly_file")
|
|||
llist user;
|
||||
llist_init (&user);
|
||||
|
||||
LumieraMMap mmap = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, mmap);
|
||||
LumieraMMap map = lumiera_mmapings_mmap_acquire (mmaps, file, &user, 0, 100);
|
||||
lumiera_mmapings_release_mmap (mmaps, &user, map);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
|
||||
|
|
@ -292,6 +293,63 @@ TEST ("mmap_readonly_file")
|
|||
|
||||
|
||||
|
||||
TEST ("file_access")
|
||||
{
|
||||
lumiera_backend_init ();
|
||||
LumieraFile file = lumiera_file_new (",tmp-filemmap", LUMIERA_FILE_RECREATE);
|
||||
lumiera_file_chunksize_set (file, 4096);
|
||||
|
||||
llist user;
|
||||
llist_init (&user);
|
||||
|
||||
LumieraMMap map = lumiera_file_mmap_acquire (file, &user, 10, 100);
|
||||
|
||||
char* addr = lumiera_mmap_address (map, 20);
|
||||
|
||||
strcpy (addr, "test");
|
||||
|
||||
lumiera_file_release_mmap (file, &user, map);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
lumiera_backend_destroy ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("mmap_section")
|
||||
{
|
||||
lumiera_backend_init ();
|
||||
LumieraFile file = lumiera_file_new (",tmp-filemmap", LUMIERA_FILE_RECREATE);
|
||||
lumiera_file_chunksize_set (file, 4096);
|
||||
|
||||
LUMIERA_FILE_MMAP_SECTION(file, 20, 20, addr)
|
||||
{
|
||||
strcpy (addr, "mmap section");
|
||||
}
|
||||
|
||||
CHECK(lumiera_error_peek() == NULL);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
lumiera_backend_destroy ();
|
||||
}
|
||||
|
||||
|
||||
TEST ("mmap_section_err")
|
||||
{
|
||||
lumiera_backend_init ();
|
||||
LumieraFile file = lumiera_file_new (",tmp-filemmap", LUMIERA_FILE_RECREATE);
|
||||
/* forgot to set lumiera_file_chunksize_set (file, 4096); */
|
||||
|
||||
LUMIERA_FILE_MMAP_SECTION(file, 20, 20, addr)
|
||||
{
|
||||
strcpy (addr, "mmap section");
|
||||
}
|
||||
|
||||
CHECK(lumiera_error_peek() == NULL);
|
||||
|
||||
lumiera_file_delete (file);
|
||||
lumiera_backend_destroy ();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
|
|
|||
Loading…
Reference in a new issue