evas/cserve2: Store Image_Data in shared array
authorJean-Philippe Andre <jp.andre@samsung.com>
Wed, 24 Jul 2013 05:34:35 +0000 (14:34 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Mon, 28 Oct 2013 06:47:13 +0000 (15:47 +0900)
Split image entries into Image_Data and Image_Entry.
Store, find and use Image_Data descriptors from shared array.
Fix some wrong hash table usages.

src/bin/evas/evas_cserve2.h
src/bin/evas/evas_cserve2_cache.c
src/bin/evas/evas_cserve2_index.c

index 361d08a..1e1a055 100644 (file)
@@ -288,7 +288,7 @@ void cserve2_cache_client_new(Client *client);
 void cserve2_cache_client_del(Client *client);
 int cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid);
 void cserve2_cache_file_close(Client *client, unsigned int client_file_id);
-int cserve2_cache_image_entry_create(Client *client, int rid, unsigned int file_id, unsigned int image_id, Evas_Image_Load_Opts *opts);
+int cserve2_cache_image_entry_create(Client *client, int rid, unsigned int client_file_id, unsigned int image_id, Evas_Image_Load_Opts *opts);
 void cserve2_rgba_image_scale_do(void *src_data, void *dst_data, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int alpha, int smooth);
 void cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid);
 void cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid);
index 8624c08..b8a55c9 100644 (file)
@@ -17,6 +17,7 @@
 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;
@@ -24,6 +25,7 @@ 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;
 
@@ -74,12 +76,17 @@ struct _File_Data {
    Eina_Bool invalid : 1;
 };
 
-// Default values for load options commented below
+
+struct _Image_Entry {
+   ENTRY;
+   Shm_Handle *shm;
+};
+
 struct _Image_Data {
-   Entry base;
+   SHMOBJECT;
    unsigned int file_id;
+   string_t shm_id;
    Evas_Image_Load_Opts opts;
-   Shm_Handle *shm;
    Eina_Bool alpha_sparse : 1;
    Eina_Bool unused : 1;
    Eina_Bool doload : 1;
@@ -178,6 +185,7 @@ static unsigned int _entry_id = 0;
 static unsigned int _freed_entry_count = 0;
 
 static Shared_Array *_file_data_array = NULL;
+static Shared_Array *_image_data_array = NULL;
 
 static Eina_Hash *file_ids = NULL; // maps path + key --> file_id
 static Eina_Hash *file_entries = NULL; // maps file_id --> entry
@@ -262,7 +270,7 @@ _shm_object_id_cmp_cb(const void *data1, const void *data2)
      return +1;
 }
 
-static inline File_Data *
+static File_Data *
 _file_data_find(unsigned int file_id)
 {
    File_Data *fd;
@@ -276,10 +284,11 @@ _file_data_find(unsigned int file_id)
      }
    else if (!fd)
      ERR("Could not find file %u", file_id);
+
    return fd;
 }
 
-static inline File_Entry *
+static File_Entry *
 _file_entry_find(unsigned int entry_id)
 {
    Entry *e;
@@ -291,6 +300,36 @@ _file_entry_find(unsigned int entry_id)
    return (File_Entry *) e;
 }
 
+static Image_Data *
+_image_data_find(unsigned int image_id)
+{
+   Image_Data *idata;
+
+   idata = cserve2_shared_array_item_data_find(_image_data_array, &image_id,
+                                               _shm_object_id_cmp_cb);
+   if (idata && !idata->refcount)
+     {
+        ERR("Can not access object %u with refcount 0", image_id);
+        return NULL;
+     }
+   else if (!idata)
+     ERR("Could not find image %u", image_id);
+
+   return idata;
+}
+
+static Image_Entry *
+_image_entry_find(unsigned int entry_id)
+{
+   Entry *e;
+
+   e = (Entry *) eina_hash_find(image_entries, &entry_id);
+   if (!e || e->type != CSERVE2_IMAGE_DATA)
+     return NULL;
+
+   return (Image_Entry *) e;
+}
+
 static Eina_Bool
 _repack_skip_cb(Shared_Array *sa EINA_UNUSED, const void *elem,
                 void *user_data EINA_UNUSED)
@@ -369,10 +408,10 @@ _image_opened_send(Client *client, File_Data *fd, unsigned int rid)
 }
 
 static Msg_Loaded *
-_image_loaded_msg_create(Image_Data *entry, int *size)
+_image_loaded_msg_create(Image_Entry *ientry, Image_Data *idata, int *size)
 {
    Msg_Loaded *msg;
-   const char *shmpath = cserve2_shm_name_get(entry->shm);
+   const char *shmpath = cserve2_shm_name_get(ientry->shm);
    int path_len;
    char *buf;
 
@@ -382,11 +421,11 @@ _image_loaded_msg_create(Image_Data *entry, int *size)
    msg = calloc(1, *size);
    msg->base.type = CSERVE2_LOADED;
 
-   msg->shm.mmap_offset = cserve2_shm_map_offset_get(entry->shm);
-   msg->shm.use_offset = cserve2_shm_offset_get(entry->shm);
-   msg->shm.mmap_size = cserve2_shm_map_size_get(entry->shm);
-   msg->shm.image_size = cserve2_shm_size_get(entry->shm);
-   msg->alpha_sparse = entry->alpha_sparse;
+   msg->shm.mmap_offset = cserve2_shm_map_offset_get(ientry->shm);
+   msg->shm.use_offset = cserve2_shm_offset_get(ientry->shm);
+   msg->shm.mmap_size = cserve2_shm_map_size_get(ientry->shm);
+   msg->shm.image_size = cserve2_shm_size_get(ientry->shm);
+   msg->alpha_sparse = idata->alpha_sparse;
 
    buf = (char *)msg + sizeof(*msg);
    memcpy(buf, shmpath, path_len);
@@ -395,14 +434,15 @@ _image_loaded_msg_create(Image_Data *entry, int *size)
 }
 
 static void
