diff --git a/src/bin/evas/evas_cserve2.h b/src/bin/evas/evas_cserve2.h index c91e822b6b..f4a1d8da32 100644 --- a/src/bin/evas/evas_cserve2.h +++ b/src/bin/evas/evas_cserve2.h @@ -233,7 +233,7 @@ void cserve2_client_del(Client *client); void cserve2_client_deliver(Client *client); void cserve2_client_error_send(Client *client, unsigned int rid, int error_code); ssize_t cserve2_client_send(Client *client, const void *data, size_t size); -void cserve2_index_list_send(const char *files_index_path, const char *images_index_path, const char *fonts_index_path); +void cserve2_index_list_send(const char *strings_index_path, const char *strings_entries_path, const char *files_index_path, const char *images_index_path, const char *fonts_index_path, Client *client); Eina_Bool cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data); Eina_Bool cserve2_fd_watch_del(int fd); @@ -357,6 +357,8 @@ void *cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid); // Shared strings +const char *cserve2_shared_strings_table_name_get(); +const char *cserve2_shared_strings_index_name_get(); int cserve2_shared_string_add(const char *str); int cserve2_shared_string_ref(int id); void cserve2_shared_string_del(int id); diff --git a/src/bin/evas/evas_cserve2_cache.c b/src/bin/evas/evas_cserve2_cache.c index 777d35c337..5bbe014fae 100644 --- a/src/bin/evas/evas_cserve2_cache.c +++ b/src/bin/evas/evas_cserve2_cache.c @@ -148,7 +148,8 @@ struct _File_Watch { }; static unsigned int _entry_id = 0; -static unsigned int _freed_entry_count = 0; +static unsigned int _freed_file_entry_count = 0; +static unsigned int _freed_image_entry_count = 0; static Shared_Array *_file_data_array = NULL; static Shared_Array *_image_data_array = NULL; @@ -315,12 +316,13 @@ _repack() { Shared_Array *sa; int count; + Eina_Bool updated = EINA_FALSE; // Repack when we have 10% fragmentation over the whole shm buffer count = cserve2_shared_array_size_get(_file_data_array); - if ((count > 0) && (_freed_entry_count > 100 || - ((_freed_entry_count * 100) / count >= 10))) + if ((count > 0) && (_freed_file_entry_count > 100 || + ((_freed_file_entry_count * 100) / count >= 10))) { DBG("Repacking file data array: %s", cserve2_shared_array_name_get(_file_data_array)); @@ -331,19 +333,46 @@ _repack() if (!sa) { ERR("Failed to repack array. Keeping previous references!"); - return; + goto skip_files; } cserve2_shared_array_del(_file_data_array); - _freed_entry_count = 0; + _freed_file_entry_count = 0; _file_data_array = sa; + updated = EINA_TRUE; } +skip_files: - // FIXME TODO: Repack image data array as well + count = cserve2_shared_array_size_get(_image_data_array); + if ((count > 0) && (_freed_image_entry_count > 100 || + ((_freed_image_entry_count * 100) / count >= 10))) + { + DBG("Repacking image data array: %s", + cserve2_shared_array_name_get(_image_data_array)); - cserve2_index_list_send(cserve2_shared_array_name_get(_file_data_array), - cserve2_shared_array_name_get(_image_data_array), - NULL); + sa = cserve2_shared_array_repack(_image_data_array, + _repack_skip_cb, + _shm_object_id_cmp_cb, NULL); + if (!sa) + { + ERR("Failed to repack array. Keeping previous references!"); + goto skip_images; + } + + cserve2_shared_array_del(_image_data_array); + _freed_image_entry_count = 0; + _image_data_array = sa; + updated = EINA_TRUE; + } +skip_images: + + if (updated) + cserve2_index_list_send(cserve2_shared_strings_index_name_get(), + cserve2_shared_strings_table_name_get(), + cserve2_shared_array_name_get(_file_data_array), + cserve2_shared_array_name_get(_image_data_array), + NULL, + NULL); } @@ -404,6 +433,18 @@ _image_loaded_msg_create(Image_Entry *ientry, Image_Data *idata, int *size) msg->shm.image_size = cserve2_shm_size_get(ientry->shm); msg->alpha_sparse = idata->alpha_sparse; + if (idata->shm_id) + { + const char *old = cserve2_shared_string_get(idata->shm_id); + if (strcmp(old, shmpath)) + { + cserve2_shared_string_del(idata->shm_id); + idata->shm_id = cserve2_shared_string_add(shmpath); + } + } + else + idata->shm_id = cserve2_shared_string_add(shmpath); + buf = (char *)msg + sizeof(*msg); memcpy(buf, shmpath, path_len); @@ -723,7 +764,7 @@ _scaling_prepare_and_do(Image_Entry *ientry, Image_Data *idata) cserve2_shm_unref(ientry->shm); cserve2_shared_string_del(idata->shm_id); ientry->shm = scale_shm; - idata->shm_id = cserve2_shared_string_add(cserve2_shm_name_get(ientry->shm)); + idata->shm_id = 0; return 0; } @@ -891,6 +932,8 @@ _hash_image_entry_free(void *data) { _image_id_free(idata); _image_entry_free(ientry); + _freed_image_entry_count++; + _repack(); } else ERR("Could not find image entry %u", ENTRYID(ientry)); } @@ -951,7 +994,7 @@ _hash_file_entry_free(void *data) _file_data_free(fd); _file_entry_free(fentry); - _freed_entry_count++; + _freed_file_entry_count++; _repack(); } @@ -1165,6 +1208,7 @@ _entry_unused_push(Image_Entry *ientry) idata = _image_data_find(ENTRYID(ientry)); if (!idata) return; + idata->unused = EINA_TRUE; size = _image_entry_size_get(ientry); if ((size > max_unused_mem_usage) || !(idata->doload)) @@ -1191,7 +1235,6 @@ _entry_unused_push(Image_Entry *ientry) unused_mem_usage = 0; } image_entries_lru = eina_list_append(image_entries_lru, ientry); - idata->unused = EINA_TRUE; unused_mem_usage += size; } @@ -1303,6 +1346,13 @@ cserve2_cache_client_new(Client *client) client->files.referencing = eina_hash_int32_new(_entry_free_cb); client->images.referencing = eina_hash_int32_new(_entry_free_cb); client->fonts.referencing = NULL; + + cserve2_index_list_send(cserve2_shared_strings_index_name_get(), + cserve2_shared_strings_table_name_get(), + cserve2_shared_array_name_get(_file_data_array), + cserve2_shared_array_name_get(_image_data_array), + NULL, + client); } void diff --git a/src/bin/evas/evas_cserve2_index.c b/src/bin/evas/evas_cserve2_index.c index 329ceeb4e2..6563872f5b 100644 --- a/src/bin/evas/evas_cserve2_index.c +++ b/src/bin/evas/evas_cserve2_index.c @@ -12,7 +12,6 @@ #include typedef struct _Data_Shm Data_Shm; -typedef struct _Index_Entry Index_Entry; typedef struct _Block Block; typedef struct _Shared_Index Shared_Index; @@ -60,16 +59,6 @@ struct _Block int32_t shmid; }; -struct _Index_Entry -{ - int32_t id; // Write last, can't be 0 - int32_t refcount; - // Block entry - int32_t length; - int32_t offset; - int32_t shmid; -}; - // Data blocks will be aligned to blocks of DATA_BLOCKSIZE bytes to reduce // fragmentation (after del). 16 is convenient for debugging with hd :) @@ -159,7 +148,7 @@ _block_rbtree_block_find(const Block *node, const void *key, // Data shm -Data_Shm * +static Data_Shm * _shared_data_shm_new(int size) { Data_Shm *ds; @@ -194,7 +183,7 @@ _shared_data_shm_new(int size) return ds; } -void +static void _shared_data_shm_del(Data_Shm *ds) { if (!ds) return; @@ -202,7 +191,7 @@ _shared_data_shm_del(Data_Shm *ds) free(ds); } -int +static int _shared_data_shm_resize(Data_Shm *ds, size_t newsize) { Shm_Handle *shm; @@ -803,6 +792,24 @@ cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid) // Shared strings +const char * +cserve2_shared_strings_table_name_get() +{ + if (!_string_mempool) + return NULL; + + return cserve2_shm_name_get(_string_mempool->ds->shm); +} + +const char * +cserve2_shared_strings_index_name_get() +{ + if (!_string_mempool) + return NULL; + + return cserve2_shared_array_name_get(_string_mempool->index->sa); +} + int cserve2_shared_string_add(const char *str) { diff --git a/src/bin/evas/evas_cserve2_main.c b/src/bin/evas/evas_cserve2_main.c index 5982c0d297..ae4a80e854 100644 --- a/src/bin/evas/evas_cserve2_main.c +++ b/src/bin/evas/evas_cserve2_main.c @@ -36,17 +36,27 @@ cserve2_client_error_send(Client *client, unsigned int rid, int error_code) } void -cserve2_index_list_send(const char *files_index_path, +cserve2_index_list_send(const char *strings_index_path, + const char *strings_entries_path, + const char *files_index_path, const char *images_index_path, - const char *fonts_index_path) + const char *fonts_index_path, + Client *client) { Eina_Iterator *iter; - Client *client; Msg_Index_List msg; const int size = sizeof(msg); + INF("New shared index: strings: '%s':'%s' files: '%s' images: '%s', fonts: '%s'", + strings_index_path, strings_entries_path, + files_index_path, images_index_path, fonts_index_path); + memset(&msg, 0, size); msg.base.type = CSERVE2_INDEX_LIST; + if (strings_index_path) + eina_strlcpy(msg.strings_index_path, strings_index_path, 64); + if (strings_entries_path) + eina_strlcpy(msg.strings_entries_path, strings_entries_path, 64); if (files_index_path) eina_strlcpy(msg.files_index_path, files_index_path, 64); if (images_index_path) @@ -54,14 +64,23 @@ cserve2_index_list_send(const char *files_index_path, if (fonts_index_path) eina_strlcpy(msg.fonts_index_path, fonts_index_path, 64); - iter = eina_hash_iterator_data_new(client_list); - EINA_ITERATOR_FOREACH(iter, client) + if (!client) + { + iter = eina_hash_iterator_data_new(client_list); + EINA_ITERATOR_FOREACH(iter, client) + { + DBG("Sending updated list of indexes to client %d", client->id); + cserve2_client_send(client, &size, sizeof(size)); + cserve2_client_send(client, &msg, sizeof(msg)); + } + eina_iterator_free(iter); + } + else { DBG("Sending updated list of indexes to client %d", client->id); cserve2_client_send(client, &size, sizeof(size)); cserve2_client_send(client, &msg, sizeof(msg)); } - eina_iterator_free(iter); } static void diff --git a/src/lib/evas/cserve2/evas_cs2.h b/src/lib/evas/cserve2/evas_cs2.h index d47a02aac9..7cb6e08375 100644 --- a/src/lib/evas/cserve2/evas_cs2.h +++ b/src/lib/evas/cserve2/evas_cs2.h @@ -275,12 +275,15 @@ struct _Msg_Font_Debug { */ struct _Msg_Index_List { Msg_Base base; + char strings_index_path[64]; + char strings_entries_path[64]; char files_index_path[64]; char images_index_path[64]; char fonts_index_path[64]; }; typedef struct _Shm_Object Shm_Object; +typedef struct _Index_Entry Index_Entry; typedef struct _File_Data File_Data; typedef struct _Image_Data Image_Data; typedef struct _Shared_Array_Header Shared_Array_Header; @@ -304,6 +307,15 @@ struct _Shm_Object SHMOBJECT; }; +struct _Index_Entry +{ + SHMOBJECT; + // Block entry + int32_t length; + int32_t offset; + int32_t shmid; +}; + struct _File_Data { SHMOBJECT; string_t path; diff --git a/src/lib/evas/cserve2/evas_cs2_client.c b/src/lib/evas/cserve2/evas_cs2_client.c index a52d547386..73d0936e66 100644 --- a/src/lib/evas/cserve2/evas_cs2_client.c +++ b/src/lib/evas/cserve2/evas_cs2_client.c @@ -21,6 +21,7 @@ typedef void (*Op_Callback)(void *data, const void *msg, int size); struct _File_Entry { unsigned int file_id; + unsigned int server_file_id; }; struct _Client_Request { @@ -44,7 +45,10 @@ static Eina_List *_requests = NULL; // Shared index table static Index_Table _index; +static const char *_shared_string_get(int id); static int _server_index_list_set(Msg_Base *data, int size); +static const File_Data *_shared_image_entry_file_data_find(Image_Entry *ie); +static const Image_Data *_shared_image_entry_image_data_find(Image_Entry *ie); #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)NULL)->sun_path) @@ -325,123 +329,6 @@ _next_rid(void) return _rid_count++; } -// Returns the number of correctly opened index arrays -static int -_server_index_list_set(Msg_Base *data, int size) -{ - Msg_Index_List *msg = (Msg_Index_List *) data; - unsigned sz; - int ret = 0; - - if (size != sizeof(*msg) || msg->base.type != CSERVE2_INDEX_LIST) - { - CRIT("Invalid message! type: %d, size: %d (expected %d)", - msg->base.type, size, (int) sizeof(*msg)); - return -1; - } - - // Reset index table - if (_index.files.f) - { - if (_index.files.header) - eina_file_map_free(_index.files.f, (void *) _index.files.header); - eina_file_close(_index.files.f); - } - if (_index.images.f) - { - if (_index.images.header) - eina_file_map_free(_index.images.f, (void *) _index.images.header); - eina_file_close(_index.images.f); - } - if (_index.fonts.f) - { - if (_index.fonts.header) - eina_file_map_free(_index.fonts.f, (void *) _index.fonts.header); - eina_file_close(_index.fonts.f); - } - memset(&_index, 0, sizeof(_index)); - - // Open new indexes - eina_strlcpy(_index.files.path, msg->files_index_path, 64); - eina_strlcpy(_index.images.path, msg->images_index_path, 64); - eina_strlcpy(_index.fonts.path, msg->fonts_index_path, 64); - - if (_index.files.path[0]) - { - _index.files.f = eina_file_open(_index.files.path, EINA_TRUE); - sz = eina_file_size_get(_index.files.f); - if (sz < sizeof(Shared_Array_Header)) - { - ERR("Shared index for files is too small: %u", sz); - eina_file_close(_index.files.f); - _index.files.f = NULL; - } - else - { - _index.files.header = eina_file_map_all(_index.files.f, - EINA_FILE_WILLNEED); - if (sz < (_index.files.header->count * sizeof(File_Data) - + sizeof(Shared_Array_Header))) - { - ERR("Shared index size does not match array size: %u / %u", - sz, _index.files.header->count); - eina_file_map_free(_index.files.f, - (void *) _index.files.header); - eina_file_close(_index.files.f); - _index.files.f = NULL; - } - else - { - _index.files.entries = (File_Data *) &(_index.files.header[1]); - DBG("Mapped files shared index '%s' at %p: %u entries max", - _index.files.path, _index.files.header, - _index.files.header->count); - ret++; - } - } - } - - if (_index.images.path[0]) - { - _index.images.f = eina_file_open(_index.images.path, EINA_TRUE); - sz = eina_file_size_get(_index.images.f); - if (sz < sizeof(Shared_Array_Header)) - { - ERR("Shared index for images is too small: %u", sz); - eina_file_close(_index.images.f); - _index.images.f = NULL; - } - else - { - _index.images.header = eina_file_map_all(_index.images.f, - EINA_FILE_WILLNEED); - if (sz < (_index.images.header->count * sizeof(Image_Data) - + sizeof(Shared_Array_Header))) - { - ERR("Shared index size does not match array size: %u / %u", - sz, _index.images.header->count); - eina_file_map_free(_index.images.f, - (void *) _index.images.header); - eina_file_close(_index.images.f); - _index.images.f = NULL; - } - else - { - _index.images.entries = (Image_Data *) &(_index.images.header[1]); - DBG("Mapped images shared index '%s' at %p: %u entries max", - _index.images.path, _index.images.header, - _index.images.header->count); - ret++; - } - } - } - - if (_index.fonts.path[0]) - ERR("Not implemented yet: fonts shared index"); - - return ret; -} - static unsigned int _server_dispatch(Eina_Bool *failed) { @@ -546,7 +433,10 @@ _image_opened_cb(void *data, const void *msg_received, int size) */ //DBG("Received OPENED for RID: %d [open_rid: %d]", answer->rid, ie->open_rid); if (answer->rid != ie->open_rid) - WRN("Message rid (%d) differs from expected rid (open_rid: %d)", answer->rid, ie->open_rid); + { + WRN("Message rid (%d) differs from expected rid (open_rid: %d)", answer->rid, ie->open_rid); + return; + } ie->open_rid = 0; if (answer->type != CSERVE2_OPENED) @@ -639,7 +529,10 @@ _image_loaded_cb(void *data, const void *msg_received, int size) //DBG("Received LOADED for RID: %d [load_rid: %d]", answer->rid, ie->load_rid); if (answer->rid != ie->load_rid) - WRN("Message rid (%d) differs from expected rid (load_rid: %d)", answer->rid, ie->load_rid); + { + WRN("Message rid (%d) differs from expected rid (load_rid: %d)", answer->rid, ie->load_rid); + return; + } ie->load_rid = 0; if (!ie->data2) @@ -1008,9 +901,25 @@ evas_cserve2_image_load(Image_Entry *ie) int evas_cserve2_image_load_wait(Image_Entry *ie) { + const File_Data *fd; + if (!ie) return CSERVE2_GENERIC; + fd = _shared_image_entry_file_data_find(ie); + if (fd) + { + INF("Bypassing socket wait (open_rid %d)", ie->open_rid); + ie->w = fd->w; + ie->h = fd->h; + ie->flags.alpha = fd->alpha; + ie->animated.loop_hint = fd->loop_hint; + ie->animated.loop_count = fd->loop_count; + ie->animated.frame_count = fd->frame_count; + ie->open_rid = 0; + return CSERVE2_NONE; + } + if (ie->open_rid) { if (!_server_dispatch_until(ie->open_rid)) @@ -1045,9 +954,51 @@ evas_cserve2_image_data_load(Image_Entry *ie) int evas_cserve2_image_load_data_wait(Image_Entry *ie) { + const Image_Data *idata; + if (!ie) return CSERVE2_GENERIC; + idata = _shared_image_entry_image_data_find(ie); + if (idata) + { + // FIXME: Ugly copy & paste from _loaded_handle + Data_Entry *dentry = ie->data2; + RGBA_Image *im = (RGBA_Image *)ie; + const char *shmpath; + + shmpath = _shared_string_get(idata->shm_id); + if (!shmpath) goto load_wait; + INF("Bypassing image load socket wait. Image found: %d in %s", + idata->id, shmpath); + + dentry->shm.mmap_offset = 0; + dentry->shm.use_offset = 0; + dentry->shm.f = eina_file_open(shmpath, EINA_TRUE); + dentry->shm.mmap_size = eina_file_size_get(dentry->shm.f); + dentry->shm.image_size = dentry->shm.mmap_size; + + dentry->shm.data = eina_file_map_new(dentry->shm.f, EINA_FILE_WILLNEED, + dentry->shm.mmap_offset, + dentry->shm.mmap_size); + if (!dentry->shm.data) + { + DBG("could not mmap the shm file: %d %m", errno); + eina_file_close(dentry->shm.f); + dentry->shm.f = NULL; + goto load_wait; + } + + im->image.data = dentry->shm.data; + ie->flags.alpha_sparse = idata->alpha_sparse; + ie->flags.loaded = EINA_TRUE; + im->image.no_free = 1; + + ie->load_rid = 0; + return CSERVE2_NONE; + } + +load_wait: if (ie->load_rid) { if (!_server_dispatch_until(ie->load_rid)) @@ -1652,4 +1603,431 @@ evas_cserve2_font_glyph_bitmap_get(Font_Entry *fe, unsigned int idx, Font_Hint_F return &(out->base); } + + +// Fast access to shared index tables + + +// Returns the number of correctly opened index arrays +static int +_server_index_list_set(Msg_Base *data, int size) +{ + Msg_Index_List *msg = (Msg_Index_List *) data; + unsigned sz; + int ret = 0; + + // TODO #1: Check populate rule. + // TODO #2: Protect memory for read-only access. + // TODO #3: Optimize file reopen/remap (esp. strings table) + + if (size != sizeof(*msg) || msg->base.type != CSERVE2_INDEX_LIST) + { + CRIT("Invalid message! type: %d, size: %d (expected %d)", + msg->base.type, size, (int) sizeof(*msg)); + return -1; + } + + // Reset index table + if (_index.strings.index_file) + { + if (_index.strings.index_header) + eina_file_map_free(_index.strings.index_file, + (void *) _index.strings.index_header); + eina_file_close(_index.strings.index_file); + } + if (_index.strings.entries_file) + { + if (_index.strings.index_header) + eina_file_map_free(_index.strings.entries_file, + (void *) _index.strings.index_header); + eina_file_close(_index.strings.entries_file); + } + if (_index.files.f) + { + if (_index.files.header) + eina_file_map_free(_index.files.f, (void *) _index.files.header); + eina_file_close(_index.files.f); + } + if (_index.images.f) + { + if (_index.images.header) + eina_file_map_free(_index.images.f, (void *) _index.images.header); + eina_file_close(_index.images.f); + } + if (_index.fonts.f) + { + if (_index.fonts.header) + eina_file_map_free(_index.fonts.f, (void *) _index.fonts.header); + eina_file_close(_index.fonts.f); + } + + // Open new indexes + eina_strlcpy(_index.strings.index_path, msg->strings_index_path, 64); + eina_strlcpy(_index.strings.entries_path, msg->strings_entries_path, 64); + eina_strlcpy(_index.files.path, msg->files_index_path, 64); + eina_strlcpy(_index.images.path, msg->images_index_path, 64); + eina_strlcpy(_index.fonts.path, msg->fonts_index_path, 64); + + if (_index.strings.index_path[0] && _index.strings.entries_path[0]) + { + _index.strings.index_file = eina_file_open(_index.strings.index_path, + EINA_TRUE); + sz = eina_file_size_get(_index.strings.index_file); + _index.strings.index_header = eina_file_map_all( + _index.strings.index_file, EINA_FILE_POPULATE); + if (_index.strings.index_header && sz > sizeof(Shared_Array_Header) + && sz >= (_index.strings.index_header->count * sizeof(Index_Entry) + + sizeof(Shared_Array_Header))) + { + _index.strings.indexes = (Index_Entry *) + &(_index.strings.index_header[1]); + _index.strings.entries_file = eina_file_open( + _index.strings.entries_path, EINA_TRUE); + _index.strings.entries_size = eina_file_size_get( + _index.strings.entries_file); + _index.strings.data = eina_file_map_all( + _index.strings.entries_file, EINA_FILE_RANDOM); + if (!_index.strings.entries_size || !_index.strings.data) + goto strings_map_failed; + DBG("Mapped shared string table with indexes in %s and data in %s", + _index.strings.index_path, _index.strings.entries_path); + } + else + { +strings_map_failed: + eina_file_map_free(_index.strings.entries_file, + (void *) _index.strings.data); + eina_file_close(_index.strings.entries_file); + eina_file_map_free(_index.strings.index_file, + (void *) _index.strings.index_header); + eina_file_close(_index.strings.index_file); + memset(&_index.strings, 0, sizeof(_index.strings)); + } + } + + if (_index.files.path[0]) + { + _index.files.f = eina_file_open(_index.files.path, EINA_TRUE); + sz = eina_file_size_get(_index.files.f); + if (sz < sizeof(Shared_Array_Header)) + { + ERR("Shared index for files is too small: %u", sz); + eina_file_close(_index.files.f); + _index.files.f = NULL; + } + else + { + _index.files.header = eina_file_map_all(_index.files.f, + EINA_FILE_POPULATE); + if (sz < (_index.files.header->count * sizeof(File_Data) + + sizeof(Shared_Array_Header))) + { + ERR("Shared index size does not match array size: %u / %u", + sz, _index.files.header->count); + eina_file_map_free(_index.files.f, + (void *) _index.files.header); + eina_file_close(_index.files.f); + _index.files.f = NULL; + _index.files.header = NULL; + } + else + { + _index.files.entries.fdata = + (File_Data *) &(_index.files.header[1]); + DBG("Mapped files shared index '%s' at %p: %u entries max", + _index.files.path, _index.files.header, + _index.files.header->count); + ret++; + } + } + } + + if (_index.images.path[0]) + { + _index.images.f = eina_file_open(_index.images.path, EINA_TRUE); + sz = eina_file_size_get(_index.images.f); + if (sz < sizeof(Shared_Array_Header)) + { + ERR("Shared index for images is too small: %u", sz); + eina_file_close(_index.images.f); + _index.images.f = NULL; + } + else + { + int size = eina_file_size_get(_index.images.f); + _index.images.header = eina_file_map_all(_index.images.f, + EINA_FILE_POPULATE); + if (sz < (_index.images.header->count * sizeof(Image_Data) + + sizeof(Shared_Array_Header))) + { + ERR("Shared index size does not match array size: %u / %u", + sz, _index.images.header->count); + eina_file_map_free(_index.images.f, + (void *) _index.images.header); + eina_file_close(_index.images.f); + _index.images.f = NULL; + _index.images.header = NULL; + } + else + { + _index.images.count = (size - sizeof(Shared_Array_Header)) + / sizeof(Image_Data); + _index.images.entries.idata = + (Image_Data *) &(_index.images.header[1]); + DBG("Mapped images shared index '%s' at %p: %u entries max", + _index.images.path, _index.images.header, + _index.images.header->count); + ret++; + } + } + } + + if (_index.fonts.path[0]) + ERR("Not implemented yet: fonts shared index"); + + return ret; +} + +// FIXME: Copy & paste from evas_cserve2_cache.c +static int +_shm_object_id_cmp_cb(const void *data1, const void *data2) +{ + const Shm_Object *obj; + unsigned int key; + + if (data1 == data2) return 0; + if (!data1) return 1; + if (!data2) return -1; + + obj = data1; + key = *((unsigned int *) data2); + if (obj->id == key) return 0; + if (obj->id < key) + return -1; + else + return +1; +} + +// FIXME: (almost) copy & paste from evas_cserve2_cache.c +static const char * +_shared_string_get(int id) +{ + const char *ret; + const Index_Entry *ie = NULL; + int k; + + if (id <= 0) return NULL; + if (!_index.strings.data) return NULL; + + // Binary search + if (_index.strings.index_header->sortedidx > 0) + { + int low = 0; + int high = _index.strings.index_header->sortedidx; + int prev = -1; + int r; + k = high / 2; + while (prev != k) + { + ie = &(_index.strings.indexes[k]); + r = _shm_object_id_cmp_cb(ie, &id); + if (!r) + goto found; + else if (r > 0) + high = k; + else + low = k; + prev = k; + k = low + (high - low) / 2; + } + } + + // Linear search O(n) + k = _index.strings.index_header->sortedidx; + for (; k < _index.strings.index_header->emptyidx; k++) + { + ie = &(_index.strings.indexes[k]); + if (!_shm_object_id_cmp_cb(ie, &id)) + goto found; + } + + return NULL; + +found: + if (!ie) return NULL; + if (!ie->refcount) return NULL; + if (ie->length + ie->offset > (int) _index.strings.entries_size) + return NULL; + + ret = _index.strings.data + ie->offset; + return ret; +} + +static inline Eina_Bool +_shared_image_entry_file_data_match(Image_Entry *ie, const File_Data *fd) +{ + const char *path, *key, *loader; + + if (!fd || !ie) return EINA_FALSE; + if (!ie->file && !ie->key) + return EINA_FALSE; + + path = _shared_string_get(fd->path); + key = _shared_string_get(fd->key); + loader = _shared_string_get(fd->loader_data); + + if (!path && ie->file) + return EINA_FALSE; + if (ie->file && strcmp(path, ie->file)) + return EINA_FALSE; + + if (!key && ie->key) + return EINA_FALSE; + if (ie->key && strcmp(key, ie->key)) + return EINA_FALSE; + + /* + if (!loader && ie->loader_data) + return EINA_FALSE; + if (strcmp(loader, ie->loader_data)) + return EINA_FALSE; + */ + + // Check w,h ? + // Not sure which load opts should be checked here + DBG("Found a match for %s:%s", ie->file, ie->key); + return EINA_TRUE; +} + +static const File_Data * +_shared_image_entry_file_data_find(Image_Entry *ie) +{ + const File_Data *fdata = NULL; + File_Entry *fe; + int k; + + DBG("Trying to find if image '%s:%s' is already opened by cserve2", + ie->file, ie->key); + + if (!_index.files.entries.fdata) + return NULL; + +#warning FIXME Use safe count + for (k = 0; k < _index.files.header->count; k++) + { + const File_Data *fd = &(_index.files.entries.fdata[k]); + if (!fd->id) return NULL; + if (!fd->refcount) continue; + + if (_shared_image_entry_file_data_match(ie, fd)) + { + fdata = fd; + break; + } + } + + DBG("Found file data for %s:%s: %d", ie->file, ie->key, fdata->id); + fe = ie->data1; + fe->server_file_id = fdata->id; + return fdata; +} + +static inline Eina_Bool +_shared_image_entry_image_data_match(Image_Entry *ie, const Image_Data *id) +{ + int cmp; + cmp = memcmp(&ie->load_opts, &id->opts, sizeof(ie->load_opts)); + if (!cmp) + { + DBG("Found loaded image entry at %d", id->id); + return EINA_TRUE; + } + return EINA_FALSE; +} + +static const Image_Data * +_shared_image_entry_image_data_find(Image_Entry *ie) +{ + const Image_Data *idata = NULL; + File_Entry *fe; + unsigned int file_id = 0; + int k; + + DBG("Trying to find if image '%s:%s' is already loaded by cserve2", + ie->file, ie->key); + + if (!_index.images.entries.idata || !_index.images.count) + return NULL; + + fe = ie->data1; + if (fe && fe->server_file_id) + file_id = fe->server_file_id; + else + { + const File_Data *fdata = _shared_image_entry_file_data_find(ie); + if (!fdata) + { + ERR("File is not opened by cserve2"); + return NULL; + } + file_id = fdata->id; + } + + // FIXME. Factorize and simplify. + if (_index.images.count != _index.images.header->count) + { + size_t sz; + WRN("Image entries array has been resized from %d to %d. Remapping.", + _index.images.count, _index.images.header->count); + eina_file_map_free(_index.images.f, (void *) _index.images.header); + eina_file_close(_index.images.f); + _index.images.f = eina_file_open(_index.images.path, EINA_TRUE); + sz = eina_file_size_get(_index.images.f); + _index.images.header = eina_file_map_new(_index.images.f, EINA_FILE_RANDOM, + 0, sz); //eina_file_map_all(_index.images.f, EINA_FILE_RANDOM); + _index.images.count = _index.images.header->count; + if (_index.images.count * sizeof(Image_Data) + sizeof(Shared_Array_Header) > sz) + CRIT("New mapping might be too small!"); + if (!_index.images.header) + { + ERR("Could not remap the array!"); + eina_file_close(_index.images.f); + _index.images.f = NULL; + _index.images.entries.idata = NULL; + return NULL; + } + _index.images.entries.idata = + (Image_Data *) &(_index.images.header[1]); + } + + DBG("Looking for loaded image with file id %d", file_id); + for (k = 0; k < _index.images.count; k++) + { + const Image_Data *id = &(_index.images.entries.idata[k]); + if (!id->id) return NULL; + if (!id->refcount) continue; + if (id->file_id != file_id) continue; + + if (_shared_image_entry_image_data_match(ie, id)) + { + idata = id; + break; + } + } + + if (!idata) + return NULL; + + if (!_shared_string_get(idata->shm_id)) + { + ERR("Found image but it is not loaded yet: %d (doload %d shm %s)", + idata->id, idata->doload, _shared_string_get(idata->shm_id)); + return NULL; + } + + DBG("Found image, loaded, in shm %s", _shared_string_get(idata->shm_id)); + return idata; +} + + #endif diff --git a/src/lib/evas/cserve2/evas_cs2_private.h b/src/lib/evas/cserve2/evas_cs2_private.h index 6acf6f66d4..a2b897b0de 100644 --- a/src/lib/evas/cserve2/evas_cs2_private.h +++ b/src/lib/evas/cserve2/evas_cs2_private.h @@ -4,6 +4,11 @@ #include "evas_common_private.h" #include "evas_cs2.h" +typedef struct _Data_Entry Data_Entry; +typedef struct _Font_Entry Font_Entry; +typedef struct _Index_Table Index_Table; +typedef struct _Shared_Index Shared_Index; + struct _Data_Entry { unsigned int image_id; void (*preloaded_cb)(void *, Eina_Bool); @@ -18,30 +23,38 @@ struct _Data_Entry { } shm; }; -struct _Index_Table { - struct { - char path[64]; - Eina_File *f; - const Shared_Array_Header *header; - const File_Data *entries; - } files; - struct { - char path[64]; - Eina_File *f; - const Shared_Array_Header *header; - const Image_Data *entries; - } images; - struct { - char path[64]; - Eina_File *f; - const Shared_Array_Header *header; - const void *entries; // FIXME - } fonts; +struct _Shared_Index { + char path[64]; + Eina_File *f; + const Shared_Array_Header *header; + union + { + const Index_Entry *index; // TODO for strings + const Image_Data *idata; + const File_Data *fdata; + // TODO Fonts + } entries; + int count; + Eina_Hash *entries_by_hkey; + int last_entry_in_hash; }; -typedef struct _Data_Entry Data_Entry; -typedef struct _Font_Entry Font_Entry; -typedef struct _Index_Table Index_Table; +struct _Index_Table { + // TODO: use Shared_Index + struct { + char index_path[64]; + char entries_path[64]; + Eina_File *index_file; + Eina_File *entries_file; + const Shared_Array_Header *index_header; + const Index_Entry *indexes; + const char *data; + size_t entries_size; + } strings; + Shared_Index files; + Shared_Index images; + Shared_Index fonts; // TODO +}; int evas_cserve2_init(void); int evas_cserve2_shutdown(void);