diff --git a/ChangeLog b/ChangeLog index 9c4c2b40f5..2e2d23460f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-07-31 Cedric Bail + + * Eina: add eina_file_virtualize() and eina_file_virtual(). + 2013-07-25 ChunEon Park (Hermet) * Evas: Skip the map rendering if all points are transparent. diff --git a/NEWS b/NEWS index 8df3505ecf..0bacd4e705 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,7 @@ Additions: - Add eina_tiler_area_size_set(), eina_tiler_strict_set(), eina_tiler_area_size_get() - Add eina_file_map_populate() - Add eina_tiler_empty() + - Add eina_file_virtualize() and eina_file_virtual() * 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 6cc1e3835d..32ae4ea2fa 100644 --- a/src/lib/eina/eina_file.c +++ b/src/lib/eina/eina_file.c @@ -324,27 +324,6 @@ _eina_file_map_close(Eina_File_Map *map) free(map); } -static unsigned int -_eina_file_map_key_length(const void *key EINA_UNUSED) -{ - return sizeof (unsigned long int) * 2; -} - -static int -_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length EINA_UNUSED, - const unsigned long int *key2, int key2_length EINA_UNUSED) -{ - if (key1[0] - key2[0] == 0) return key1[1] - key2[1]; - return key1[0] - key2[0]; -} - -static int -_eina_file_map_key_hash(const unsigned long int *key, int key_length EINA_UNUSED) -{ - return eina_hash_int64(&key[0], sizeof (unsigned long int)) - ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); -} - #ifndef MAP_POPULATE static unsigned int _eina_file_map_populate(char *map, unsigned int size, Eina_Bool hugetlb) @@ -880,9 +859,9 @@ eina_file_open(const char *path, Eina_Bool shared) memset(n, 0, sizeof(Eina_File)); n->filename = (char*) (n + 1); strcpy((char*) n->filename, filename); - n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length), - EINA_KEY_CMP(_eina_file_map_key_cmp), - EINA_KEY_HASH(_eina_file_map_key_hash), + n->map = eina_hash_new(EINA_KEY_LENGTH(eina_file_map_key_length), + EINA_KEY_CMP(eina_file_map_key_cmp), + EINA_KEY_HASH(eina_file_map_key_hash), EINA_FREE_CB(_eina_file_map_close), 3); n->rmap = eina_hash_pointer_new(NULL); @@ -931,7 +910,9 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule) EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); -// bsd people will lack this feature + if (file->virtual) return eina_file_virtual_map_all(file); + + // bsd people will lack this feature #ifdef MAP_POPULATE if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE; #endif @@ -984,6 +965,9 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule, if (offset == 0 && length == file->length) return eina_file_map_all(file, rule); + if (file->virtual) + return eina_file_virtual_map_new(file, offset, length); + key[0] = offset; key[1] = length; @@ -1048,6 +1032,9 @@ eina_file_map_free(Eina_File *file, void *map) { EINA_SAFETY_ON_NULL_RETURN(file); + if (file->virtual) + return eina_file_virtual_map_free(file, map); + eina_lock_take(&file->lock); if (file->global_map == map) @@ -1104,6 +1091,8 @@ eina_file_map_faulted(Eina_File *file, void *map) EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE); + if (file->virtual) return EINA_FALSE; + eina_lock_take(&file->lock); if (file->global_map == map) @@ -1126,6 +1115,8 @@ eina_file_xattr_get(Eina_File *file) { EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + if (file->virtual) return NULL; + return eina_xattr_fd_ls(file->fd); } @@ -1134,6 +1125,8 @@ eina_file_xattr_value_get(Eina_File *file) { EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + if (file->virtual) return NULL; + return eina_xattr_value_fd_ls(file->fd); } diff --git a/src/lib/eina/eina_file.h b/src/lib/eina/eina_file.h index 265f4bd648..36aac586e4 100644 --- a/src/lib/eina/eina_file.h +++ b/src/lib/eina/eina_file.h @@ -444,8 +444,6 @@ typedef enum { */ EAPI Eina_Bool eina_file_copy(const char *src, const char *dst, Eina_File_Copy_Flags flags, Eina_File_Copy_Progress cb, const void *cb_data) EINA_ARG_NONNULL(1, 2); - - /** * @brief Get a read-only handler to a file. * @@ -461,6 +459,30 @@ EAPI Eina_Bool eina_file_copy(const char *src, const char *dst, Eina_File_Copy_F */ EAPI Eina_File *eina_file_open(const char *name, Eina_Bool shared) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; +/** + * @brief Create a virtual file from a memory pointer. + * + * @param data The memory pointer to take data from + * @param length The length of the data in memory + * @param copy #EINA_TRUE if the data must be copied + * @return Eina_File handle to the file + * + * @since 1.8 + */ +EAPI Eina_File * +eina_file_virtualize(const void *data, unsigned long long length, Eina_Bool copy) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1); + +/** + * @brief Tell if a file is a real file or only exist in memory + * + * @param file The file to test + * @return #EINA_TRUE if the file is a virtual file + * + * @since 1.8 + */ +EAPI Eina_Bool +eina_file_virtual(Eina_File *file) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1); + /** * @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 f52b39fc3d..75c92564dd 100644 --- a/src/lib/eina/eina_file_common.c +++ b/src/lib/eina/eina_file_common.c @@ -129,6 +129,116 @@ _eina_file_escape(char *path, size_t len) return result; } + +unsigned int +eina_file_map_key_length(const void *key EINA_UNUSED) +{ + return sizeof (unsigned long int) * 2; +} + +int +eina_file_map_key_cmp(const unsigned long int *key1, int key1_length EINA_UNUSED, + const unsigned long int *key2, int key2_length EINA_UNUSED) +{ + if (key1[0] - key2[0] == 0) return key1[1] - key2[1]; + return key1[0] - key2[0]; +} + +int +eina_file_map_key_hash(const unsigned long int *key, int key_length EINA_UNUSED) +{ + return eina_hash_int64(&key[0], sizeof (unsigned long int)) + ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); +} + +void * +eina_file_virtual_map_all(Eina_File *file) +{ + eina_lock_take(&file->lock); + file->global_refcount++; + eina_lock_release(&file->lock); + + return file->global_map; +} + +void * +eina_file_virtual_map_new(Eina_File *file, + unsigned long int offset, unsigned long int length) +{ + Eina_File_Map *map; + unsigned long int key[2]; + + // offset and length has already been checked by the caller function + + key[0] = offset; + key[1] = length; + + eina_lock_take(&file->lock); + + map = eina_hash_find(file->map, &key); + if (!map) + { + map = malloc(sizeof (Eina_File_Map)); + goto on_error; + + map->map = ((char*) file->global_map) + offset; + map->offset = offset; + map->length = length; + map->refcount = 0; + + eina_hash_add(file->map, &key, map); + eina_hash_direct_add(file->rmap, map->map, map); + } + + map->refcount++; + + on_error: + eina_lock_release(&file->lock); + return map ? map->map : NULL; +} + +void +eina_file_virtual_map_free(Eina_File *file, void *map) +{ + Eina_File_Map *em; + + eina_lock_take(&file->lock); + + // map could equal global_map even if length != file->length + em = eina_hash_find(file->rmap, &map); + if (em) + { + unsigned long int key[2]; + + 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); + } + else + { + if (file->global_map == map) + { + file->global_refcount--; + } + } + + on_exit: + eina_lock_release(&file->lock); +} + +// Private to this file API +static void +_eina_file_map_close(Eina_File_Map *map) +{ + free(map); +} + // Global API EAPI char * @@ -152,10 +262,71 @@ eina_file_path_sanitize(const char *path) return _eina_file_escape(eina_file_cleanup(result), len); } +EAPI Eina_File * +eina_file_virtualize(const void *data, unsigned long long length, Eina_Bool copy) +{ + Eina_File *file; + Eina_Nano_Time tp; + long int ti; + const char *tmpname = "/dev/mem/virtual\\/%16x"; + + // Generate an almost uniq filename based on current nsec time. + if (_eina_time_get(&tp)) return NULL; + ti = _eina_time_convert(&tp); + + file = malloc(sizeof (Eina_File) + + strlen(tmpname) + 17 + + (copy ? length : 0)); + if (!file) return NULL; + + memset(file, 0, sizeof(Eina_File)); + file->filename = (char*) (file + 1); + sprintf((char*) file->filename, tmpname, ti); + + eina_lock_new(&file->lock); + file->mtime = ti / 1000; + file->length = length; + file->mtime_nsec = ti; + file->refcount = 1; + file->fd = -1; + file->virtual = EINA_TRUE; + file->map = eina_hash_new(EINA_KEY_LENGTH(eina_file_map_key_length), + EINA_KEY_CMP(eina_file_map_key_cmp), + EINA_KEY_HASH(eina_file_map_key_hash), + EINA_FREE_CB(_eina_file_map_close), + 3); + file->rmap = eina_hash_pointer_new(NULL); + + if (copy) + { + file->global_map = (void*)(file->filename + + strlen(file->filename) + 1); + memcpy((char*) file->global_map, data, length); + } + else + { + file->global_map = (void*) data; + } + + return file; +} + +EAPI Eina_Bool +eina_file_virtual(Eina_File *file) +{ + if (file) return file->virtual; + return EINA_FALSE; +} + EAPI Eina_File * eina_file_dup(Eina_File *file) { - if (file) file->refcount++; + if (file) + { + eina_lock_take(&file->lock); + file->refcount++; + eina_lock_release(&file->lock); + } return file; } diff --git a/src/lib/eina/eina_file_common.h b/src/lib/eina/eina_file_common.h index 3d56f7bbee..31f6b6d306 100644 --- a/src/lib/eina/eina_file_common.h +++ b/src/lib/eina/eina_file_common.h @@ -61,6 +61,7 @@ struct _Eina_File Eina_Bool shared : 1; Eina_Bool delete_me : 1; Eina_Bool global_faulty : 1; + Eina_Bool virtual : 1; }; struct _Eina_File_Map @@ -123,4 +124,16 @@ extern Eina_Hash *_eina_file_cache; extern Eina_Lock _eina_file_lock_cache; extern int _eina_file_log_dom; +// Common function to handle virtual file +void *eina_file_virtual_map_all(Eina_File *file); +void *eina_file_virtual_map_new(Eina_File *file, + unsigned long int offset, unsigned long int length); +void eina_file_virtual_map_free(Eina_File *file, void *map); + +// Common hash function +unsigned int eina_file_map_key_length(const void *key); +int eina_file_map_key_cmp(const unsigned long int *key1, int key1_length, + const unsigned long int *key2, int key2_length); +int eina_file_map_key_hash(const unsigned long int *key, int key_length); + #endif /* EINA_FILE_COMMON_H_ */ diff --git a/src/lib/eina/eina_file_win32.c b/src/lib/eina/eina_file_win32.c index e795f60c1d..d96720bbd2 100644 --- a/src/lib/eina/eina_file_win32.c +++ b/src/lib/eina/eina_file_win32.c @@ -384,27 +384,6 @@ _eina_file_map_close(Eina_File_Map *map) free(map); } -static unsigned int -_eina_file_map_key_length(const void *key EINA_UNUSED) -{ - return sizeof (unsigned long int) * 2; -} - -static int -_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length EINA_UNUSED, - const unsigned long int *key2, int key2_length EINA_UNUSED) -{ - if (key1[0] - key2[0] == 0) return key1[1] - key2[1]; - return key1[0] - key2[0]; -} - -static int -_eina_file_map_key_hash(const unsigned long int *key, int key_length EINA_UNUSED) -{ - return eina_hash_int64(&key[0], sizeof (unsigned long int)) - ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); -} - /** * @endcond */ @@ -804,9 +783,9 @@ eina_file_open(const char *path, Eina_Bool shared) memset(n, 0, sizeof(Eina_File)); n->filename = (char*) (n + 1); strcpy((char*) n->filename, filename); - n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length), - EINA_KEY_CMP(_eina_file_map_key_cmp), - EINA_KEY_HASH(_eina_file_map_key_hash), + n->map = eina_hash_new(EINA_KEY_LENGTH(eina_file_map_key_length), + EINA_KEY_CMP(eina_file_map_key_cmp), + EINA_KEY_HASH(eina_file_map_key_hash), EINA_FREE_CB(_eina_file_map_close), 3); n->rmap = eina_hash_pointer_new(NULL); @@ -859,6 +838,8 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule EINA_UNUSED) { EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + if (file->virtual) return eina_file_virtual_map_all(file); + eina_lock_take(&file->lock); if (file->global_map == MAP_FAILED) { @@ -875,6 +856,7 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule EINA_UNUSED) if (file->global_map != MAP_FAILED) { file->global_refcount++; + eina_lock_release(&file->lock); return file->global_map; } @@ -899,6 +881,9 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule, if (offset == 0 && length == file->length) return eina_file_map_all(file, rule); + if (file->virtual) + return eina_file_virtual_map_new(file, offset, length); + key[0] = offset; key[1] = length; @@ -952,6 +937,9 @@ eina_file_map_free(Eina_File *file, void *map) { EINA_SAFETY_ON_NULL_RETURN(file); + if (file->virtual) + return eina_file_virtual_map_free(file, map); + eina_lock_take(&file->lock); if (file->global_map == map) @@ -989,6 +977,7 @@ eina_file_map_free(Eina_File *file, void *map) EAPI Eina_Bool eina_file_map_faulted(Eina_File *file, void *map) { + if (file->virtual) return EINA_FALSE; /* * FIXME: * vc++ : http://msdn.microsoft.com/en-us/library/windows/desktop/aa366801%28v=vs.85%29.aspx