From 4dd259f3b159af87e6f569082ffb5353a3886b2f Mon Sep 17 00:00:00 2001 From: Cedric Bail Date: Wed, 31 Jul 2013 17:16:20 +0900 Subject: [PATCH] eina: add eina_file_refresh(). --- ChangeLog | 2 +- NEWS | 1 + src/lib/eina/eina_file.c | 109 +++++++++++++++++++++++++------- src/lib/eina/eina_file.h | 13 ++++ src/lib/eina/eina_file_common.c | 90 ++++++++++++++++++++++++++ src/lib/eina/eina_file_common.h | 7 ++ src/lib/eina/eina_file_win32.c | 55 +++++++++++----- 7 files changed, 237 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 637fa0d3e1..2762dad52b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,7 @@ 2013-07-31 Cedric Bail - * Eina: add eina_file_virtualize() and eina_file_virtual(). + * Eina: add eina_file_refresh(), eina_file_virtualize() and eina_file_virtual(). * Evas: use eina_file_virtualize() for evas_object_image_memfile_set(). 2013-07-25 ChunEon Park (Hermet) diff --git a/NEWS b/NEWS index c0834591f0..39b5d5946e 100644 --- a/NEWS +++ b/NEWS @@ -35,6 +35,7 @@ Additions: - Add eina_file_map_populate() - Add eina_tiler_empty() - Add eina_file_virtualize() and eina_file_virtual() + - Add eina_file_refresh() * Eet: - Add eet_mmap() - Add eet_data_descriptor_name_get() diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c index 32ae4ea2fa..ceb3e1cc0c 100644 --- a/src/lib/eina/eina_file.c +++ b/src/lib/eina/eina_file.c @@ -304,11 +304,19 @@ _eina_file_stat_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data) void eina_file_real_close(Eina_File *file) { + Eina_File_Map *map; + if (file->refcount != 0) return; eina_hash_free(file->rmap); eina_hash_free(file->map); + EINA_LIST_FREE(file->dead_map, map) + { + munmap(map->map, map->length); + free(map); + } + if (file->global_map != MAP_FAILED) munmap(file->global_map, file->length); @@ -462,6 +470,19 @@ eina_file_shutdown(void) return EINA_TRUE; } +static Eina_Bool +_eina_file_mmap_faulty_one(void *addr, long page_size, + Eina_File_Map *m) +{ + if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) && + (((unsigned char *) addr) + page_size) >= (unsigned char *) m->map) + { + m->faulty = EINA_TRUE; + return EINA_TRUE; + } + return EINA_FALSE; +} + void eina_file_mmap_faulty(void *addr, long page_size) { @@ -497,17 +518,23 @@ eina_file_mmap_faulty(void *addr, long page_size) itm = eina_hash_iterator_data_new(f->map); EINA_ITERATOR_FOREACH(itm, m) { - if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) && - (((unsigned char *) addr) + page_size) >= (unsigned char *) m->map) - { - m->faulty = EINA_TRUE; - faulty = EINA_TRUE; - break; - } + faulty = _eina_file_mmap_faulty_one(addr, page_size, m); + if (faulty) break; } eina_iterator_free(itm); } + if (!faulty) + { + Eina_List *l; + + EINA_LIST_FOREACH(f->dead_map, l, m) + { + faulty = _eina_file_mmap_faulty_one(addr, page_size, m); + if (faulty) break; + } + } + eina_lock_release(&f->lock); if (faulty) break; @@ -902,6 +929,39 @@ eina_file_open(const char *path, Eina_Bool shared) return NULL; } +EAPI Eina_Bool +eina_file_refresh(Eina_File *file) +{ + struct stat file_stat; + Eina_Bool r = EINA_FALSE; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE); + + if (file->virtual) return EINA_FALSE; + + if (fstat(file->fd, &file_stat)) + return EINA_FALSE; + + if (file->length != (unsigned long int) file_stat.st_size) + { + eina_file_flush(file, file_stat.st_size); + r = EINA_TRUE; + } + + file->length = file_stat.st_size; + file->mtime = file_stat.st_mtime; +#ifdef _STAT_VER_LINUX +# if (defined __USE_MISC && defined st_mtime) + file->mtime_nsec = (unsigned long int)file_stat.st_mtim.tv_nsec; +# else + file->mtime_nsec = (unsigned long int)file_stat.st_mtimensec; +# endif +#endif + file->inode = file_stat.st_ino; + + return r; +} + EAPI void * eina_file_map_all(Eina_File *file, Eina_File_Populate rule) { @@ -1048,21 +1108,7 @@ eina_file_map_free(Eina_File *file, void *map) } else { - Eina_File_Map *em; - unsigned long int key[2]; - - em = eina_hash_find(file->rmap, &map); - if (!em) goto on_exit; - - em->refcount--; - - if (em->refcount > 0) goto on_exit; - - key[0] = em->offset; - key[1] = em->length; - - eina_hash_del(file->rmap, &map, em); - eina_hash_del(file->map, &key, em); + eina_file_common_map_free(file, map, _eina_file_map_close); } on_exit: @@ -1086,7 +1132,6 @@ eina_file_map_populate(Eina_File *file, Eina_File_Populate rule, void *map, EAPI Eina_Bool eina_file_map_faulted(Eina_File *file, void *map) { - Eina_File_Map *em; Eina_Bool r = EINA_FALSE; EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE); @@ -1101,8 +1146,24 @@ eina_file_map_faulted(Eina_File *file, void *map) } else { + Eina_File_Map *em; + em = eina_hash_find(file->rmap, &map); - if (em) r = em->faulty; + if (em) + { + r = em->faulty; + } + else + { + Eina_List *l; + + EINA_LIST_FOREACH(file->dead_map, l, em) + if (em->map == map) + { + r = em->faulty; + break; + } + } } eina_lock_release(&file->lock); diff --git a/src/lib/eina/eina_file.h b/src/lib/eina/eina_file.h index 36aac586e4..0e43d2acb8 100644 --- a/src/lib/eina/eina_file.h +++ b/src/lib/eina/eina_file.h @@ -483,6 +483,19 @@ eina_file_virtualize(const void *data, unsigned long long length, Eina_Bool copy EAPI Eina_Bool eina_file_virtual(Eina_File *file) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1); +/** + * @brief Refresh file information + * + * @param file The file to refresh + * @return #EINA_TRUE if the file has changed + * + * All current map continue to exist. You need to manually delete + * and recreate them to have the new correct mapping. + * + * @since 1.8 + */ +EAPI Eina_Bool eina_file_refresh(Eina_File *file); + /** * @brief Dup a read-only handler of a previously open file. * diff --git a/src/lib/eina/eina_file_common.c b/src/lib/eina/eina_file_common.c index 75c92564dd..91eec161b7 100644 --- a/src/lib/eina/eina_file_common.c +++ b/src/lib/eina/eina_file_common.c @@ -232,6 +232,96 @@ eina_file_virtual_map_free(Eina_File *file, void *map) eina_lock_release(&file->lock); } +void +eina_file_common_map_free(Eina_File *file, void *map, + void (*free_func)(Eina_File_Map *map)) +{ + Eina_File_Map *em; + unsigned long int key[2]; + Eina_List *l = NULL; + Eina_Bool hashed = EINA_TRUE; + + em = eina_hash_find(file->rmap, &map); + if (!em) + { + EINA_LIST_FOREACH(file->dead_map, l, em) + if (em->map == map) + { + hashed = EINA_FALSE; + break ; + } + if (hashed) return ; + } + + em->refcount--; + + if (em->refcount > 0) return ; + + key[0] = em->offset; + key[1] = em->length; + + if (hashed) + { + eina_hash_del(file->rmap, &map, em); + eina_hash_del(file->map, &key, em); + } + else + { + file->dead_map = eina_list_remove_list(file->dead_map, l); + free_func(em); + } +} + +void +eina_file_flush(Eina_File *file, unsigned long int length) +{ + Eina_File_Map *tmp; + Eina_Iterator *it; + Eina_List *dead_map = NULL; + Eina_List *l; + + // File size changed + if (file->global_map) + { + // Forget global map + tmp = malloc(sizeof (Eina_File_Map)); + if (tmp) + { + tmp->map = file->global_map; + tmp->offset = 0; + tmp->length = file->length; + tmp->refcount = file->refcount; + + file->dead_map = eina_list_append(file->dead_map, tmp); + } + + file->global_map = NULL; + file->refcount = 0; + } + + it = eina_hash_iterator_data_new(file->map); + EINA_ITERATOR_FOREACH(it, tmp) + { + // Add out of limit map to dead_map + if (tmp->offset + tmp->length > length) + dead_map = eina_list_append(dead_map, tmp); + } + eina_iterator_free(it); + + EINA_LIST_FOREACH(dead_map, l, tmp) + { + unsigned long int key[2]; + + key[0] = tmp->offset; + key[1] = tmp->length; + + eina_hash_del(file->rmap, &tmp->map, tmp); + eina_hash_del(file->map, &key, tmp); + } + + file->dead_map = eina_list_merge(file->dead_map, dead_map); +} + // Private to this file API static void _eina_file_map_close(Eina_File_Map *map) diff --git a/src/lib/eina/eina_file_common.h b/src/lib/eina/eina_file_common.h index 31f6b6d306..06e9a93143 100644 --- a/src/lib/eina/eina_file_common.h +++ b/src/lib/eina/eina_file_common.h @@ -22,6 +22,7 @@ #include "eina_file.h" #include "eina_tmpstr.h" #include "eina_lock.h" +#include "eina_list.h" typedef struct _Eina_File_Map Eina_File_Map; typedef struct _Eina_Lines_Iterator Eina_Lines_Iterator; @@ -58,6 +59,8 @@ struct _Eina_File HANDLE fm; #endif + Eina_List *dead_map; + Eina_Bool shared : 1; Eina_Bool delete_me : 1; Eina_Bool global_faulty : 1; @@ -119,6 +122,10 @@ Eina_Bool eina_file_path_relative(const char *path); Eina_Tmpstr *eina_file_current_directory_get(const char *path, size_t len); char *eina_file_cleanup(Eina_Tmpstr *path); void eina_file_real_close(Eina_File *file); +void eina_file_flush(Eina_File *file, unsigned long int length); +void eina_file_common_map_free(Eina_File *file, void *map, + void (*free_func)(Eina_File_Map *map)); + extern Eina_Hash *_eina_file_cache; extern Eina_Lock _eina_file_lock_cache; diff --git a/src/lib/eina/eina_file_win32.c b/src/lib/eina/eina_file_win32.c index d96720bbd2..6b4e247531 100644 --- a/src/lib/eina/eina_file_win32.c +++ b/src/lib/eina/eina_file_win32.c @@ -364,9 +364,17 @@ _eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it) void eina_file_real_close(Eina_File *file) { + Eina_File_Map *map; + eina_hash_free(file->rmap); eina_hash_free(file->map); + EINA_LIST_FREE(file->dead_map, map) + { + UnmapViewOfFile(map->map); + free(map); + } + if (file->global_map != MAP_FAILED) UnmapViewOfFile(file->global_map); @@ -715,6 +723,37 @@ eina_file_stat_ls(const char *dir) return eina_file_direct_ls(dir); } +EAPI Eina_Bool +eina_file_refresh(Eina_File *file) +{ + WIN32_FILE_ATTRIBUTE_DATA fad; + ULARGE_INTEGER length; + ULARGE_INTEGER mtime; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE); + + if (file->virtual) return EINA_FALSE; + + if (!GetFileAttributesEx(file->filename, GetFileExInfoStandard, &fad)) + return EINA_FALSE; + + length.u.LowPart = fad.nFileSizeLow; + length.u.HighPart = fad.nFileSizeHigh; + mtime.u.LowPart = fad.ftLastWriteTime.dwLowDateTime; + mtime.u.HighPart = fad.ftLastWriteTime.dwHighDateTime; + + if (file->length != length.QuadPart) + { + eina_file_flush(file, file_stat.st_size); + r = EINA_TRUE; + } + + n->length = length.QuadPart; + n->mtime = mtime.QuadPart; + + return r; +} + EAPI Eina_File * eina_file_open(const char *path, Eina_Bool shared) { @@ -953,21 +992,7 @@ eina_file_map_free(Eina_File *file, void *map) } else { - Eina_File_Map *em; - unsigned long int key[2]; - - em = eina_hash_find(file->rmap, &map); - if (!em) goto on_exit; - - em->refcount--; - - if (em->refcount > 0) goto on_exit; - - key[0] = em->offset; - key[1] = em->length; - - eina_hash_del(file->rmap, &map, em); - eina_hash_del(file->map, &key, em); + eina_file_common_map_free(file, map, _eina_file_map_close); } on_exit: