On Thu, 14 Apr 2011, Vincent Torri wrote:
> > > eina_file_size_get() returns an unsigned_long, but on Win64, it's of size > 32 bits. Can't you return a uint_64_t ? or size_t ? > > Vincent > > On Wed, 13 Apr 2011, Enlightenment SVN wrote: > >> Log: >> eina: add Eina_File API. >> >> NOTE: the purpose of this API is to replace mmap user in the >> EFL, share cache and more code across them. The potential user >> are eet, evas, efreet, eio and enlil. More patch are needed for >> them to use this infra. Help welcome :-) >> >> NOTE2: this API also need more test and is waiting for some >> more pthread infra before being thread safe. But at the end >> it will be thread safe if eina thread safety is requested. >> >> >> Author: cedric >> Date: 2011-04-13 09:15:30 -0700 (Wed, 13 Apr 2011) >> New Revision: 58637 >> Trac: http://trac.enlightenment.org/e/changeset/58637 >> >> Modified: >> trunk/eina/ChangeLog trunk/eina/src/include/eina_file.h >> trunk/eina/src/lib/eina_file.c trunk/eina/src/lib/eina_main.c >> >> Modified: trunk/eina/ChangeLog >> =================================================================== >> --- trunk/eina/ChangeLog 2011-04-13 13:29:54 UTC (rev 58636) >> +++ trunk/eina/ChangeLog 2011-04-13 16:15:30 UTC (rev 58637) >> @@ -47,3 +47,8 @@ >> * Add eina_inlist_sort. >> * Add eina_mempool_repack. >> * Add Eina_Object API. >> + >> +2011-05-13 Cedric Bail & Vincent Torri >> + >> + * Add Eina_File API. >> + >> >> Modified: trunk/eina/src/include/eina_file.h >> =================================================================== >> --- trunk/eina/src/include/eina_file.h 2011-04-13 13:29:54 UTC (rev >> 58636) >> +++ trunk/eina/src/include/eina_file.h 2011-04-13 16:15:30 UTC (rev >> 58637) >> @@ -81,6 +81,15 @@ >> EINA_FILE_WHT /**< Whiteout file type (unused on Windows). */ >> } Eina_File_Type; >> >> +typedef struct _Eina_File Eina_File; >> + >> +typedef enum { >> + EINA_FILE_RANDOM, /**< Advise random memory access to the mapped >> memory. */ >> + EINA_FILE_SEQUENTIAL, /**< Advise sequential memory access to the mapped >> memory. */ >> + EINA_FILE_WILLNEED, /**< Advise need for all the mapped memory. */ >> + EINA_FILE_POPULATE /**< Request all the mapped memory. */ >> +} Eina_File_Populate; >> + >> /* Why do this? Well PATH_MAX may vary from when eina itself is compiled >> * to when the app using eina is compiled. exposing the path buffer below >> * cant safely and portably vary based on how/when you compile. it should >> @@ -239,6 +248,82 @@ >> EAPI Eina_Iterator *eina_file_direct_ls(const char *dir) >> EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; >> >> /** >> + * @brief Get a read-only handler to a file. >> + * >> + * @param name Filename to open >> + * @param shared Requested a shm >> + * >> + * The file are only open in read only mode. Name should be an absolute >> path to >> + * prevent cache mistake. A handler could be shared among multiple instance >> and >> + * will be correctly refcounted. File are automatically closed on exec. >> + */ >> +EAPI Eina_File *eina_file_open(const char *name, Eina_Bool shared) >> EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC; >> + >> +/** >> + * @brief Unref file handler. >> + * >> + * @param file File handler to unref. >> + * >> + * This doesn't close the file, it will remain open until it leave the >> cache. >> + */ >> +EAPI void eina_file_close(Eina_File *file); >> + >> +/** >> + * @brief Get file size at open time. >> + * >> + * @param file The file handler to request the size from. >> + * @return The length of the file. >> + */ >> +EAPI unsigned long int eina_file_size_get(Eina_File *file); >> + >> +/** >> + * @brief Get the last modification time of an open file. >> + * >> + * @param file The file handler to request the modification time from. >> + * @return The last modification time. >> + */ >> +EAPI time_t eina_file_mtime_get(Eina_File *file); >> + >> +/** >> + * @brief Get the filename of an open file. >> + * >> + * @param file The file handler to request the name from. >> + * @return Stringshared filename of the file. >> + */ >> +EAPI const char *eina_file_filename_get(Eina_File *file); >> + >> +/** >> + * @brief Map all the file to a buffer. >> + * >> + * @param file The file handler to map in memory >> + * @param rule The rule to apply to the mapped memory >> + * @return A pointer to a buffer that map all the file content. @c NULL if >> it fail. >> + */ >> +EAPI void *eina_file_map_all(Eina_File *file, Eina_File_Populate rule); >> + >> +/** >> + * @brief Map a part of the file. >> + * >> + * @param file The file handler to map in memory >> + * @param rule The rule to apply to the mapped memory >> + * @param offset The offset inside the file >> + * @param length The length of the memory to map >> + * @return A valid pointer to the system memory with @p length valid byte >> in it. And @c NULL if not inside the file or anything else goes wrong. >> + * >> + * This does handle refcounting so it will share map that target the same >> memory area. >> + */ >> +EAPI void *eina_file_map_new(Eina_File *file, Eina_File_Populate rule, >> + unsigned long int offset, unsigned long int >> length); >> + >> +/** >> + * @brief Unref and unmap memory if possible. >> + * >> + * @param file The file handler to unmap memory from. >> + * @param map Memory map to unref and unmap. >> + */ >> +EAPI void eina_file_map_free(Eina_File *file, void *map); >> + >> +/** >> * @} >> */ >> >> >> Modified: trunk/eina/src/lib/eina_file.c >> =================================================================== >> --- trunk/eina/src/lib/eina_file.c 2011-04-13 13:29:54 UTC (rev 58636) >> +++ trunk/eina/src/lib/eina_file.c 2011-04-13 16:15:30 UTC (rev 58637) >> @@ -44,6 +44,8 @@ >> #include <sys/types.h> >> #include <sys/stat.h> >> #include <unistd.h> >> +#include <sys/mman.h> >> +#include <fcntl.h> >> >> #define PATH_DELIM '/' >> >> @@ -60,15 +62,38 @@ >> #include "eina_safety_checks.h" >> #include "eina_file.h" >> #include "eina_stringshare.h" >> +#include "eina_hash.h" >> +#include "eina_list.h" >> >> /*============================================================================* >> * Local >> * >> >> *============================================================================*/ >> >> +#ifndef EINA_LOG_COLOR_DEFAULT >> +#define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN >> +#endif >> + >> +#ifdef ERR >> +#undef ERR >> +#endif >> +#define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__) >> + >> +#ifdef WRN >> +#undef WRN >> +#endif >> +#define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__) >> + >> +#ifdef DBG >> +#undef DBG >> +#endif >> +#define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__) >> + >> /** >> * @cond LOCAL >> */ >> typedef struct _Eina_File_Iterator Eina_File_Iterator; >> +typedef struct _Eina_File_Map Eina_File_Map; >> + >> struct _Eina_File_Iterator >> { >> Eina_Iterator iterator; >> @@ -79,6 +104,42 @@ >> char dir[1]; >> }; >> >> +struct _Eina_File >> +{ >> + const char *filename; >> + >> + Eina_Hash *map; >> + Eina_Hash *rmap; >> + void *global_map; >> + >> + unsigned long length; >> + time_t mtime; >> + >> + int refcount; >> + int global_refcount; >> + >> + int fd; >> + >> + Eina_Bool shared : 1; >> + Eina_Bool delete_me : 1; >> +}; >> + >> +struct _Eina_File_Map >> +{ >> + void *map; >> + >> + unsigned long int offset; >> + unsigned long int length; >> + >> + int refcount; >> +}; >> + >> +static Eina_Hash *_eina_file_cache = NULL; >> +static Eina_List *_eina_file_cache_lru = NULL; >> +static Eina_List *_eina_file_cache_delete = NULL; >> + >> +static int _eina_file_log_dom = -1; >> + >> /* >> * This complex piece of code is needed due to possible race condition. >> * The code and description of the issue can be found at : >> @@ -310,6 +371,121 @@ >> return EINA_TRUE; >> } >> >> +static void >> +_eina_file_real_close(Eina_File *file) >> +{ >> + eina_hash_free(file->rmap); >> + eina_hash_free(file->map); >> + >> + if (file->global_map != MAP_FAILED) >> + munmap(file->global_map, file->length); >> + >> + close(file->fd); >> + >> + eina_stringshare_del(file->filename); >> + >> + free(file); >> +} >> + >> +static void >> +_eina_file_map_close(Eina_File_Map *map) >> +{ >> + munmap(map->map, map->length); >> + free(map); >> +} >> + >> +static unsigned int >> +_eina_file_map_key_length(__UNUSED__ const void *key) >> +{ >> + return sizeof (unsigned long int) * 2; >> +} >> + >> +static int >> +_eina_file_map_key_cmp(const unsigned long int *key1, __UNUSED__ int >> key1_length, >> + const unsigned long int *key2, __UNUSED__ int >> key2_length) >> +{ >> + 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, __UNUSED__ int >> key_length) >> +{ >> + return eina_hash_int64(&key[0], sizeof (unsigned long int)) >> + ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); >> +} >> + >> +static void >> +_eina_file_map_rule_apply(Eina_File_Populate rule, void *addr, unsigned >> long int size) >> +{ >> + int flag; >> + >> + switch (rule) >> + { >> + case EINA_FILE_RANDOM: flag = MADV_RANDOM; break; >> + case EINA_FILE_SEQUENTIAL: flag = MADV_SEQUENTIAL; break; >> + case EINA_FILE_WILLNEED: >> + case EINA_FILE_POPULATE: >> + flag = MADV_WILLNEED; >> + break; >> + } >> + >> + madvise(addr, size, flag); >> +} >> + >> +Eina_Bool >> +eina_file_init(void) >> +{ >> + _eina_file_log_dom = eina_log_domain_register("eina_file", >> + EINA_LOG_COLOR_DEFAULT); >> + if (_eina_file_log_dom < 0) >> + { >> + EINA_LOG_ERR("Could not register log domain: eina_file"); >> + return EINA_FALSE; >> + } >> + >> + _eina_file_cache = >> eina_hash_string_djb2_new(EINA_FREE_CB(_eina_file_real_close)); >> + if (!_eina_file_cache) >> + { >> + ERR("Could not create cache."); >> + eina_log_domain_unregister(_eina_file_log_dom); >> + _eina_file_log_dom = -1; >> + return EINA_FALSE; >> + } >> + >> + return EINA_TRUE; >> +} >> + >> +Eina_Bool >> +eina_file_shutdown(void) >> +{ >> + Eina_File *f; >> + Eina_List *l; >> + >> + EINA_LIST_FREE(_eina_file_cache_delete, f) >> + _eina_file_real_close(f); >> + >> + EINA_LIST_FOREACH(_eina_file_cache_lru, l, f) >> + eina_hash_del(_eina_file_cache, f->filename, f); >> + >> + if (eina_hash_population(_eina_file_cache) > 0) >> + { >> + Eina_Iterator *it; >> + const char *key; >> + >> + it = eina_hash_iterator_key_new(_eina_file_cache); >> + EINA_ITERATOR_FOREACH(it, key) >> + ERR("File [%s] still open !", key); >> + eina_iterator_free(it); >> + } >> + >> + eina_hash_free(_eina_file_cache); >> + >> + eina_log_domain_unregister(_eina_file_log_dom); >> + _eina_file_log_dom = -1; >> + return EINA_FALSE; >> +} >> + >> /** >> * @endcond >> */ >> @@ -527,3 +703,228 @@ >> >> return &it->iterator; >> } >> + >> +EAPI Eina_File * >> +eina_file_open(const char *filename, Eina_Bool shared) >> +{ >> + Eina_File *file; >> + Eina_File *n; >> + struct stat file_stat; >> + int fd; >> + Eina_Bool create = EINA_FALSE; >> + >> + /* FIXME: always open absolute path (need to fix filename according to >> current >> + directory) */ >> + >> + if (shared) >> + fd = shm_open(filename, O_RDONLY | O_CLOEXEC, ACCESSPERMS); >> + else >> + fd = open(filename, O_RDONLY | O_CLOEXEC, ACCESSPERMS); >> + >> + if (fd < 0) return NULL; >> + >> + if (fstat(fd, &file_stat)) >> + { >> + close(fd); >> + return NULL; >> + } >> + >> + file = eina_hash_find(_eina_file_cache, filename); >> + if (file && (file->mtime != file_stat.st_mtime >> + || file->length != file_stat.st_size)) >> + { >> + create = EINA_TRUE; >> + >> + if (file->refcount == 0) >> + { >> + _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, >> file); >> + eina_hash_del(_eina_file_cache, file->filename, file); >> + >> + file = NULL; >> + } >> + else if (!file->delete_me) >> + { >> + file->delete_me = EINA_TRUE; >> + _eina_file_cache_delete = >> eina_list_prepend(_eina_file_cache_delete, file); >> + } >> + } >> + >> + if (!file || create) >> + { >> + n = malloc(sizeof (Eina_File)); >> + if (!n) goto on_error; >> + >> + n->filename = eina_stringshare_add(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), >> + EINA_FREE_CB(_eina_file_map_close), >> + 3); >> + n->rmap = eina_hash_pointer_new(NULL); >> + n->global_map = MAP_FAILED; >> + n->length = file_stat.st_size; >> + n->mtime = file_stat.st_mtime; >> + n->refcount = 0; >> + n->fd = fd; >> + n->shared = shared; >> + n->delete_me = EINA_FALSE; >> + >> + eina_hash_set(_eina_file_cache, filename, n); >> + } >> + else >> + { >> + close(fd); >> + >> + n = file; >> + >> + if (n->refcount == 0) >> + _eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n); >> + } >> + >> + n->refcount++; >> + >> + return n; >> + >> + on_error: >> + close(fd); >> + return NULL; >> +} >> + >> +EAPI void >> +eina_file_close(Eina_File *file) >> +{ >> + file->refcount--; >> + >> + if (file->refcount != 0) return ; >> + >> + if (file->delete_me) >> + { >> + _eina_file_cache_delete = eina_list_remove(_eina_file_cache_delete, >> file); >> + _eina_file_real_close(file); >> + } >> + else >> + { >> + _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, >> file); >> + } >> +} >> + >> +EAPI unsigned long int >> +eina_file_size_get(Eina_File *file) >> +{ >> + return file->length; >> +} >> + >> +EAPI time_t >> +eina_file_mtime_get(Eina_File *file) >> +{ >> + return file->mtime; >> +} >> + >> +EAPI const char * >> +eina_file_filename_get(Eina_File *file) >> +{ >> + return file->filename; >> +} >> + >> +EAPI void * >> +eina_file_map_all(Eina_File *file, Eina_File_Populate rule) >> +{ >> + int flags = MAP_SHARED; >> + >> + if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE; >> + >> + if (file->global_map == MAP_FAILED) >> + file->global_map = mmap(NULL, file->length, PROT_READ, flags, >> file->fd, 0); >> + >> + if (file->global_map != MAP_FAILED) >> + { >> + _eina_file_map_rule_apply(rule, file->global_map, file->length); >> + file->global_refcount++; >> + return file->global_map; >> + } >> + return NULL; >> +} >> + >> +EAPI void * >> +eina_file_map_new(Eina_File *file, Eina_File_Populate rule, >> + unsigned long int offset, unsigned long int length) >> +{ >> + Eina_File_Map *map; >> + unsigned long int key[2]; >> + >> + if (offset > file->length) >> + return NULL; >> + if (offset + length > file->length) >> + return NULL; >> + >> + if (offset == 0 && length == file->length) >> + return eina_file_map_all(file, rule); >> + >> + key[0] = offset; >> + key[1] = length; >> + >> + map = eina_hash_find(file->map, &key); >> + if (!map) >> + { >> + int flags = MAP_SHARED; >> + >> + if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE; >> + >> + map = malloc(sizeof (Eina_File_Map)); >> + if (!map) return NULL; >> + >> + map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset); >> + map->offset = offset; >> + map->length = length; >> + map->refcount = 0; >> + >> + if (map->map == MAP_FAILED) >> + { >> + free(map); >> + return NULL; >> + } >> + >> + eina_hash_add(file->map, &key, map); >> + eina_hash_direct_add(file->rmap, map->map, map); >> + } >> + >> + map->refcount++; >> + >> + _eina_file_map_rule_apply(rule, map->map, length); >> + >> + return map->map; >> +} >> + >> +EAPI void >> +eina_file_map_free(Eina_File *file, void *map) >> +{ >> + if (file->global_map == map) >> + { >> + file->global_refcount--; >> + >> + if (file->global_refcount > 0) return ; >> + >> + munmap(file->global_map, file->length); >> + file->global_map = MAP_FAILED; >> + } >> + else >> + { >> + Eina_File_Map *em; >> + unsigned long int key[2]; >> + >> + em = eina_hash_find(file->rmap, &map); >> + if (!em) return ; >> + >> + em->refcount--; >> + >> + if (em->refcount > 0) return ; >> + >> + key[0] = em->offset; >> + key[1] = em->length; >> + >> + eina_hash_del(file->rmap, &map, em); >> + eina_hash_del(file->map, &key, em); >> + } >> +} >> + >> + >> >> Modified: trunk/eina/src/lib/eina_main.c >> =================================================================== >> --- trunk/eina/src/lib/eina_main.c 2011-04-13 13:29:54 UTC (rev 58636) >> +++ trunk/eina/src/lib/eina_main.c 2011-04-13 16:15:30 UTC (rev 58637) >> @@ -124,6 +124,7 @@ >> S(ustrbuf); >> S(quadtree); >> S(simple_xml); >> + S(file); >> #undef S >> >> struct eina_desc_setup >> @@ -156,7 +157,8 @@ >> S(strbuf), >> S(ustrbuf), >> S(quadtree), >> - S(simple_xml) >> + S(simple_xml), >> + S(file) >> #undef S >> }; >> static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / >> >> >> ------------------------------------------------------------------------------ >> Forrester Wave Report - Recovery time is now measured in hours and minutes >> not days. Key insights are discussed in the 2010 Forrester Wave Report as >> part of an in-depth evaluation of disaster recovery service providers. >> Forrester found the best-in-class provider in terms of services and vision. >> Read this report now! http://p.sf.net/sfu/ibm-webcastpromo >> _______________________________________________ >> enlightenment-svn mailing list >> enlightenment-...@lists.sourceforge.net >> https://lists.sourceforge.net/lists/listinfo/enlightenment-svn >> >> > > ------------------------------------------------------------------------------ > Benefiting from Server Virtualization: Beyond Initial Workload > Consolidation -- Increasing the use of server virtualization is a top > priority.Virtualization can reduce costs, simplify management, and improve > application availability and disaster protection. Learn more about boosting > the value of server virtualization. http://p.sf.net/sfu/vmware-sfdev2dev > _______________________________________________ > enlightenment-devel mailing list > enlightenment-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/enlightenment-devel > > ------------------------------------------------------------------------------ Benefiting from Server Virtualization: Beyond Initial Workload Consolidation -- Increasing the use of server virtualization is a top priority.Virtualization can reduce costs, simplify management, and improve application availability and disaster protection. Learn more about boosting the value of server virtualization. http://p.sf.net/sfu/vmware-sfdev2dev _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel