diff --git a/src/backend/file.c b/src/backend/file.c index 185d11b78..4c42b9fa1 100644 --- a/src/backend/file.c +++ b/src/backend/file.c @@ -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: +*/ diff --git a/src/backend/file.h b/src/backend/file.h index 91796998b..8152523ca 100644 --- a/src/backend/file.h +++ b/src/backend/file.h @@ -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: +*/ diff --git a/src/backend/mmap.h b/src/backend/mmap.h index 2bd9db7c2..7c5712338 100644 --- a/src/backend/mmap.h +++ b/src/backend/mmap.h @@ -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); diff --git a/src/backend/mmapings.c b/src/backend/mmapings.c index f3fa4edb7..cdf84ec63 100644 --- a/src/backend/mmapings.c +++ b/src/backend/mmapings.c @@ -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 diff --git a/tests/30mmap.tests b/tests/30mmap.tests index 8bb70dd15..015691f8e 100644 --- a/tests/30mmap.tests +++ b/tests/30mmap.tests @@ -36,4 +36,16 @@ TEST "readonly file" mmap_readonly_file </dev/null diff --git a/tests/backend/test-filemmap.c b/tests/backend/test-filemmap.c index 7cae6f362..771094d47 100644 --- a/tests/backend/test-filemmap.c +++ b/tests/backend/test-filemmap.c @@ -34,6 +34,7 @@ #include "tests/test.h" #include +#include #include #include @@ -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