-_image_loaded_send(Client *client, Image_Data *entry, unsigned int rid)
+_image_loaded_send(Client *client, Image_Entry *ientry, Image_Data *idata,
+                   unsigned int rid)
 {
    int size;
    Msg_Loaded *msg;
 
-   DBG("Sending LOADED reply for entry %d and RID: %d.", entry->base.id, rid);
+   DBG("Sending LOADED reply for entry %d and RID: %d.", idata->id, rid);
 
-   msg = _image_loaded_msg_create(entry, &size);
+   msg = _image_loaded_msg_create(ientry, idata, &size);
    msg->base.rid = rid;
 
    cserve2_client_send(client, &size, sizeof(size));
@@ -438,6 +478,9 @@ _open_request_build(Entry *entry, int *bufsize)
    Slave_Msg_Image_Open msg;
    File_Data *fd;
 
+   if (!entry || entry->type != CSERVE2_IMAGE_FILE)
+     return NULL;
+
    fd = _file_data_find(entry->id);
    if (!fd)
      {
@@ -541,7 +584,7 @@ static Slave_Request_Funcs _open_funcs = {
 };
 
 static void *
-_load_request_build(Image_Data *i, int *bufsize)
+_load_request_build(Image_Entry *ientry, int *bufsize)
 {
    char *buf, *ptr;
    const char *shmpath, *loader_data;
@@ -549,21 +592,29 @@ _load_request_build(Image_Data *i, int *bufsize)
    int shmlen, filelen, keylen, loaderlen;
    Slave_Msg_Image_Load msg;
    File_Data *fd;
+   Image_Data *idata;
+
+   idata = _image_data_find(ENTRYID(ientry));
+   if (!idata || !idata->refcount)
+     {
+        ERR("Image data not found for entry %u", ENTRYID(ientry));
+        return NULL;
+     }
 
-   fd = _file_data_find(i->file_id);
+   fd = _file_data_find(idata->file_id);
    if (!fd)
      {
-        ERR("Could not find file data %u for image %u", i->file_id, i->base.id);
+        ERR("Could not find file data %u for image %u",
+            idata->file_id, idata->id);
         return NULL;
      }
 
    // opening shm for this file
-   i->shm = cserve2_shm_request("img", fd->w * fd->h * 4);
-   if (!i->shm)
+   ientry->shm = cserve2_shm_request("img", fd->w * fd->h * 4);
+   if (!ientry->shm)
      return NULL;
 
-   shmpath = cserve2_shm_name_get(i->shm);
-
+   shmpath = cserve2_shm_name_get(ientry->shm);
    shmlen = strlen(shmpath) + 1;
    filelen = strlen(cserve2_shared_string_get(fd->path)) + 1;
    keylen = strlen(cserve2_shared_string_get(fd->key)) + 1;
@@ -583,18 +634,18 @@ _load_request_build(Image_Data *i, int *bufsize)
    msg.alpha = fd->alpha;
 
    // NOTE: Not passing scale_load options
-   msg.opts.w = i->opts.w;
-   msg.opts.h = i->opts.h;
-   msg.opts.region = i->opts.region;
-   msg.opts.scale_down_by = i->opts.scale_down_by;
-   msg.opts.dpi = i->opts.dpi;
-   msg.opts.degree = i->opts.degree;
-   msg.opts.orientation = i->opts.orientation;
-
-   msg.shm.mmap_offset = cserve2_shm_map_offset_get(i->shm);
-   msg.shm.image_offset = cserve2_shm_offset_get(i->shm);
-   msg.shm.mmap_size = cserve2_shm_map_size_get(i->shm);
-   msg.shm.image_size = cserve2_shm_size_get(i->shm);
+   msg.opts.w = idata->opts.w;
+   msg.opts.h = idata->opts.h;
+   msg.opts.region = idata->opts.region;
+   msg.opts.scale_down_by = idata->opts.scale_down_by;
+   msg.opts.dpi = idata->opts.dpi;
+   msg.opts.degree = idata->opts.degree;
+   msg.opts.orientation = idata->opts.orientation;
+
+   msg.shm.mmap_offset = cserve2_shm_map_offset_get(ientry->shm);
+   msg.shm.image_offset = cserve2_shm_offset_get(ientry->shm);
+   msg.shm.mmap_size = cserve2_shm_map_size_get(ientry->shm);
+   msg.shm.image_size = cserve2_shm_size_get(ientry->shm);
 
    msg.has_loader_data = !!loaderlen;
 
@@ -611,31 +662,31 @@ _load_request_build(Image_Data *i, int *bufsize)
 
    *bufsize = size;
 
-   _entry_load_start(&i->base);
+   _entry_load_start(&ientry->base);
 
    return buf;
 }
 
 static inline Eina_Bool
-_scaling_needed(Image_Data *entry, Slave_Msg_Image_Loaded *resp)
+_scaling_needed(Image_Data *idata, Slave_Msg_Image_Loaded *resp)
 {
-   return (((entry->opts.scale_load.dst_w) && (entry->opts.scale_load.dst_h)) &&
-           ((entry->opts.scale_load.dst_w != resp->w) ||
-            (entry->opts.scale_load.dst_h != resp->h)));
+   return (((idata->opts.scale_load.dst_w) && (idata->opts.scale_load.dst_h)) &&
+           ((idata->opts.scale_load.dst_w != resp->w) ||
+            (idata->opts.scale_load.dst_h != resp->h)));
 }
 
 static int
-_scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
+_scaling_do(Shm_Handle *scale_shm, Image_Data *idata, Image_Entry *original)
 {
    char *scale_map, *orig_map;
    void *src_data, *dst_data;
    File_Data *fd;
 
-   fd = _file_data_find(entry->file_id);
+   fd = _file_data_find(idata->file_id);
    if (!fd)
      {
         ERR("Could not find file data %u for image %u",
-            entry->file_id, entry->base.id);
+            idata->file_id, idata->id);
         return -1;
      }
 
@@ -659,17 +710,18 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
    dst_data = scale_map + cserve2_shm_map_offset_get(scale_shm);
 
    DBG("Scaling image ([%d,%d:%dx%d] --> [%d,%d:%dx%d])",
-       entry->opts.scale_load.src_x, entry->opts.scale_load.src_y,
-       entry->opts.scale_load.src_w, entry->opts.scale_load.src_h,
+       idata->opts.scale_load.src_x, idata->opts.scale_load.src_y,
+       idata->opts.scale_load.src_w, idata->opts.scale_load.src_h,
        0, 0,
-       entry->opts.scale_load.dst_w, entry->opts.scale_load.dst_h);
+       idata->opts.scale_load.dst_w, idata->opts.scale_load.dst_h);
 
-   cserve2_rgba_image_scale_do(src_data, dst_data,
-                               entry->opts.scale_load.src_x, entry->opts.scale_load.src_y,
-                               entry->opts.scale_load.src_w, entry->opts.scale_load.src_h,
-                               0, 0,
-                               entry->opts.scale_load.dst_w, entry->opts.scale_load.dst_h,
-                               fd->alpha, entry->opts.scale_load.smooth);
+   cserve2_rgba_image_scale_do(
+            src_data, dst_data,
+            idata->opts.scale_load.src_x, idata->opts.scale_load.src_y,
+            idata->opts.scale_load.src_w, idata->opts.scale_load.src_h,
+            0, 0,
+            idata->opts.scale_load.dst_w, idata->opts.scale_load.dst_h,
+            fd->alpha, idata->opts.scale_load.smooth);
 
    cserve2_shm_unmap(original->shm);
    cserve2_shm_unmap(scale_shm);
@@ -678,51 +730,64 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
 }
 
 static int
-_scaling_prepare_and_do(Image_Data *orig)
+_scaling_prepare_and_do(Image_Entry *ientry, Image_Data *idata)
 {
    Shm_Handle *scale_shm;
 
-   DBG("Original image's shm path %s", cserve2_shm_name_get(orig->shm));
+   scale_shm = cserve2_shm_request("img", idata->opts.scale_load.dst_w
+                                   * idata->opts.scale_load.dst_h * 4);
 
-   scale_shm = cserve2_shm_request(
-            "img",
-            orig->opts.scale_load.dst_w * orig->opts.scale_load.dst_h * 4);
+   if (!scale_shm)
+     return -1;
 
-   DBG("Scale image's shm path %s", cserve2_shm_name_get(scale_shm));
+   DBG("Scaling image from shm %s to shm %s",
+       cserve2_shm_name_get(ientry->shm), cserve2_shm_name_get(scale_shm));
 
-   if (_scaling_do(scale_shm, orig, orig)) return -1;
+   if (_scaling_do(scale_shm, idata, ientry) != 0)
+     return -1;
 
-   cserve2_shm_unref(orig->shm); /* unreference old shm */
-   orig->shm = scale_shm; /* update shm */
+   // Switch shm in original image
+   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));
 
    return 0;
 }
 
 static Msg_Loaded *
