From 47be3a2b819ed6319a65018195b31b622b547aab Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Mon, 29 Jul 2013 13:08:36 +0900 Subject: [PATCH] evas/cserve2: Prepare shared indexes in clients - Move required struct definitions to common evas_cs2.h - Open/close shm and map arrays to memory Pretty stupid for now as it will close & reopen the shm files even when unchanged. - Check shm size and array header consistency - Implement message send - Send messages from server when calling repack() --- src/bin/evas/evas_cserve2.h | 1 + src/bin/evas/evas_cserve2_cache.c | 49 ++------- src/bin/evas/evas_cserve2_index.c | 13 --- src/bin/evas/evas_cserve2_main.c | 29 +++++ src/lib/evas/cserve2/evas_cs2.h | 68 +++++++++++- src/lib/evas/cserve2/evas_cs2_client.c | 137 ++++++++++++++++++++++++ src/lib/evas/cserve2/evas_cs2_private.h | 23 ++++ 7 files changed, 267 insertions(+), 53 deletions(-) diff --git a/src/bin/evas/evas_cserve2.h b/src/bin/evas/evas_cserve2.h index 1e1a055e21..c91e822b6b 100644 --- a/src/bin/evas/evas_cserve2.h +++ b/src/bin/evas/evas_cserve2.h @@ -233,6 +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); 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); diff --git a/src/bin/evas/evas_cserve2_cache.c b/src/bin/evas/evas_cserve2_cache.c index b1fc2ee8dd..777d35c337 100644 --- a/src/bin/evas/evas_cserve2_cache.c +++ b/src/bin/evas/evas_cserve2_cache.c @@ -14,19 +14,14 @@ #include -typedef int string_t; #define ENTRY Entry base #define ASENTRY(a) (&(a->base)) #define ENTRYID(a) ((a)->base.id) -#define SHMOBJECT unsigned int id; unsigned int refcount typedef struct _Entry Entry; -typedef struct _Shm_Object Shm_Object; typedef struct _Reference Reference; typedef struct _File_Entry File_Entry; -typedef struct _File_Data File_Data; typedef struct _Image_Entry Image_Entry; -typedef struct _Image_Data Image_Data; typedef struct _File_Watch File_Watch; typedef struct _Font_Source Font_Source; @@ -52,46 +47,17 @@ struct _Entry { #endif }; -struct _Shm_Object -{ - SHMOBJECT; -}; - struct _File_Entry { ENTRY; File_Watch *watcher; Eina_List *images; }; -struct _File_Data { - SHMOBJECT; - string_t path; - string_t key; - string_t loader_data; - int w, h; - int frame_count; - int loop_count; - int loop_hint; - Eina_Bool alpha : 1; - Eina_Bool invalid : 1; -}; - - struct _Image_Entry { ENTRY; Shm_Handle *shm; }; -struct _Image_Data { - SHMOBJECT; - unsigned int file_id; - string_t shm_id; - Evas_Image_Load_Opts opts; - Eina_Bool alpha_sparse : 1; - Eina_Bool unused : 1; - Eina_Bool doload : 1; -}; - struct _Font_Source { string_t key; string_t name; @@ -350,12 +316,11 @@ _repack() Shared_Array *sa; int count; - count = cserve2_shared_array_size_get(_file_data_array); - if (count <= 0) return; - // Repack when we have 10% fragmentation over the whole shm buffer - if (_freed_entry_count > 100 || - ((_freed_entry_count * 100) / count >= 10)) + + count = cserve2_shared_array_size_get(_file_data_array); + if ((count > 0) && (_freed_entry_count > 100 || + ((_freed_entry_count * 100) / count >= 10))) { DBG("Repacking file data array: %s", cserve2_shared_array_name_get(_file_data_array)); @@ -373,6 +338,12 @@ _repack() _freed_entry_count = 0; _file_data_array = sa; } + + // FIXME TODO: Repack image data array as well + + cserve2_index_list_send(cserve2_shared_array_name_get(_file_data_array), + cserve2_shared_array_name_get(_image_data_array), + NULL); } diff --git a/src/bin/evas/evas_cserve2_index.c b/src/bin/evas/evas_cserve2_index.c index debaedce53..329ceeb4e2 100644 --- a/src/bin/evas/evas_cserve2_index.c +++ b/src/bin/evas/evas_cserve2_index.c @@ -14,7 +14,6 @@ typedef struct _Data_Shm Data_Shm; typedef struct _Index_Entry Index_Entry; typedef struct _Block Block; -typedef struct _Shared_Array_Header Shared_Array_Header; typedef struct _Shared_Index Shared_Index; static int _instances = 0; @@ -31,18 +30,6 @@ struct _Data_Shm char *data; }; -struct _Shared_Array_Header -{ - int32_t tag; - int32_t elemsize; - int32_t count; - int32_t generation_id; - int32_t emptyidx; - int32_t sortedidx; - int32_t _reserved1; - int32_t _reserved2; -}; - struct _Shared_Array { Data_Shm *ds; diff --git a/src/bin/evas/evas_cserve2_main.c b/src/bin/evas/evas_cserve2_main.c index e77eba2f14..5982c0d297 100644 --- a/src/bin/evas/evas_cserve2_main.c +++ b/src/bin/evas/evas_cserve2_main.c @@ -35,6 +35,35 @@ cserve2_client_error_send(Client *client, unsigned int rid, int error_code) cserve2_client_send(client, &msg, sizeof(msg)); } +void +cserve2_index_list_send(const char *files_index_path, + const char *images_index_path, + const char *fonts_index_path) +{ + Eina_Iterator *iter; + Client *client; + Msg_Index_List msg; + const int size = sizeof(msg); + + memset(&msg, 0, size); + msg.base.type = CSERVE2_INDEX_LIST; + if (files_index_path) + eina_strlcpy(msg.files_index_path, files_index_path, 64); + if (images_index_path) + eina_strlcpy(msg.images_index_path, images_index_path, 64); + 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) + { + 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 _cserve2_client_close(Client *client) { diff --git a/src/lib/evas/cserve2/evas_cs2.h b/src/lib/evas/cserve2/evas_cs2.h index ad36b4e7fe..d47a02aac9 100644 --- a/src/lib/evas/cserve2/evas_cs2.h +++ b/src/lib/evas/cserve2/evas_cs2.h @@ -23,6 +23,7 @@ typedef enum { CSERVE2_FONT_GLYPHS_USED, CSERVE2_STATS, CSERVE2_FONT_DEBUG, + CSERVE2_INDEX_LIST, CSERVE2_ERROR } Message_Type; @@ -224,7 +225,7 @@ struct _Msg_Stats { } images; }; -/* +/** * @struct _Msg_Font_Debug * * Message from server containing all font cache info. @@ -262,6 +263,70 @@ struct _Msg_Font_Debug { Msg_Base base; }; +/** + * @brief The Msg_Index_List struct + * + * Message sent from the server, without request from the client, + * to inform all clients of the shared index files. Contains the paths + * to the latest File, Image and Font index shm. + * + * The paths contain only the filename used in the call to shm_open. + * All strings must be null-terminated. + */ +struct _Msg_Index_List { + Msg_Base base; + char files_index_path[64]; + char images_index_path[64]; + char fonts_index_path[64]; +}; + +typedef struct _Shm_Object Shm_Object; +typedef struct _File_Data File_Data; +typedef struct _Image_Data Image_Data; +typedef struct _Shared_Array_Header Shared_Array_Header; +typedef int string_t; +#define SHMOBJECT unsigned int id; unsigned int refcount + +struct _Shared_Array_Header +{ + int32_t tag; + int32_t elemsize; + int32_t count; + int32_t generation_id; + int32_t emptyidx; + int32_t sortedidx; + int32_t _reserved1; + int32_t _reserved2; +}; + +struct _Shm_Object +{ + SHMOBJECT; +}; + +struct _File_Data { + SHMOBJECT; + string_t path; + string_t key; + string_t loader_data; + int w, h; + int frame_count; + int loop_count; + int loop_hint; + Eina_Bool alpha : 1; + Eina_Bool invalid : 1; +}; + +struct _Image_Data { + SHMOBJECT; + unsigned int file_id; + string_t shm_id; + Evas_Image_Load_Opts opts; + Eina_Bool alpha_sparse : 1; + Eina_Bool unused : 1; + Eina_Bool doload : 1; +}; + struct _Msg_Error { Msg_Base base; int error; @@ -282,6 +347,7 @@ typedef struct _Msg_Font_Glyphs_Loaded Msg_Font_Glyphs_Loaded; typedef struct _Msg_Stats Msg_Stats; typedef struct _Msg_Font_Debug Msg_Font_Debug; typedef struct _Msg_Error Msg_Error; +typedef struct _Msg_Index_List Msg_Index_List; #endif #endif diff --git a/src/lib/evas/cserve2/evas_cs2_client.c b/src/lib/evas/cserve2/evas_cs2_client.c index 9fde9412d8..a52d547386 100644 --- a/src/lib/evas/cserve2/evas_cs2_client.c +++ b/src/lib/evas/cserve2/evas_cs2_client.c @@ -42,6 +42,10 @@ static unsigned int _data_id = 0; static Eina_List *_requests = NULL; +// Shared index table +static Index_Table _index; +static int _server_index_list_set(Msg_Base *data, int size); + #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)NULL)->sun_path) #endif @@ -279,6 +283,8 @@ evas_cserve2_init(void) if (cserve2_init++) return cserve2_init; + memset(&_index, 0, sizeof(_index)); + DBG("Connecting to cserve2."); if (!_server_connect()) { @@ -292,10 +298,13 @@ evas_cserve2_init(void) int evas_cserve2_shutdown(void) { + const char zeros[sizeof(Msg_Index_List)] = {0}; + if ((--cserve2_init) > 0) return cserve2_init; DBG("Disconnecting from cserve2."); + _server_index_list_set((Msg_Base *) zeros, sizeof(Msg_Index_List)); _server_disconnect(); return cserve2_init; @@ -316,6 +325,123 @@ _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) { @@ -333,6 +459,17 @@ _server_dispatch(Eina_Bool *failed) } *failed = EINA_FALSE; + // Special messages (no request) + switch (msg->type) + { + case CSERVE2_INDEX_LIST: + _server_index_list_set(msg, size); + free(msg); + return 0; + default: break; + } + + // Normal client to server requests EINA_LIST_FOREACH_SAFE(_requests, l, l_next, cr) { if (cr->rid != msg->rid) // dispatch this answer diff --git a/src/lib/evas/cserve2/evas_cs2_private.h b/src/lib/evas/cserve2/evas_cs2_private.h index 1cb59a3bdb..6acf6f66d4 100644 --- a/src/lib/evas/cserve2/evas_cs2_private.h +++ b/src/lib/evas/cserve2/evas_cs2_private.h @@ -2,6 +2,7 @@ #define EVAS_CS2_PRIVATE_H 1 #include "evas_common_private.h" +#include "evas_cs2.h" struct _Data_Entry { unsigned int image_id; @@ -17,8 +18,30 @@ 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; +}; + typedef struct _Data_Entry Data_Entry; typedef struct _Font_Entry Font_Entry; +typedef struct _Index_Table Index_Table; int evas_cserve2_init(void); int evas_cserve2_shutdown(void);