eina: make Eina_File thread safe.

SVN revision: 59995
This commit is contained in:
Cedric BAIL 2011-06-06 17:08:06 +00:00
parent f07605db74
commit 5fa5eb95cd
1 changed files with 44 additions and 11 deletions

View File

@ -64,6 +64,7 @@ void *alloca (size_t);
#include "eina_stringshare.h" #include "eina_stringshare.h"
#include "eina_hash.h" #include "eina_hash.h"
#include "eina_list.h" #include "eina_list.h"
#include "eina_lock.h"
/*============================================================================* /*============================================================================*
* Local * * Local *
@ -116,6 +117,8 @@ struct _Eina_File
Eina_Hash *rmap; Eina_Hash *rmap;
void *global_map; void *global_map;
Eina_Lock lock;
unsigned long long length; unsigned long long length;
time_t mtime; time_t mtime;
ino_t inode; ino_t inode;
@ -142,6 +145,7 @@ struct _Eina_File_Map
static Eina_Hash *_eina_file_cache = NULL; static Eina_Hash *_eina_file_cache = NULL;
static Eina_List *_eina_file_cache_lru = NULL; static Eina_List *_eina_file_cache_lru = NULL;
static Eina_List *_eina_file_cache_delete = NULL; static Eina_List *_eina_file_cache_delete = NULL;
static Eina_Lock _eina_file_lock_cache;
static int _eina_file_log_dom = -1; static int _eina_file_log_dom = -1;
@ -487,6 +491,8 @@ eina_file_init(void)
return EINA_FALSE; return EINA_FALSE;
} }
eina_lock_new(&_eina_file_lock_cache);
return EINA_TRUE; return EINA_TRUE;
} }
@ -515,6 +521,8 @@ eina_file_shutdown(void)
eina_hash_free(_eina_file_cache); eina_hash_free(_eina_file_cache);
eina_lock_free(&_eina_file_lock_cache);
eina_log_domain_unregister(_eina_file_log_dom); eina_log_domain_unregister(_eina_file_log_dom);
_eina_file_log_dom = -1; _eina_file_log_dom = -1;
return EINA_TRUE; return EINA_TRUE;
@ -771,6 +779,8 @@ eina_file_open(const char *filename, Eina_Bool shared)
if (fstat(fd, &file_stat)) if (fstat(fd, &file_stat))
goto on_error; goto on_error;
eina_lock_take(&_eina_file_lock_cache);
file = eina_hash_find(_eina_file_cache, filename); file = eina_hash_find(_eina_file_cache, filename);
if (file && (file->mtime != file_stat.st_mtime if (file && (file->mtime != file_stat.st_mtime
|| file->length != (unsigned long long) file_stat.st_size || file->length != (unsigned long long) file_stat.st_size
@ -814,6 +824,7 @@ eina_file_open(const char *filename, Eina_Bool shared)
n->fd = fd; n->fd = fd;
n->shared = shared; n->shared = shared;
n->delete_me = EINA_FALSE; n->delete_me = EINA_FALSE;
eina_lock_new(&n->lock);
if (file) eina_hash_del(_eina_file_cache, filename, file); if (file) eina_hash_del(_eina_file_cache, filename, file);
eina_hash_direct_add(_eina_file_cache, n->filename, n); eina_hash_direct_add(_eina_file_cache, n->filename, n);
@ -828,7 +839,11 @@ eina_file_open(const char *filename, Eina_Bool shared)
_eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n); _eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n);
} }
eina_lock_take(&n->lock);
n->refcount++; n->refcount++;
eina_lock_release(&n->lock);
eina_lock_release(&_eina_file_lock_cache);
return n; return n;
@ -840,13 +855,16 @@ eina_file_open(const char *filename, Eina_Bool shared)
EAPI void EAPI void
eina_file_close(Eina_File *file) eina_file_close(Eina_File *file)
{ {
eina_lock_take(&file->lock);
file->refcount--; file->refcount--;
eina_lock_release(&file->lock);
if (file->refcount != 0) return ; if (file->refcount != 0) return ;
if (file->delete_me) if (file->delete_me)
{ {
_eina_file_cache_delete = eina_list_remove(_eina_file_cache_delete, file); _eina_file_cache_delete = eina_list_remove(_eina_file_cache_delete,
file);
_eina_file_real_close(file); _eina_file_real_close(file);
} }
else else
@ -877,6 +895,7 @@ EAPI void *
eina_file_map_all(Eina_File *file, Eina_File_Populate rule) eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
{ {
int flags = MAP_SHARED; int flags = MAP_SHARED;
void *ret = NULL;
// bsd people will lack this feature // bsd people will lack this feature
#ifdef MAP_POPULATE #ifdef MAP_POPULATE
@ -886,6 +905,7 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB; if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
#endif #endif
eina_lock_take(&file->lock);
if (file->global_map == MAP_FAILED) if (file->global_map == MAP_FAILED)
file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0); file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
@ -893,9 +913,11 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
{ {
_eina_file_map_rule_apply(rule, file->global_map, file->length); _eina_file_map_rule_apply(rule, file->global_map, file->length);
file->global_refcount++; file->global_refcount++;
return file->global_map; ret = file->global_map;
} }
return NULL;
eina_lock_release(&file->lock);
return ret;
} }
EAPI void * EAPI void *
@ -916,6 +938,8 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
key[0] = offset; key[0] = offset;
key[1] = length; key[1] = length;
eina_lock_take(&file->lock);
map = eina_hash_find(file->map, &key); map = eina_hash_find(file->map, &key);
if (!map) if (!map)
{ {
@ -930,18 +954,14 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
#endif #endif
map = malloc(sizeof (Eina_File_Map)); map = malloc(sizeof (Eina_File_Map));
if (!map) return NULL; if (!map) goto on_error;
map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset); map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset);
map->offset = offset; map->offset = offset;
map->length = length; map->length = length;
map->refcount = 0; map->refcount = 0;
if (map->map == MAP_FAILED) if (map->map == MAP_FAILED) goto on_error;
{
free(map);
return NULL;
}
eina_hash_add(file->map, &key, map); eina_hash_add(file->map, &key, map);
eina_hash_direct_add(file->rmap, map->map, map); eina_hash_direct_add(file->rmap, map->map, map);
@ -951,17 +971,27 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
_eina_file_map_rule_apply(rule, map->map, length); _eina_file_map_rule_apply(rule, map->map, length);
eina_lock_release(&file->lock);
return map->map; return map->map;
on_error:
free(map);
eina_lock_release(&file->lock);
return NULL;
} }
EAPI void EAPI void
eina_file_map_free(Eina_File *file, void *map) eina_file_map_free(Eina_File *file, void *map)
{ {
eina_lock_take(&file->lock);
if (file->global_map == map) if (file->global_map == map)
{ {
file->global_refcount--; file->global_refcount--;
if (file->global_refcount > 0) return ; if (file->global_refcount > 0) goto on_exit;
munmap(file->global_map, file->length); munmap(file->global_map, file->length);
file->global_map = MAP_FAILED; file->global_map = MAP_FAILED;
@ -976,7 +1006,7 @@ eina_file_map_free(Eina_File *file, void *map)
em->refcount--; em->refcount--;
if (em->refcount > 0) return ; if (em->refcount > 0) goto on_exit;
key[0] = em->offset; key[0] = em->offset;
key[1] = em->length; key[1] = em->length;
@ -984,6 +1014,9 @@ eina_file_map_free(Eina_File *file, void *map)
eina_hash_del(file->rmap, &map, em); eina_hash_del(file->rmap, &map, em);
eina_hash_del(file->map, &key, em); eina_hash_del(file->map, &key, em);
} }
on_exit:
eina_lock_release(&file->lock);
} }