7 #include "evas_cserve2.h"
9 typedef struct _Request_Funcs Request_Funcs;
10 typedef struct _Request Request;
12 typedef struct _Entry Entry;
13 typedef struct _Reference Reference;
14 typedef struct _Waiter Waiter;
15 typedef struct _File_Data File_Data;
16 typedef struct _Image_Data Image_Data;
17 typedef struct _File_Watch File_Watch;
19 typedef struct _Font_Source Font_Source;
20 typedef struct _Font_Entry Font_Entry;
21 typedef struct _Font_Cache Font_Cache;
22 typedef struct _Glyph_Entry Glyph_Entry;
24 typedef void *(*Request_Msg_Create)(Entry *e, int *size);
25 typedef void (*Request_Response)(Entry *e, void *resp);
26 typedef void (*Request_Error)(Entry *e, Error_Type error);
28 struct _Request_Funcs {
29 Request_Msg_Create msg_create;
30 Request_Response response;
49 Eina_List *references;
62 const char *loader_data;
66 Eina_Bool invalid : 1;
69 // Default values for load options commented below
75 double dpi; // dpi < -1
76 int w, h; // w and h < -1
77 int scale_down; // scale_down < -1
78 int rx, ry, rw, rh; // rx, ry, rw, rh < -1
79 Eina_Bool orientation; // orientation == 0
82 Eina_Bool alpha_sparse : 1;
95 unsigned int rend_flags;
113 struct _Glyph_Entry {
124 unsigned int client_entry_id; // for reverse lookup
139 static Eina_List *open_requests = NULL;
140 static Eina_List *load_requests = NULL;
141 static Eina_List *spload_requests = NULL; // speculative preload requests
143 static unsigned int _file_id = 0; // id unique number
144 static unsigned int _image_id = 0; // id unique number
145 static Eina_Hash *file_ids = NULL; // maps path + key --> file_id
146 static Eina_Hash *file_entries = NULL; // maps file_id --> entry
148 static Eina_Hash *image_ids = NULL; // maps file id + load opts --> image id
149 static Eina_Hash *image_entries = NULL; // maps image_id --> entry
151 static Eina_Hash *font_sources = NULL; // font path --> font source
152 static Eina_Hash *font_entries = NULL; // maps font path + options --> entry
154 static Eina_Hash *file_watch = NULL;
156 static Eina_List *image_entries_lru = NULL;
158 static int max_unused_mem_usage = 5 * 1024; /* in kbytes */
159 static int unused_mem_usage = 0;
162 _image_opened_send(Client *client, File_Data *entry, unsigned int rid)
167 DBG("Sending OPENED reply for entry: %d and RID: %d.", entry->base.id, rid);
168 // clear the struct with possible paddings, since it is not aligned.
169 memset(&msg, 0, sizeof(msg));
171 msg.base.type = CSERVE2_OPENED;
172 msg.image.w = entry->w;
173 msg.image.h = entry->h;
174 msg.image.frame_count = entry->frame_count;
175 msg.image.loop_count = entry->loop_count;
176 msg.image.loop_hint = entry->loop_hint;
177 msg.image.alpha = entry->alpha;
180 cserve2_client_send(client, &size, sizeof(size));
181 cserve2_client_send(client, &msg, sizeof(msg));
182 // _cserve2_cache_load_requests_process();
186 _image_loaded_send(Client *client, Image_Data *entry, unsigned int rid)
189 const char *shmpath = cserve2_shm_name_get(entry->shm);
194 DBG("Sending LOADED reply for entry %d and RID: %d.", entry->base.id, rid);
195 path_len = strlen(shmpath) + 1;
197 memset(&msg, 0, sizeof(msg));
199 msg.base.type = CSERVE2_LOADED;
201 msg.shm.mmap_offset = cserve2_shm_map_offset_get(entry->shm);
202 msg.shm.use_offset = cserve2_shm_offset_get(entry->shm);
203 msg.shm.mmap_size = cserve2_shm_map_size_get(entry->shm);
204 msg.shm.image_size = cserve2_shm_size_get(entry->shm);
205 msg.alpha_sparse = entry->alpha_sparse;
207 buf = malloc(sizeof(msg) + path_len);
209 memcpy(buf, &msg, sizeof(msg));
210 memcpy(buf + sizeof(msg), shmpath, path_len);
212 size = sizeof(msg) + path_len;
214 cserve2_client_send(client, &size, sizeof(size));
215 cserve2_client_send(client, buf, size);
221 _image_preloaded_send(Client *client, unsigned int rid)
226 DBG("Sending PRELOADED reply for RID: %d.", rid);
227 memset(&msg, 0, sizeof(msg));
229 msg.base.type = CSERVE2_PRELOADED;
232 cserve2_client_send(client, &size, sizeof(size));
233 cserve2_client_send(client, &msg, size);
237 _open_request_build(File_Data *f, int *bufsize)
240 int size, pathlen, keylen;
241 Slave_Msg_Image_Open msg;
243 pathlen = strlen(f->path) + 1;
244 keylen = strlen(f->key) + 1;
246 size = sizeof(msg) + pathlen + keylen;
248 if (!buf) return NULL;
250 memset(&msg, 0, sizeof(msg));
251 memcpy(buf, &msg, sizeof(msg));
252 memcpy(buf + sizeof(msg), f->path, pathlen);
253 memcpy(buf + sizeof(msg) + pathlen, f->key, keylen);
260 _request_failed(Entry *e, Error_Type type)
266 DBG("Request for entry %p failed with error %d", e, type);
267 EINA_LIST_FREE(e->request->waiters, w)
269 cserve2_client_error_send(w->ref->client, w->rid, type);
275 EINA_LIST_FOREACH(e->references, l, ref)
277 Eina_Hash *hash = NULL;
278 if (e->type == CSERVE2_IMAGE_FILE)
279 hash = ref->client->files.referencing;
280 else if (e->type == CSERVE2_IMAGE_DATA)
281 hash = ref->client->images.referencing;
285 eina_hash_del_by_key(hash, &(ref->client_entry_id));
290 _open_request_response(File_Data *e, Slave_Msg_Image_Opened *resp)
296 e->frame_count = resp->frame_count;
297 e->loop_count = resp->loop_count;
298 e->loop_hint = resp->loop_hint;
299 e->alpha = resp->alpha;
300 if (resp->has_loader_data)
302 const char *ldata = (const char *)resp +
303 sizeof(Slave_Msg_Image_Opened);
304 e->loader_data = eina_stringshare_add(ldata);
307 DBG("Finished opening file %d. Notifying %d waiters.", e->base.id,
308 e->base.request->waiters ? eina_list_count(e->base.request->waiters) : 0);
309 EINA_LIST_FREE(e->base.request->waiters, w)
311 _image_opened_send(w->ref->client, e, w->rid);
316 static Request_Funcs _open_funcs = {
317 .msg_create = (Request_Msg_Create)_open_request_build,
318 .response = (Request_Response)_open_request_response,
319 .error = (Request_Error)_request_failed
323 _load_request_build(Image_Data *i, int *bufsize)
328 int shmlen, filelen, keylen, loaderlen;
329 Slave_Msg_Image_Load msg;
331 // opening shm for this file
332 i->shm = cserve2_shm_request(i->file->w * i->file->h * 4);
334 shmpath = cserve2_shm_name_get(i->shm);
336 shmlen = strlen(shmpath) + 1;
337 filelen = strlen(i->file->path) + 1;
338 keylen = strlen(i->file->key) + 1;
339 if (i->file->loader_data)
340 loaderlen = strlen(i->file->loader_data) + 1;
344 size = sizeof(msg) + shmlen + filelen + keylen + loaderlen;
346 if (!buf) return NULL;
348 memset(&msg, 0, sizeof(msg));
351 msg.alpha = i->file->alpha;
352 msg.opts.w = i->opts.w;
353 msg.opts.h = i->opts.h;
354 msg.opts.rx = i->opts.rx;
355 msg.opts.ry = i->opts.ry;
356 msg.opts.rw = i->opts.rw;
357 msg.opts.rh = i->opts.rh;
358 msg.opts.scale_down_by = i->opts.scale_down;
359 msg.opts.dpi = i->opts.dpi;
360 msg.opts.orientation = i->opts.orientation;
362 msg.shm.mmap_offset = cserve2_shm_map_offset_get(i->shm);
363 msg.shm.image_offset = cserve2_shm_offset_get(i->shm);
364 msg.shm.mmap_size = cserve2_shm_map_size_get(i->shm);
365 msg.shm.image_size = cserve2_shm_size_get(i->shm);
367 msg.has_loader_data = !!loaderlen;
369 memcpy(buf, &msg, sizeof(msg));
370 ptr = buf + sizeof(msg);
372 memcpy(ptr, shmpath, shmlen);
374 memcpy(ptr, i->file->path, filelen);
376 memcpy(ptr, i->file->key, keylen);
378 memcpy(ptr, i->file->loader_data, loaderlen);
385 _load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp)
389 e->alpha_sparse = resp->alpha_sparse;
391 DBG("Entry %d loaded by speculative preload.", e->base.id);
393 DBG("Finished loading image %d. Notifying %d waiters.", e->base.id,
394 e->base.request->waiters ? eina_list_count(e->base.request->waiters) : 0);
395 EINA_LIST_FREE(e->base.request->waiters, w)
397 if (w->type == CSERVE2_LOAD)
398 _image_loaded_send(w->ref->client, e, w->rid);
399 else if (w->type == CSERVE2_PRELOAD)
400 _image_preloaded_send(w->ref->client, w->rid);
401 // else w->type == CSERVE2_SETOPTS --> do nothing
407 static Request_Funcs _load_funcs = {
408 .msg_create = (Request_Msg_Create)_load_request_build,
409 .response = (Request_Response)_load_request_response,
410 .error = (Request_Error)_request_failed
414 _img_opts_id_get(Image_Data *im, char *buf, int size)
418 snprintf(buf, size, "%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:%d",
419 im->file_id, im->opts.dpi, im->opts.w, im->opts.h,
420 im->opts.scale_down, im->opts.rx, im->opts.ry,
421 im->opts.rw, im->opts.rh, im->opts.orientation);
423 image_id = (uintptr_t)eina_hash_find(image_ids, buf);
429 _image_entry_size_get(Image_Data *e)
431 int size = sizeof(Image_Data);
432 /* XXX: get the overhead of the shm handler too */
434 size += cserve2_shm_size_get(e->shm);
439 _file_id_free(File_Data *entry)
443 DBG("Removing entry file id: %d, file: \"%s:%s\"",
444 entry->base.id, entry->path, entry->key);
445 snprintf(buf, sizeof(buf), "%s:%s", entry->path, entry->key);
446 eina_hash_del_by_key(file_ids, buf);
450 _image_id_free(Image_Data *entry)
454 DBG("Removing entry image id: %d", entry->base.id);
456 _img_opts_id_get(entry, buf, sizeof(buf));
457 eina_hash_del_by_key(image_ids, buf);
461 _image_entry_free(Image_Data *entry)
463 File_Data *fentry = entry->file;
465 if (entry->base.request)
467 if (entry->base.request->processing)
468 entry->base.request->entry = NULL;
469 else if (!entry->base.request->waiters)
472 load_requests = eina_list_remove(load_requests,
473 entry->base.request);
475 spload_requests = eina_list_remove(spload_requests,
476 entry->base.request);
482 image_entries_lru = eina_list_remove(image_entries_lru, entry);
483 unused_mem_usage -= _image_entry_size_get(entry);
487 fentry->images = eina_list_remove(fentry->images, entry);
489 cserve2_shm_unref(entry->shm);
494 _hash_image_entry_free(void *data)
496 Image_Data *entry = data;
498 _image_id_free(entry);
499 _image_entry_free(entry);
503 _file_entry_free(File_Data *entry)
507 // Should we call free for each of the images too?
508 // If everything goes fine, it's not necessary.
511 ERR("Freeing file %d (\"%s:%s\") image data still referenced.",
512 entry->base.id, entry->path, entry->key);
513 eina_list_free(entry->images);
516 if (entry->base.request)
518 if (entry->base.request->processing)
519 entry->base.request->entry = NULL;
520 else if (!entry->base.request->waiters)
522 open_requests = eina_list_remove(open_requests,
523 entry->base.request);
524 free(entry->base.request);
528 if ((fw = entry->watcher))
530 fw->entries = eina_list_remove(fw->entries, entry);
532 eina_hash_del_by_key(file_watch, fw->path);
537 eina_stringshare_del(entry->loader_data);
542 _hash_file_entry_free(void *data)
544 File_Data *entry = data;
545 // TODO: Add some checks to make sure that we are freeing an
548 _file_id_free(entry);
549 _file_entry_free(entry);
553 _file_watch_free(void *data)
555 File_Watch *fw = data;
556 cserve2_file_change_watch_del(fw->path);
557 eina_stringshare_del(fw->path);
558 eina_list_free(fw->entries);
563 _font_entry_cmp(const Font_Entry *k1, int k1_length __UNUSED__, const Font_Entry *k2, int k2_length __UNUSED__)
565 if (k1->src->name == k2->src->name)
567 if (k1->size == k2->size)
569 if (k1->rend_flags == k2->rend_flags)
571 if (k1->hint == k2->hint)
572 return k1->dpi - k2->dpi;
573 return k1->hint - k2->hint;
575 return k1->rend_flags - k2->rend_flags;
577 return k1->size - k2->size;
579 return strcmp(k1->src->name, k2->src->name);
583 _font_entry_key_hash(const Font_Entry *key, int key_length __UNUSED__)
586 hash = eina_hash_djb2(key->src->name, eina_stringshare_strlen(key->src->name) + 1);
587 hash ^= eina_hash_int32(&key->rend_flags, sizeof(int));
588 hash ^= eina_hash_int32(&key->size, sizeof(int));
589 hash ^= eina_hash_int32(&key->dpi, sizeof(int));
595 _font_entry_free(Font_Entry *fe)
601 _font_source_free(Font_Source *fs)
603 if (fs->name) eina_stringshare_del(fs->name);
604 if (fs->file) eina_stringshare_del(fs->file);
610 cserve2_cache_init(void)
612 file_ids = eina_hash_string_superfast_new(NULL);
613 file_entries = eina_hash_int32_new(_hash_file_entry_free);
614 image_ids = eina_hash_string_superfast_new(NULL);
615 image_entries = eina_hash_string_superfast_new(_hash_image_entry_free);
616 file_watch = eina_hash_string_superfast_new(_file_watch_free);
618 font_sources = eina_hash_string_small_new(EINA_FREE_CB(_font_source_free));
619 font_entries = eina_hash_new(NULL,
620 EINA_KEY_CMP(_font_entry_cmp),
621 EINA_KEY_HASH(_font_entry_key_hash),
622 EINA_FREE_CB(_font_entry_free),
627 cserve2_cache_shutdown(void)
629 eina_hash_free(image_entries);
630 eina_hash_free(image_ids);
631 eina_hash_free(file_entries);
632 eina_hash_free(file_ids);
633 eina_hash_free(file_watch);
635 eina_hash_free(font_entries);
636 eina_hash_free(font_sources);
640 _request_answer_del(Eina_List **requests, Request *req, Client *client, Error_Type err)
642 Eina_List *l, *l_next;
645 DBG("Removing answer requests from entry: %d, client: %d",
646 req->entry->id, client->id);
648 EINA_LIST_FOREACH_SAFE(req->waiters, l, l_next, it)
650 if (it->ref->client->id == client->id)
652 cserve2_client_error_send(client, it->rid, err);
653 req->waiters = eina_list_remove_list(req->waiters, l);
658 // FIXME: Should this be really here? I guess that it should be in the
659 // entry_free_cb function, or entry_reference_del, when there are no more
661 if (!req->entry && !req->waiters)
663 *requests = eina_list_remove(*requests, req);
669 _request_answer_all_del(Eina_List **requests, Request *req, Error_Type err)
673 DBG("Removing all answer requests from entry: %d", req->entry->id);
675 EINA_LIST_FREE(req->waiters, it)
677 cserve2_client_error_send(it->ref->client, it->rid, err);
681 *requests = eina_list_remove(*requests, req);
686 _request_answer_add(Request *req, Reference *ref, unsigned int rid, Message_Type type)
688 Waiter *w = malloc(sizeof(*w));
694 DBG("Add answer request for entry id: %d, client: %d, rid: %d",
695 req->entry->id, ref->client->id, rid);
696 req->waiters = eina_list_append(req->waiters, w);
700 _request_add(Eina_List **requests, Entry *entry, Reference *ref, unsigned int rid, Message_Type type)
704 // add the request if it doesn't exist yet
707 req = malloc(sizeof(*req));
710 req->processing = EINA_FALSE;
711 entry->request = req;
712 if (type == CSERVE2_OPEN)
713 req->funcs = &_open_funcs;
715 req->funcs = &_load_funcs;
716 *requests = eina_list_append(*requests, req);
717 DBG("Add request for entry id: %d, client: %d, rid: %d",
718 req->entry->id, ref->client->id, rid);
721 req = entry->request;
723 if (type != CSERVE2_SETOPTS)
724 _request_answer_add(req, ref, rid, type);
726 DBG("Adding entry for speculative preload: id=%d", req->entry->id);
730 _entry_reference_add(Entry *entry, Client *client, unsigned int client_entry_id)
734 // increase reference for this file
735 ref = malloc(sizeof(*ref));
736 ref->client = client;
738 ref->client_entry_id = client_entry_id;
740 entry->references = eina_list_append(entry->references, ref);
746 _cserve2_cache_open_requests_process(int nloaders)
749 char *slave_cmd_data;
752 while ((nloaders > 0) && (open_requests))
754 // remove the first element from the list and process this element
755 req = eina_list_data_get(open_requests);
756 open_requests = eina_list_remove_list(open_requests, open_requests);
758 DBG("Processing OPEN request for file entry: %d", req->entry->id);
760 slave_cmd_data = req->funcs->msg_create(req->entry, &slave_cmd_size);
762 cserve2_slave_cmd_dispatch(req, IMAGE_OPEN, slave_cmd_data,
765 free(slave_cmd_data);
767 req->processing = EINA_TRUE;
775 _cserve2_cache_load_requests_list_process(Eina_List **queue, int nloaders)
777 Eina_List *skipped = NULL;
780 while ((nloaders > 0) && (*queue))
786 // remove the first element from the list and process this element
787 req = eina_list_data_get(*queue);
788 *queue = eina_list_remove_list(*queue, *queue);
790 ientry = (Image_Data *)req->entry;
793 ERR("File entry doesn't exist for entry id %d", req->entry->id);
794 _request_failed(req->entry, CSERVE2_INVALID_CACHE);
798 if (ientry->file->base.request)
800 /* OPEN still pending, skip this request */
801 skipped = eina_list_append(skipped, req);
805 DBG("Processing LOAD request for image entry: %d", req->entry->id);
807 buf = req->funcs->msg_create(req->entry, &size);
809 cserve2_slave_cmd_dispatch(req, IMAGE_LOAD, buf, size);
813 req->processing = EINA_TRUE;
818 EINA_LIST_FREE(skipped, req)
819 *queue = eina_list_append(*queue, req);
825 _cserve2_cache_load_requests_process(int nloaders)
827 nloaders = _cserve2_cache_load_requests_list_process(&load_requests,
829 _cserve2_cache_load_requests_list_process(&spload_requests, nloaders - 1);
834 cserve2_cache_requests_process(void)
838 avail_loaders = cserve2_slave_available_get();
839 avail_loaders = _cserve2_cache_open_requests_process(avail_loaders);
840 _cserve2_cache_load_requests_process(avail_loaders);
844 _entry_unused_push(Image_Data *e)
846 int size = _image_entry_size_get(e);
848 if ((size > max_unused_mem_usage) || !(e->doload))
850 eina_hash_del_by_key(image_entries, &e->base.id);
853 while (size > (max_unused_mem_usage - unused_mem_usage))
855 Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
856 eina_hash_del_by_key(image_entries, &ie->id);
858 image_entries_lru = eina_list_append(image_entries_lru, e);
859 e->unused = EINA_TRUE;
860 unused_mem_usage += size;
864 _entry_reference_del(Entry *entry, Reference *ref)
866 entry->references = eina_list_remove(entry->references, ref);
868 if (entry->references)
871 if (entry->type == CSERVE2_IMAGE_FILE)
873 File_Data *fentry = (File_Data *)entry;
876 _file_entry_free(fentry);
880 EINA_LIST_FREE(fentry->images, ie)
882 eina_hash_del_by_key(file_entries, &entry->id);
885 else if (entry->type == CSERVE2_IMAGE_DATA)
887 Image_Data *ientry = (Image_Data *)entry;
890 eina_hash_del_by_key(image_entries, &entry->id);
891 else if (ientry->file->invalid)
892 _image_entry_free(ientry);
894 _entry_unused_push(ientry);
897 ERR("Wrong type of entry.");
904 _entry_free_cb(void *data)
906 Reference *ref = data;
909 DBG("Removing client reference for entry id: %d, client: %d",
910 ref->entry->id, ref->client->id);
914 if (entry->request && !entry->request->processing)
916 if (entry->type == CSERVE2_IMAGE_FILE)
917 _request_answer_del(&open_requests, entry->request, ref->client,
918 CSERVE2_REQUEST_CANCEL);
919 else if (entry->type == CSERVE2_IMAGE_DATA)
921 if (((Image_Data *)entry)->doload)
922 _request_answer_del(&load_requests, entry->request,
923 ref->client, CSERVE2_REQUEST_CANCEL);
925 _request_answer_del(&spload_requests, entry->request,
926 ref->client, CSERVE2_REQUEST_CANCEL);
930 _entry_reference_del(entry, ref);
934 cserve2_cache_client_new(Client *client)
936 client->files.referencing = eina_hash_int32_new(_entry_free_cb);
937 client->images.referencing = eina_hash_int32_new(_entry_free_cb);
941 cserve2_cache_client_del(Client *client)
943 // will call _entry_free_cb() for every entry
944 eina_hash_free(client->images.referencing);
945 // will call _entry_free_cb() for every entry
946 eina_hash_free(client->files.referencing);
950 _image_msg_new(Client *client, Msg_Setopts *msg)
953 Image_Data *im_entry;
955 ref = eina_hash_find(client->files.referencing, &msg->file_id);
958 ERR("Couldn't find file id: %d, for image id: %d",
959 msg->file_id, msg->image_id);
960 cserve2_client_error_send(client, msg->base.rid,
961 CSERVE2_INVALID_CACHE);
964 if (((File_Data *)ref->entry)->invalid)
966 cserve2_client_error_send(client, msg->base.rid,
967 CSERVE2_FILE_CHANGED);
971 im_entry = calloc(1, sizeof(*im_entry));
972 im_entry->base.type = CSERVE2_IMAGE_DATA;
973 im_entry->file_id = ref->entry->id;
974 im_entry->file = (File_Data *)ref->entry;
975 im_entry->opts.dpi = msg->opts.dpi;
976 im_entry->opts.w = msg->opts.w;
977 im_entry->opts.h = msg->opts.h;
978 im_entry->opts.scale_down = msg->opts.scale_down;
979 im_entry->opts.rx = msg->opts.rx;
980 im_entry->opts.ry = msg->opts.ry;
981 im_entry->opts.rw = msg->opts.rw;
982 im_entry->opts.rh = msg->opts.rh;
983 im_entry->opts.orientation = msg->opts.orientation;
989 _file_changed_cb(const char *path __UNUSED__, Eina_Bool deleted __UNUSED__, void *data)
991 File_Watch *fw = data;
995 EINA_LIST_FOREACH(fw->entries, l, e)
1000 e->invalid = EINA_TRUE;
1003 EINA_LIST_FOREACH(e->images, ll, ie)
1006 eina_hash_set(image_entries, &ie->base.id, NULL);
1007 if (ie->base.request && !ie->base.request->processing)
1010 _request_answer_all_del(&load_requests, ie->base.request,
1011 CSERVE2_FILE_CHANGED);
1013 _request_answer_all_del(&spload_requests, ie->base.request,
1014 CSERVE2_FILE_CHANGED);
1016 ie->base.request = NULL;
1018 _image_entry_free(ie);
1022 eina_hash_set(file_entries, &e->base.id, NULL);
1023 if (e->base.request && !e->base.request->processing)
1024 _request_answer_all_del(&open_requests, e->base.request,
1025 CSERVE2_FILE_CHANGED);
1026 e->base.request = NULL;
1027 if (!e->images && !e->base.references)
1028 _file_entry_free(e);
1031 eina_hash_del_by_key(file_watch, fw->path);
1035 cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid)
1037 unsigned int file_id;
1043 // look for this file on client references
1044 ref = eina_hash_find(client->files.referencing, &client_file_id);
1047 entry = (File_Data *)ref->entry;
1051 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
1055 DBG("found client file id: %d", client_file_id);
1058 // File already being loaded, just add the request to be replied
1059 if (entry->base.request)
1060 _request_answer_add(entry->base.request, ref, rid, CSERVE2_OPEN);
1062 _image_opened_send(client, entry, rid);
1066 // search whether the file is already opened by another client
1067 snprintf(buf, sizeof(buf), "%s:%s", path, key);
1068 file_id = (unsigned int)eina_hash_find(file_ids, buf);
1071 DBG("found file_id %u for client file id %d",
1072 file_id, client_file_id);
1073 entry = eina_hash_find(file_entries, &file_id);
1076 ERR("file \"%s\" is in file_ids hash but not in entries hash.",
1078 cserve2_client_error_send(client, rid, CSERVE2_INVALID_CACHE);
1081 ref = _entry_reference_add((Entry *)entry, client, client_file_id);
1082 eina_hash_add(client->files.referencing, &client_file_id, ref);
1083 if (entry->base.request)
1084 _request_answer_add(entry->base.request, ref, rid, CSERVE2_OPEN);
1085 else // File already loaded, otherwise there would be a request
1086 _image_opened_send(client, entry, rid);
1090 file_id = _file_id++;
1091 while ((file_id == 0) || (eina_hash_find(file_entries, &file_id)))
1092 file_id = _file_id++;
1094 DBG("Creating new entry with file_id: %u for file \"%s:%s\"",
1095 file_id, path, key);
1096 entry = calloc(1, sizeof(*entry));
1097 entry->base.type = CSERVE2_IMAGE_FILE;
1098 entry->path = strdup(path);
1099 entry->key = strdup(key);
1100 entry->base.id = file_id;
1101 eina_hash_add(file_entries, &file_id, entry);
1102 eina_hash_add(file_ids, buf, (void *)file_id);
1103 ref = _entry_reference_add((Entry *)entry, client, client_file_id);
1104 eina_hash_add(client->files.referencing, &client_file_id, ref);
1106 fw = eina_hash_find(file_watch, entry->path);
1109 fw = calloc(1, sizeof(File_Watch));
1110 fw->path = eina_stringshare_add(entry->path);
1111 cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw);
1112 eina_hash_direct_add(file_watch, fw->path, fw);
1114 fw->entries = eina_list_append(fw->entries, entry);
1115 entry->watcher = fw;
1117 _request_add(&open_requests, (Entry *)entry, ref, rid, CSERVE2_OPEN);
1119 // _open_image_default_set(entry);
1125 cserve2_cache_file_close(Client *client, unsigned int client_file_id)
1127 Reference *ref = eina_hash_find(client->files.referencing,
1131 ERR("Couldn't find file %d in client hash.", client_file_id);
1136 if (ref->count <= 0)
1137 // will call _entry_free_cb() for this entry
1138 eina_hash_del_by_key(client->files.referencing, &client_file_id);
1142 cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg)
1145 File_Data *fentry = NULL;
1146 Reference *ref, *oldref;
1147 unsigned int image_id;
1150 oldref = eina_hash_find(client->images.referencing, &msg->image_id);
1152 // search whether the image is already loaded by another client
1153 entry = _image_msg_new(client, msg);
1156 image_id = _img_opts_id_get(entry, buf, sizeof(buf));
1158 { // if so, just update the references
1160 DBG("found image_id %d for client image id %d",
1161 image_id, msg->image_id);
1162 entry = eina_hash_find(image_entries, &image_id);
1165 ERR("image id %d is in file_ids hash, but not in entries hash"
1166 "with entry id %d.", msg->image_id, image_id);
1167 cserve2_client_error_send(client, msg->base.rid,
1168 CSERVE2_INVALID_CACHE);
1174 DBG("Re-using old image entry (id: %d) from the LRU list.",
1176 entry->unused = EINA_FALSE;
1177 image_entries_lru = eina_list_remove(image_entries_lru, entry);
1178 unused_mem_usage -= _image_entry_size_get(entry);
1181 if (oldref && (oldref->entry->id == image_id))
1184 ref = _entry_reference_add((Entry *)entry, client, msg->image_id);
1187 eina_hash_del_by_key(client->images.referencing, &msg->image_id);
1189 eina_hash_add(client->images.referencing, &msg->image_id, ref);
1194 image_id = _image_id++;
1195 while ((image_id == 0) || (eina_hash_find(image_entries, &image_id)))
1196 image_id = _image_id++;
1198 entry->base.id = image_id;
1199 eina_hash_add(image_entries, &image_id, entry);
1200 eina_hash_add(image_ids, buf, (void *)image_id);
1201 ref = _entry_reference_add((Entry *)entry, client, msg->image_id);
1204 eina_hash_del_by_key(client->images.referencing, &msg->image_id);
1205 eina_hash_add(client->images.referencing, &msg->image_id, ref);
1207 fentry = entry->file;
1208 fentry->images = eina_list_append(fentry->images, entry);
1210 _request_add(&spload_requests, (Entry *)entry, ref, msg->base.rid,
1216 cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid)
1221 ref = eina_hash_find(client->images.referencing, &client_image_id);
1224 ERR("Can't load: client %d has no image id %d",
1225 client->id, client_image_id);
1229 entry = (Image_Data *)ref->entry;
1231 if (entry->file->invalid)
1233 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
1237 DBG("Loading image id: %d", ref->entry->id);
1239 // File already being loaded, just add the request to be replied
1240 if (entry->base.request)
1242 _request_answer_add(entry->base.request, ref, rid, CSERVE2_LOAD);
1243 if ((!entry->base.request->processing) && (!entry->doload))
1245 DBG("Removing entry %d from speculative preload and adding "
1246 "to normal load queue.", entry->base.id);
1247 spload_requests = eina_list_remove(spload_requests,
1248 entry->base.request);
1249 load_requests = eina_list_append(load_requests,
1250 entry->base.request);
1253 else if (entry->shm)
1254 _image_loaded_send(client, entry, rid);
1256 _request_add(&load_requests, (Entry *)entry, ref, rid, CSERVE2_LOAD);
1258 entry->doload = EINA_TRUE;
1262 cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid)
1267 ref = eina_hash_find(client->images.referencing, &client_image_id);
1270 ERR("Can't load: client %d has no image id %d",
1271 client->id, client_image_id);
1275 entry = (Image_Data *)ref->entry;
1277 if (entry->file->invalid)
1279 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
1283 DBG("Loading image id: %d", ref->entry->id);
1285 // File already being loaded, just add the request to be replied
1286 if (entry->base.request)
1288 _request_answer_add(entry->base.request, ref, rid, CSERVE2_PRELOAD);
1289 if ((!entry->base.request->processing) && (!entry->doload))
1291 DBG("Removing entry %d from speculative preload and adding "
1292 "to normal (pre)load queue.", entry->base.id);
1293 spload_requests = eina_list_remove(spload_requests,
1294 entry->base.request);
1295 load_requests = eina_list_append(load_requests,
1296 entry->base.request);
1299 else if (entry->shm)
1300 _image_preloaded_send(client, rid);
1302 _request_add(&load_requests, (Entry *)entry, ref, rid, CSERVE2_PRELOAD);
1304 entry->doload = EINA_TRUE;
1308 cserve2_cache_image_unload(Client *client, unsigned int client_image_id)
1310 Reference *ref = eina_hash_find(client->images.referencing,
1314 ERR("Couldn't find file %d in client hash.", client_image_id);
1319 if (ref->count <= 0)
1320 // will call _entry_free_cb() for this entry
1321 eina_hash_del_by_key(client->images.referencing, &client_image_id);
1325 cserve2_cache_requests_response(Slave_Command type, void *msg, void *data)
1327 Request *req = data;
1332 DBG("Request finished but it has no entry anymore.");
1333 EINA_LIST_FREE(req->waiters, w)
1335 cserve2_client_error_send(w->ref->client, w->rid,
1336 CSERVE2_REQUEST_CANCEL);
1342 else if (type == ERROR)
1344 Error_Type *error = msg;
1345 req->funcs->error(req->entry, *error);
1348 req->funcs->response(req->entry, msg);
1351 req->entry->request = NULL;