-_load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp, int *size)
+_load_request_response(Image_Entry *ientry,
+                       Slave_Msg_Image_Loaded *resp, int *size)
 {
-   _entry_load_finish(&e->base);
+   Image_Data *idata;
+
+   idata = _image_data_find(ENTRYID(ientry));
+   if (!idata)
+     {
+        ERR("Image data %u not found", ENTRYID(ientry));
+        return NULL;
+     }
 
-   e->base.request = NULL;
+   _entry_load_finish(ASENTRY(ientry));
+   ASENTRY(ientry)->request = NULL;
 
-   e->alpha_sparse = resp->alpha_sparse;
-   if (!e->doload)
-     DBG("Entry %d loaded by speculative preload.", e->base.id);
+   idata->alpha_sparse = resp->alpha_sparse;
+   if (!idata->doload)
+     DBG("Entry %d loaded by speculative preload.", idata->id);
 
-   if (_scaling_needed(e, resp))
+   if (_scaling_needed(idata, resp))
      {
+        DBG("About to scale image %u", idata->id);
 
-        DBG("About to scale down image %u", ASENTRY(e)->id);
-
-        if (!_scaling_prepare_and_do(e))
-          DBG("Image %u has been scaled down.", ASENTRY(e)->id);
+        if (!_scaling_prepare_and_do(ientry, idata))
+          DBG("Image %u has been scaled.", idata->id);
         else
-          ERR("Failed to scale down image %u", ASENTRY(e)->id);
+          ERR("Failed to scale image %u", idata->id);
      }
    else
-     DBG("No scaling needed for image %u", ASENTRY(e)->id);
+     DBG("No scaling needed for image %u", idata->id);
 
-   return _image_loaded_msg_create(e, size);
+   return _image_loaded_msg_create(ientry, idata, size);
 }
 
 static Slave_Request_Funcs _load_funcs = {
@@ -732,11 +797,14 @@ static Slave_Request_Funcs _load_funcs = {
    .error = (Slave_Request_Error)_request_failed
 };
 
-static unsigned int
-_img_opts_id_get(unsigned int file_id, Evas_Image_Load_Opts *opts,
-                 char *buf, int size)
+static void
+_image_key_set(unsigned int file_id, const Evas_Image_Load_Opts *opts,
+               char *buf, int size)
 {
-   uintptr_t image_id;
+   const char empty[sizeof(Evas_Image_Load_Opts)] = {0};
+
+   if (!opts)
+     opts = (Evas_Image_Load_Opts *) &empty;
 
    snprintf(buf, size,
             "%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:!([%d,%d:%dx%d]-[%dx%d:%d]):%d:%d",
@@ -748,25 +816,27 @@ _img_opts_id_get(unsigned int file_id, Evas_Image_Load_Opts *opts,
             opts->scale_load.dst_w, opts->scale_load.dst_h,
             opts->scale_load.smooth, opts->degree,
             opts->orientation);
-
-   image_id = (uintptr_t)eina_hash_find(image_ids, buf);
-
-   return image_id;
 }
 
 static unsigned int
-_image_data_opts_id_get(Image_Data *im, char *buf, int size)
+_image_opts_id_get(unsigned int file_id, Evas_Image_Load_Opts *opts,
+                   char *buf, int size)
 {
-   return _img_opts_id_get(im->file_id, &im->opts, buf, size);
+   uintptr_t image_id;
+
+   _image_key_set(file_id, opts, buf, size);
+   image_id = (uintptr_t) eina_hash_find(image_ids, buf);
+
+   return (unsigned int) image_id;
 }
 
 static int
-_image_entry_size_get(Image_Data *e)
+_image_entry_size_get(Image_Entry *ientry)
 {
    int size = sizeof(Image_Data);
    /* XXX: get the overhead of the shm handler too */
-   if (e->shm)
-     size += cserve2_shm_size_get(e->shm);
+   if (ientry->shm)
+     size += cserve2_shm_size_get(ientry->shm);
    return size / 1024;
 }
 
@@ -785,54 +855,75 @@ _file_id_free(File_Data *fd)
 }
 
 static void
-_image_id_free(Image_Data *entry)
+_image_id_free(Image_Data *idata)
 {
    char buf[4096];
 
-   DBG("Removing entry image id: %d", entry->base.id);
+   DBG("Removing entry image id: %d", idata->id);
 
-   _image_data_opts_id_get(entry, buf, sizeof(buf));
+   _image_opts_id_get(idata->file_id, &idata->opts, buf, sizeof(buf));
    eina_hash_del_by_key(image_ids, buf);
 }
 
 static void
-_image_entry_free(Image_Data *entry)
+_image_entry_free(Image_Entry *ientry)
 {
    File_Data *fd;
    File_Entry *fentry;
+   Image_Data *idata;
 
-   if (entry->base.request)
-     cserve2_request_cancel_all(entry->base.request, CSERVE2_REQUEST_CANCEL);
+   idata = _image_data_find(ENTRYID(ientry));
+   if (!idata || !idata->refcount)
+     {
+        CRIT("Trying to free already freed object: %u", ENTRYID(ientry));
+        return;
+     }
 
-   if (entry->unused)
+   if (--idata->refcount > 0)
+     return;
+
+   if (ientry->base.request)
+     cserve2_request_cancel_all(ientry->base.request,
+                                CSERVE2_REQUEST_CANCEL);
+
+   if (idata->unused)
      {
-        image_entries_lru = eina_list_remove(image_entries_lru, entry);
-        unused_mem_usage -= _image_entry_size_get(entry);
+        image_entries_lru = eina_list_remove(image_entries_lru, ientry);
+        unused_mem_usage -= _image_entry_size_get(ientry);
      }
 
-   fd = _file_data_find(entry->file_id);
+   fd = _file_data_find(idata->file_id);
    if (fd)
      {
         fentry = _file_entry_find(fd->id);
-        fentry->images = eina_list_remove(fentry->images, entry);
+        fentry->images = eina_list_remove(fentry->images, ientry);
         if (fentry && !fentry->images && !ASENTRY(fentry)->references)
           eina_hash_del_by_key(file_entries, &fd->id);
      }
    else
-     ERR("Could not find file data %u for image %u",
-         entry->file_id, ASENTRY(entry)->id);
-   if (entry->shm)
-     cserve2_shm_unref(entry->shm);
-   free(entry);
+      ERR("Could not find file data %u for image %u",
+          idata->file_id, idata->id);
+
+   if (ientry->shm)
+     cserve2_shm_unref(ientry->shm);
+   cserve2_shared_string_del(idata->shm_id);
+   idata->shm_id = 0;
+   free(ientry);
 }
 
 static void
 _hash_image_entry_free(void *data)
 {
-   Image_Data *entry = data;
+   Image_Entry *ientry = data;
+   Image_Data *idata;
 
-   _image_id_free(entry);
-   _image_entry_free(entry);
+   idata = _image_data_find(ENTRYID(ientry));
+   if (idata && idata->refcount > 0)
+     {
+        _image_id_free(idata);
+        _image_entry_free(ientry);
+     }
+   else ERR("Could not find image entry %u", ENTRYID(ientry));
 }
 
 static void
@@ -847,7 +938,7 @@ _file_entry_free(File_Entry *fentry)
 
    if (fentry->images)
      {
-        ERR("Freeing file %u image data still referenced.", ASENTRY(fentry)->id);
+        ERR("Freeing file %u image data still referenced.", ENTRYID(fentry));
         eina_list_free(fentry->images);
      }
    if (ASENTRY(fentry)->request)
@@ -886,7 +977,7 @@ _hash_file_entry_free(void *data)
    // TODO: Add some checks to make sure that we are freeing an
    // unused entry.
 
-   fd = _file_data_find(ASENTRY(fentry)->id);
+   fd = _file_data_find(ENTRYID(fentry));
    _file_id_free(fd);
    _file_data_free(fd);
    _file_entry_free(fentry);
@@ -1046,7 +1137,7 @@ cserve2_cache_init(void)
    file_ids = eina_hash_string_superfast_new(NULL);
    file_entries = eina_hash_int32_new(_hash_file_entry_free);
    image_ids = eina_hash_string_superfast_new(NULL);
-   image_entries = eina_hash_string_superfast_new(_hash_image_entry_free);
+   image_entries = eina_hash_int32_new(_hash_image_entry_free);
    file_watch = eina_hash_string_superfast_new(_file_watch_free);
 
    font_sources = eina_hash_string_small_new(EINA_FREE_CB(_font_source_free));
@@ -1057,6 +1148,7 @@ cserve2_cache_init(void)
                                 5);
 
    _file_data_array = cserve2_shared_array_new(1, sizeof(File_Data), 0);
