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:
Christian Thaeter 2010-02-11 18:07:17 +01:00
parent f887ee81ff
commit e0939e9469
6 changed files with 215 additions and 62 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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