+   _image_data_array = cserve2_shared_array_new(1, sizeof(Image_Data), 0);
 }
 
 void
@@ -1077,6 +1169,7 @@ cserve2_cache_shutdown(void)
    eina_hash_free(font_sources);
 
    cserve2_shared_array_del(_file_data_array);
+   cserve2_shared_array_del(_image_data_array);
 }
 
 static Reference *
@@ -1096,25 +1189,29 @@ _entry_reference_add(Entry *entry, Client *client, unsigned int client_entry_id)
 }
 
 static void
-_entry_unused_push(Image_Data *e)
+_entry_unused_push(Image_Entry *ientry)
 {
-   int size = _image_entry_size_get(e);
+   Image_Data *idata;
+   int size;
 
-   if ((size > max_unused_mem_usage) || !(e->doload))
+   idata = _image_data_find(ENTRYID(ientry));
+
+   size = _image_entry_size_get(ientry);
+   if ((size > max_unused_mem_usage) || !(idata->doload))
      {
-        eina_hash_del_by_key(image_entries, &e->base.id);
+        eina_hash_del_by_key(image_entries, &idata->id);
         return;
      }
    while (image_entries_lru &&
           (size > (max_unused_mem_usage - unused_mem_usage)))
      {
-        Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
-        Eina_Bool ok = eina_hash_del_by_key(image_entries, &ie->id);
+        Image_Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
+        Eina_Bool ok = eina_hash_del_by_key(image_entries, &(ENTRYID(ie)));
         if (!ok)
           {
-             DBG("Image %d was not found in the hash table!", ie->id);
+             DBG("Image %d was not found in the hash table!", ENTRYID(ie));
              image_entries_lru = eina_list_remove(image_entries_lru, ie);
-             _image_entry_free((Image_Data*) ie);
+             _image_entry_free(ie);
           }
      }
    if (!image_entries_lru && (unused_mem_usage != 0))
@@ -1123,8 +1220,8 @@ _entry_unused_push(Image_Data *e)
             unused_mem_usage);
         unused_mem_usage = 0;
      }
-   image_entries_lru = eina_list_append(image_entries_lru, e);
-   e->unused = EINA_TRUE;
+   image_entries_lru = eina_list_append(image_entries_lru, ientry);
+   idata->unused = EINA_TRUE;
    unused_mem_usage += size;
 }
 
@@ -1154,15 +1251,20 @@ _entry_reference_del(Entry *entry, Reference *ref)
      }
    else if (entry->type == CSERVE2_IMAGE_DATA)
      {
-        Image_Data *ientry = (Image_Data *) entry;
-        File_Data *fd = _file_data_find(entry->id);
+        Image_Entry *ientry = (Image_Entry *) entry;
+        Image_Data *idata = _image_data_find(entry->id);
 
-        if (!fd)
+        if (!idata || !idata->file_id)
           eina_hash_del_by_key(image_entries, &entry->id);
-        else if (fd->invalid)
-          _image_entry_free(ientry);
         else
-          _entry_unused_push(ientry);
+          {
+             File_Data *fdata = _file_data_find(idata->file_id);
+
+             if (fdata->invalid)
+               _image_entry_free(ientry);
+             else
+               _entry_unused_push(ientry);
+          }
      }
    else if (entry->type == CSERVE2_FONT_ENTRY)
      {
@@ -1249,14 +1351,17 @@ cserve2_cache_client_del(Client *client)
      }
 }
 
-static Image_Data *
+static Image_Entry *
 _image_entry_new(Client *client, int rid,
-                 unsigned int client_file_id, unsigned int image_id,
-                 Evas_Image_Load_Opts *opts)
+                 unsigned int client_file_id, unsigned int client_image_id,
+                 Evas_Image_Load_Opts *opts, char *buf)
 {
-   Reference *ref;
-   Image_Data *im_entry;
+   Reference *ref, *oldref;
+   Image_Entry *ientry;
+   Image_Data *idata;
    File_Data *fd;
+   int idata_id;
+   unsigned int image_id;
 
    ref = eina_hash_find(client->files.referencing, &client_file_id);
    if (!ref)
@@ -1275,32 +1380,62 @@ _image_entry_new(Client *client, int rid,
         return NULL;
      }
 
-   im_entry = calloc(1, sizeof(*im_entry));
-   im_entry->base.type = CSERVE2_IMAGE_DATA;
-   im_entry->file_id = ref->entry->id;
+   idata_id = cserve2_shared_array_item_new(_image_data_array);
+   idata = cserve2_shared_array_item_data_get(_image_data_array, idata_id);
+   if (idata_id < 0 || !idata)
+     {
+        ERR("Could not create new image entry in shared array");
+        cserve2_client_error_send(client, rid,
+                                  CSERVE2_RESOURCE_ALLOCATION_FAILED);
+        return NULL;
+     }
+
+   image_id = ++_entry_id;
+   while (eina_hash_find(image_entries, &image_id))
+     image_id = ++_entry_id;
+
+   DBG("Creating new image entry: %u at index %d in shm %s",
+       image_id, idata_id, cserve2_shared_array_name_get(_image_data_array));
+
+   ientry = calloc(1, sizeof(*ientry));
+   ientry->base.id = image_id;
+   ientry->base.type = CSERVE2_IMAGE_DATA;
    if (opts)
      {
-        im_entry->opts.dpi = opts->dpi;
-        im_entry->opts.w = opts->w;
-        im_entry->opts.h = opts->h;
-        im_entry->opts.scale_down_by = opts->scale_down_by;
-        im_entry->opts.region.x = opts->region.x;
-        im_entry->opts.region.y = opts->region.y;
-        im_entry->opts.region.w = opts->region.w;
-        im_entry->opts.region.h = opts->region.h;
-        im_entry->opts.scale_load.src_x = opts->scale_load.src_x;
-        im_entry->opts.scale_load.src_y = opts->scale_load.src_y;
-        im_entry->opts.scale_load.src_w = opts->scale_load.src_w;
-        im_entry->opts.scale_load.src_h = opts->scale_load.src_h;
-        im_entry->opts.scale_load.dst_w = opts->scale_load.dst_w;
-        im_entry->opts.scale_load.dst_h = opts->scale_load.dst_h;
-        im_entry->opts.scale_load.smooth = opts->scale_load.smooth;
-        im_entry->opts.scale_load.scale_hint = opts->scale_load.scale_hint;
-        im_entry->opts.degree = opts->degree;
-        im_entry->opts.orientation = opts->orientation;
-     }
-
-   return im_entry;
+        idata->opts.dpi = opts->dpi;
+        idata->opts.w = opts->w;
+        idata->opts.h = opts->h;
+        idata->opts.scale_down_by = opts->scale_down_by;
+        idata->opts.region.x = opts->region.x;
+        idata->opts.region.y = opts->region.y;
+        idata->opts.region.w = opts->region.w;
+        idata->opts.region.h = opts->region.h;
+        idata->opts.scale_load.src_x = opts->scale_load.src_x;
+        idata->opts.scale_load.src_y = opts->scale_load.src_y;
+        idata->opts.scale_load.src_w = opts->scale_load.src_w;
+        idata->opts.scale_load.src_h = opts->scale_load.src_h;
+        idata->opts.scale_load.dst_w = opts->scale_load.dst_w;
+        idata->opts.scale_load.dst_h = opts->scale_load.dst_h;
+        idata->opts.scale_load.smooth = opts->scale_load.smooth;
+        idata->opts.scale_load.scale_hint = opts->scale_load.scale_hint;
+        idata->opts.degree = opts->degree;
+        idata->opts.orientation = opts->orientation;
+     }
+   idata->file_id = ref->entry->id;
+   idata->refcount = 1;
+   idata->id = image_id;
+
+   _image_key_set(idata->file_id, opts, buf, sizeof(buf));
+   eina_hash_add(image_entries, &image_id, ientry);
+   eina_hash_add(image_ids, buf, (void *)(intptr_t) image_id);
+
+   oldref = eina_hash_find(client->images.referencing, &client_image_id);
+   ref = _entry_reference_add(ASENTRY(ientry), client, client_image_id);
+   if (oldref)
+     eina_hash_del_by_key(client->images.referencing, &client_image_id);
+   eina_hash_add(client->images.referencing, &client_image_id, ref);
+
+   return ientry;
 }
 
 static void
@@ -1313,7 +1448,7 @@ _file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, vo
    EINA_LIST_FOREACH(fw->entries, l, fd)
      {
         Eina_List *ll;
-        Image_Data *ie;
+        Image_Entry *ie;
         File_Entry *fentry;
 
         fd->invalid = EINA_TRUE;
@@ -1328,14 +1463,22 @@ _file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, vo
 
         EINA_LIST_FOREACH(fentry->images, ll, ie)
           {
-             _image_id_free(ie);
-             eina_hash_set(image_entries, &ie->base.id, NULL);
-             if (ie->base.request /*&& !ie->base.request->processing*/)
-               cserve2_request_cancel_all(ie->base.request,
+             Image_Data *idata;
+
+             eina_hash_set(image_entries, &ENTRYID(ie), NULL);
+             if (ASENTRY(ie)->request /*&& !ie->base.request->processing*/)
+               cserve2_request_cancel_all(ASENTRY(ie)->request,
                                           CSERVE2_FILE_CHANGED);
-             ie->base.request = NULL;
-             if (ie->unused)
-               _image_entry_free(ie);
+             ASENTRY(ie)->request = NULL;
+
+             idata = _image_data_find(ENTRYID(ie));
+             if (idata)
+               {
+                  _image_id_free(idata);
+                  if (idata->unused)
+                    _image_entry_free(ie);
+               }
+             else ERR("Image data %u not found", ENTRYID(ie));
           }
 
         _file_id_free(fd);
@@ -1947,29 +2090,32 @@ static Eina_Bool
 _image_data_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
 {
    Msg_Stats *msg = fdata;
-   Image_Data *id = data;
+   Image_Entry *ientry = data;
+   Image_Data *idata;
    File_Data *fd;
 
+   idata = _image_data_find(ENTRYID(ientry));
+
    // accounting numbers
    msg->images.images_loaded++;
-   if (id->unused) msg->images.images_unused++;
+   if (idata->unused) msg->images.images_unused++;
 
    // accounting size
-   msg->images.images_size += _image_entry_size_get(id) * 1024;
-   if (id->unused) msg->images.unused_size += _image_entry_size_get(id) * 1024;
+   msg->images.images_size += _image_entry_size_get(ientry) * 1024;
+   if (idata->unused) msg->images.unused_size += _image_entry_size_get(ientry) * 1024;
 
-   fd = _file_data_find(id->file_id);
+   fd = _file_data_find(idata->file_id);
    if (fd)
      {
         unsigned int image_size = fd->w * fd->h * 4;
         msg->images.requested_size +=
-              (image_size * eina_list_count(id->base.references));
+              (image_size * eina_list_count(ASENTRY(ientry)->references));
      }
 
 #ifdef DEBUG_LOAD_TIME
    // accounting image entries load time
-   msg->images.images_load_time += id->base.load_time;
-   msg->images.images_saved_time += id->base.saved_time;
+   msg->images.images_load_time += ASENTRY(ientry)->load_time;
+   msg->images.images_saved_time += ASENTRY(ientry)->saved_time;
 #endif
 
    return EINA_TRUE;
@@ -2341,11 +2487,11 @@ cserve2_cache_file_close(Client *client, unsigned int client_file_id)
 }
 
 static int
-_cserve2_cache_fast_scaling_check(Client *client, Image_Data *entry)
+_cserve2_cache_fast_scaling_check(Client *client, Image_Entry *ientry)
 {
    Eina_Iterator *iter;
    Image_Data *i;
-   Image_Data *original = NULL;
+   Image_Entry *original = NULL;
    Evas_Image_Load_Opts unscaled;
    char buf[4096];
    unsigned int image_id;
@@ -2353,8 +2499,13 @@ _cserve2_cache_fast_scaling_check(Client *client, Image_Data *entry)
    int dst_w, dst_h;
    Eina_Bool first_attempt = EINA_TRUE;
    File_Entry *fentry;
+   Image_Data *idata;
+
+#warning NOT IMPLEMENTED. PLEASE REIMLPEMENT.
+   return -1;
+#if 0
 
-   if (!entry) return -1;
+   if (!ientry || !idata) return -1;
 
    dst_w = entry->opts.scale_load.dst_w;
    dst_h = entry->opts.scale_load.dst_h;
@@ -2375,7 +2526,7 @@ _cserve2_cache_fast_scaling_check(Client *client, Image_Data *entry)
    unscaled.scale_load.smooth = entry->opts.scale_load.smooth;
 
 try_again:
-   image_id = _img_opts_id_get(entry->file_id, &unscaled, buf, sizeof(buf));
+   image_id = _image_opts_id_get(entry->file_id, &unscaled, buf, sizeof(buf));
    if (image_id)
      {
         original = eina_hash_find(image_entries, &image_id);
@@ -2430,12 +2581,7 @@ try_again:
                                          0, &unscaled);
              if (!original) return -1;
 
-             image_id = ++_entry_id;
-             while ((image_id == 0) || (eina_hash_find(image_entries, &image_id)))
-               image_id = ++_entry_id;
-             DBG("Creating new image_id: %d", image_id);
-
-             original->base.id = image_id;
+             // NOTE: NOT NEEDED ANYMORE. FIXME
              eina_hash_add(image_entries, &image_id, original);
              eina_hash_add(image_ids, buf, (void *)(intptr_t)image_id);
              _entry_unused_push(original);
@@ -2478,95 +2624,95 @@ do_scaling:
         image_entries_lru = eina_list_prepend(image_entries_lru, original);
      }
    return 0;
+#endif
 }
 
 int
 cserve2_cache_image_entry_create(Client *client, int rid,
-                                 unsigned int file_id,
+                                 unsigned int client_file_id,
                                  unsigned int client_image_id,
                                  Evas_Image_Load_Opts *opts)
 {
-   Image_Data *entry;
-   Reference *ref, *oldref;
+   Image_Data *idata;
+   Image_Entry *ientry;
+   Reference *ref;
    File_Entry *fentry;
-   unsigned int image_id;
+   unsigned int image_id = 0;
    char buf[4096];
 
-   oldref = eina_hash_find(client->images.referencing, &client_image_id);
-
    // search whether the image is already loaded by another client
-   entry = _image_entry_new(client, rid, file_id, client_image_id, opts);
-   if (!entry)
-     return -1;
-   image_id = _image_data_opts_id_get(entry, buf, sizeof(buf));
+   ref = eina_hash_find(client->files.referencing, &client_file_id);
+   if (ref && opts)
+     image_id = _image_opts_id_get(ref->entry->id, opts, buf, sizeof(buf));
+
    if (image_id)
-     {  // if so, just update the references
-        free(entry);
+     {
+        // Just update the references
+        Reference *oldref;
+
         DBG("found image_id %d for client image id %d",
             image_id, client_image_id);
-        entry = eina_hash_find(image_entries, &image_id);
-        if (!entry)
+        ientry = _image_entry_find(image_id);
+        idata = _image_data_find(image_id);
+        if (!ientry || !idata)
           {
-             ERR("image id %d is in file_ids hash, but not in entries hash"
-                 "with entry id %d.", client_image_id, image_id);
+             ERR("image entry %d (client id: %d) corrupted: entry %p data %p",
+                 image_id, client_image_id, ientry, idata);
              cserve2_client_error_send(client, rid, CSERVE2_INVALID_CACHE);
              return -1;
           }
 
-        if (entry->unused)
+        // FIXME: This might be broken (wrt. refcounting)
+        if (idata->unused)
           {
              DBG("Re-using old image entry (id: %d) from the LRU list.",
-                 entry->base.id);
-             entry->unused = EINA_FALSE;
-             image_entries_lru = eina_list_remove(image_entries_lru, entry);
-             unused_mem_usage -= _image_entry_size_get(entry);
+                 ientry->base.id);
+             idata->unused = EINA_FALSE;
+             idata->refcount++;
+             image_entries_lru = eina_list_remove(image_entries_lru, ientry);
+             unused_mem_usage -= _image_entry_size_get(ientry);
           }
-        _entry_load_reused(&entry->base);
+        _entry_load_reused(&ientry->base);
 
+        oldref = eina_hash_find(client->images.referencing, &client_image_id);
         if (oldref && (oldref->entry->id == image_id))
           return 0;
 
-        ref = _entry_reference_add((Entry *)entry, client, client_image_id);
-
+        ref = _entry_reference_add(ASENTRY(ientry), client, client_image_id);
         if (oldref)
           eina_hash_del_by_key(client->images.referencing, &client_image_id);
-
         eina_hash_add(client->images.referencing, &client_image_id, ref);
+
         return 0;
      }
 
-   image_id = ++_entry_id;
-   while ((image_id == 0) || (eina_hash_find(image_entries, &image_id)))
-     image_id = ++_entry_id;
-
-   entry->base.id = image_id;
-   eina_hash_add(image_entries, &image_id, entry);
-   eina_hash_add(image_ids, buf, (void *)(intptr_t)image_id);
-   ref = _entry_reference_add((Entry *)entry, client, client_image_id);
-
-   if (oldref)
-     eina_hash_del_by_key(client->images.referencing, &client_image_id);
-   eina_hash_add(client->images.referencing, &client_image_id, ref);
+   ientry = _image_entry_new(client, rid, client_file_id, client_image_id,
+                             opts, buf);
+   if (!ientry)
+     return -1;
 
-   fentry = _file_entry_find(entry->file_id);
-   fentry->images = eina_list_append(fentry->images, entry);
+   fentry = _file_entry_find(ref->entry->id);
+   fentry->images = eina_list_append(fentry->images, ientry);
 
    if (opts && opts->scale_load.dst_w && opts->scale_load.dst_h)
      {
-        if (!_cserve2_cache_fast_scaling_check(client, entry))
+        if (!_cserve2_cache_fast_scaling_check(client, ientry))
           return 0;
      }
 
-   ASENTRY(entry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_SPEC_LOAD,
-                                                 0, NULL, ASENTRY(fentry)->request,
-                                                 &_load_funcs, entry);
+   ASENTRY(ientry)->request = cserve2_request_add(
+            CSERVE2_REQ_IMAGE_SPEC_LOAD,
+            0, NULL, ASENTRY(fentry)->request,
+            &_load_funcs, ientry);
+
    return 0;
 }
 
 void
 cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid)
 {
-   Image_Data *entry;
+   Image_Entry *ientry;
+   Image_Data *idata;
    Reference *ref;
    File_Data *fd;
 
@@ -2578,8 +2724,15 @@ cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned
         return;
      }
 
-   entry = (Image_Data *) ref->entry;
-   fd = _file_data_find(entry->file_id);
+   ientry = (Image_Entry *) ref->entry;
+   idata = _image_data_find(ENTRYID(ientry));
+   if (!idata)
+     {
+        ERR("Image data not found for entry %u", ENTRYID(ientry));
+        return;
+     }
+
+   fd = _file_data_find(idata->file_id);
    if (!fd || fd->invalid)
      {
         cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
@@ -2589,72 +2742,35 @@ cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned
    DBG("Loading image id: %d", ref->entry->id);
 
    // File already being loaded, just add the request to be replied
-   if (entry->base.request)
+   if (ASENTRY(ientry)->request)
      {
-        cserve2_request_waiter_add(entry->base.request, rid, client);
-        if (!entry->doload)
-          cserve2_request_type_set(entry->base.request, CSERVE2_REQ_IMAGE_LOAD);
+        cserve2_request_waiter_add(ASENTRY(ientry)->request, rid, client);
+        if (!idata->doload)
+          {
+             cserve2_request_type_set(ASENTRY(ientry)->request,
+                                      CSERVE2_REQ_IMAGE_LOAD);
+          }
      }
-   else if (entry->shm)
-     _image_loaded_send(client, entry, rid);
+   else if (ientry->shm)
+     _image_loaded_send(client, ientry, idata, rid);
    else
      {
-        File_Entry *fentry = _file_entry_find(entry->file_id);
-        ASENTRY(entry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_LOAD,
-                                                      rid, client,
-                                                      ASENTRY(fentry)->request,
-                                                      &_load_funcs,
-                                                      entry);
+        File_Entry *fentry = _file_entry_find(idata->file_id);
+        ASENTRY(ientry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_LOAD,
+                                                       rid, client,
+                                                       ASENTRY(fentry)->request,
+                                                       &_load_funcs,
+                                                       ientry);
      }
 
-   entry->doload = EINA_TRUE;
+   idata->doload = EINA_TRUE;
 }
 
 void
 cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid)
 {
-   Image_Data *entry;
-   Reference *ref;
-   File_Data *fd;
-
-   ref = eina_hash_find(client->images.referencing, &client_image_id);
-   if (!ref)
-     {
-        ERR("Can't load: client %d has no image id %d",
-            client->id, client_image_id);
-        return;
-     }
-
-   entry = (Image_Data *) ref->entry;
-   fd = _file_data_find(entry->file_id);
-   if (!fd || fd->invalid)
-     {
-        cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
-        return;
-     }
-
-   DBG("Loading image id: %d", ref->entry->id);
-
-   // File already being loaded, just add the request to be replied
-   if (entry->base.request)
-     {
-        cserve2_request_waiter_add(entry->base.request, rid, client);
-        if (!entry->doload)
-          cserve2_request_type_set(entry->base.request, CSERVE2_REQ_IMAGE_LOAD);
-     }
-   else if (entry->shm)
-     _image_loaded_send(client, entry, rid);
-   else
-     {
-        File_Entry *fentry = _file_entry_find(entry->file_id);
-        ASENTRY(entry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_LOAD,
-                                                      rid, client,
-                                                      ASENTRY(fentry)->request,
-                                                      &_load_funcs,
-                                                      entry);
-     }
-
-   entry->doload = EINA_TRUE;
+   // Same as normal load (for now)
+   return cserve2_cache_image_load(client, client_image_id, rid);
 }
 
 void
index dd335d8..debaedc 100644 (file)
@@ -759,17 +759,18 @@ cserve2_shared_mempool_buffer_ref(Shared_Mempool *sm, int bufferid)
    return ie->id;
 }
 
-void
-cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid)
+static Eina_Bool
+_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid)
 {
    Index_Entry *ie;
 
-   if (!sm || !bufferid) return;
+   if (!sm || !bufferid) return EINA_FALSE;
+
    ie = _shared_index_entry_find(sm->index, bufferid);
    if (!ie || ie->refcount <= 0)
      {
         CRIT("Tried to delete invalid buffer or with refcount 0");
-        return;
+        return EINA_FALSE;
      }
 
    ie->refcount--;
@@ -782,7 +783,16 @@ cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid)
         sm->empty_blocks = (Block *) eina_rbtree_inline_insert(
                  EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(newblk),
                  EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL);
+        return EINA_TRUE;
      }
+
+   return EINA_FALSE;
+}
+
+void
+cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid)
+{
+   _shared_mempool_buffer_del(sm, bufferid);
 }
 
 void *