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;
48 Eina_List *references;
61 const char *loader_data;
65 Eina_Bool invalid : 1;
68 // Default values for load options commented below
74 double dpi; // dpi < -1
75 int w, h; // w and h < -1
76 int scale_down; // scale_down < -1
77 int rx, ry, rw, rh; // rx, ry, rw, rh < -1
78 Eina_Bool orientation; // orientation == 0
81 Eina_Bool alpha_sparse : 1;
93 unsigned int rend_flags;
111 struct _Glyph_Entry {
122 unsigned int client_entry_id; // for reverse lookup
137 static Eina_List *open_requests = NULL;
138 static Eina_List *load_requests = NULL;
139 static Eina_List *spload_requests = NULL; // speculative preload requests
141 static unsigned int _file_id = 0; // id unique number
142 static unsigned int _image_id = 0; // id unique number
143 static Eina_Hash *file_ids = NULL; // maps path + key --> file_id
144 static Eina_Hash *file_entries = NULL; // maps file_id --> entry
146 static Eina_Hash *image_ids = NULL; // maps file id + load opts --> image id
147 static Eina_Hash *image_entries = NULL; // maps image_id --> entry
149 static Eina_Hash *font_sources = NULL; // font path --> font source
150 static Eina_Hash *font_entries = NULL; // maps font path + options --> entry
152 static Eina_Hash *file_watch = NULL;
154 static Eina_List *image_entries_lru = NULL;
156 static int max_unused_mem_usage = 5 * 1024; /* in kbytes */
157 static int unused_mem_usage = 0;
160 _image_opened_send(Client *client, File_Data *entry, unsigned int rid)
165 DBG("Sending OPENED reply for entry: %d and RID: %d.", entry->base.id, rid);
166 // clear the struct with possible paddings, since it is not aligned.
167 memset(&msg, 0, sizeof(msg));
169 msg.base.type = CSERVE2_OPENED;
170 msg.image.w = entry->w;
171 msg.image.h = entry->h;
172 msg.image.frame_count = entry->frame_count;
173 msg.image.loop_count = entry->loop_count;
174 msg.image.loop_hint = entry->loop_hint;
175 msg.image.alpha = entry->alpha;
178 cserve2_client_send(client, &size, sizeof(size));
179 cserve2_client_send(client, &msg, sizeof(msg));
180 // _cserve2_cache_load_requests_process();
184 _image_loaded_send(Client *client, Image_Data *entry, unsigned int rid)
187 const char *shmpath = cserve2_shm_name_get(entry->shm);
192 DBG("Sending LOADED reply for entry %d and RID: %d.", entry->base.id, rid);
193 path_len = strlen(shmpath) + 1;
195 memset(&msg, 0, sizeof(msg));
197 msg.base.type = CSERVE2_LOADED;
199 msg.shm.mmap_offset = cserve2_shm_map_offset_get(entry->shm);
200 msg.shm.use_offset = cserve2_shm_offset_get(entry->shm);
201 msg.shm.mmap_size = cserve2_shm_map_size_get(entry->shm);
202 msg.shm.image_size = cserve2_shm_size_get(entry->shm);
203 msg.alpha_sparse = entry->alpha_sparse;
205 buf = malloc(sizeof(msg) + path_len);
207 memcpy(buf, &msg, sizeof(msg));
208 memcpy(buf + sizeof(msg), shmpath, path_len);
210 size = sizeof(msg) + path_len;
212 cserve2_client_send(client, &size, sizeof(size));
213 cserve2_client_send(client, buf, size);
219 _image_preloaded_send(Client *client, unsigned int rid)
224 DBG("Sending PRELOADED reply for RID: %d.", rid);
225 memset(&msg, 0, sizeof(msg));
227 msg.base.type = CSERVE2_PRELOADED;
230 cserve2_client_send(client, &size, sizeof(size));
231 cserve2_client_send(client, &msg, size);
235 _open_request_build(File_Data *f, int *bufsize)
238 int size, pathlen, keylen;
239 Slave_Msg_Image_Open msg;
241 pathlen = strlen(f->path) + 1;
242 keylen = strlen(f->key) + 1;
244 size = sizeof(msg) + pathlen + keylen;
246 if (!buf) return NULL;
248 memset(&msg, 0, sizeof(msg));
249 memcpy(buf, &msg, sizeof(msg));
250 memcpy(buf + sizeof(msg), f->path, pathlen);
251 memcpy(buf + sizeof(msg) + pathlen, f->key, keylen);
258 _request_failed(Entry *e, Error_Type type)
264 DBG("Request for entry %p failed with error %d", e, type);
265 EINA_LIST_FREE(e->request->waiters, w)
267 cserve2_client_error_send(w->ref->client, w->rid, type);
273 EINA_LIST_FOREACH(e->references, l, ref)
275 Eina_Hash *hash = NULL;
276 if (e->type == CSERVE2_IMAGE_FILE)
277 hash = ref->client->files.referencing;
278 else if (e->type == CSERVE2_IMAGE_DATA)
279 hash = ref->client->images.referencing;
281 eina_hash_del_by_key(hash, &(ref->client_entry_id));
286 _open_request_response(File_Data *e, Slave_Msg_Image_Opened *resp)
292 e->frame_count = resp->frame_count;
293 e->loop_count = resp->loop_count;
294 e->loop_hint = resp->loop_hint;
295 e->alpha = resp->alpha;
296 if (resp->has_loader_data)
298 const char *ldata = (const char *)resp +
299 sizeof(Slave_Msg_Image_Opened);
300 e->loader_data = eina_stringshare_add(ldata);
303 DBG("Finished opening file %d. Notifying %d waiters.", e->base.id,
304 e->base.request->waiters ? eina_list_count(e->base.request->waiters) : 0);
305 EINA_LIST_FREE(e->base.request->waiters, w)
307 _image_opened_send(w->ref->client, e, w->rid);
312 static Request_Funcs _open_funcs = {
313 .msg_create = (Request_Msg_Create)_open_request_build,
314 .response = (Request_Response)_open_request_response,
315 .error = (Request_Error)_request_failed
319 _load_request_build(Image_Data *i, int *bufsize)
324 int shmlen, filelen, keylen, loaderlen;
325 Slave_Msg_Image_Load msg;
327 // opening shm for this file
328 i->shm = cserve2_shm_request(i->file->w * i->file->h * 4);
330 shmpath = cserve2_shm_name_get(i->shm);
332 shmlen = strlen(shmpath) + 1;
333 filelen = strlen(i->file->path) + 1;
334 keylen = strlen(i->file->key) + 1;
335 if (i->file->loader_data)
336 loaderlen = strlen(i->file->loader_data) + 1;
340 size = sizeof(msg) + shmlen + filelen + keylen + loaderlen;
342 if (!buf) return NULL;
344 memset(&msg, 0, sizeof(msg));
347 msg.alpha = i->file->alpha;
348 msg.opts.w = i->opts.w;
349 msg.opts.h = i->opts.h;
350 msg.opts.rx = i->opts.rx;
351 msg.opts.ry = i->opts.ry;
352 msg.opts.rw = i->opts.rw;
353 msg.opts.rh = i->opts.rh;
354 msg.opts.scale_down_by = i->opts.scale_down;
355 msg.opts.dpi = i->opts.dpi;
356 msg.opts.orientation = i->opts.orientation;
358 msg.shm.mmap_offset = cserve2_shm_map_offset_get(i->shm);
359 msg.shm.image_offset = cserve2_shm_offset_get(i->shm);
360 msg.shm.mmap_size = cserve2_shm_map_size_get(i->shm);
361 msg.shm.image_size = cserve2_shm_size_get(i->shm);
363 msg.has_loader_data = !!loaderlen;
365 memcpy(buf, &msg, sizeof(msg));
366 ptr = buf + sizeof(msg);
368 memcpy(ptr, shmpath, shmlen);
370 memcpy(ptr, i->file->path, filelen);
372 memcpy(ptr, i->file->key, keylen);
374 memcpy(ptr, i->file->loader_data, loaderlen);
381 _load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp)
385 e->alpha_sparse = resp->alpha_sparse;
387 DBG("Entry %d loaded by speculative preload.", e->base.id);
389 DBG("Finished loading image %d. Notifying %d waiters.", e->base.id,
390 e->base.request->waiters ? eina_list_count(e->base.request->waiters) : 0);
391 EINA_LIST_FREE(e->base.request->waiters, w)
393 if (w->type == CSERVE2_LOAD)
394 _image_loaded_send(w->ref->client, e, w->rid);
395 else if (w->type == CSERVE2_PRELOAD)
396 _image_preloaded_send(w->ref->client, w->rid);
397 // else w->type == CSERVE2_SETOPTS --> do nothing
403 static Request_Funcs _load_funcs = {
404 .msg_create = (Request_Msg_Create)_load_request_build,
405 .response = (Request_Response)_load_request_response,
406 .error = (Request_Error)_request_failed
410 _img_opts_id_get(Image_Data *im, char *buf, int size)
414 snprintf(buf, size, "%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:%d",
415 im->file_id, im->opts.dpi, im->opts.w, im->opts.h,
416 im->opts.scale_down, im->opts.rx, im->opts.ry,
417 im->opts.rw, im->opts.rh, im->opts.orientation);
419 image_id = (uintptr_t)eina_hash_find(image_ids, buf);
425 _image_entry_size_get(Image_Data *e)
427 int size = sizeof(Image_Data);
428 /* XXX: get the overhead of the shm handler too */
430 size += cserve2_shm_size_get(e->shm);
435 _file_id_free(File_Data *entry)
439 DBG("Removing entry file id: %d, file: \"%s:%s\"",
440 entry->base.id, entry->path, entry->key);
441 snprintf(buf, sizeof(buf), "%s:%s", entry->path, entry->key);
442 eina_hash_del_by_key(file_ids, buf);
446 _image_id_free(Image_Data *entry)
450 DBG("Removing entry image id: %d", entry->base.id);
452 _img_opts_id_get(entry, buf, sizeof(buf));
453 eina_hash_del_by_key(image_ids, buf);
457 _image_entry_free(Image_Data *entry)
459 File_Data *fentry = entry->file;
461 if (entry->base.request)
463 if (entry->base.request->processing)
464 entry->base.request->entry = NULL;
465 else if (!entry->base.request->waiters)
468 load_requests = eina_list_remove(load_requests,
469 entry->base.request);
471 spload_requests = eina_list_remove(spload_requests,
472 entry->base.request);
478 image_entries_lru = eina_list_remove(image_entries_lru, entry);
479 unused_mem_usage -= _image_entry_size_get(entry);
483 fentry->images = eina_list_remove(fentry->images, entry);
485 cserve2_shm_unref(entry->shm);
490 _hash_image_entry_free(void *data)
492 Image_Data *entry = data;
494 _image_id_free(entry);
495 _image_entry_free(entry);
499 _file_entry_free(File_Data *entry)
503 // Should we call free for each of the images too?
504 // If everything goes fine, it's not necessary.
507 ERR("Freeing file %d (\"%s:%s\") image data still referenced.",
508 entry->base.id, entry->path, entry->key);
509 eina_list_free(entry->images);
512 if (entry->base.request)
514 if (entry->base.request->processing)
515 entry->base.request->entry = NULL;
516 else if (!entry->base.request->waiters)
518 open_requests = eina_list_remove(open_requests,
519 entry->base.request);
520 free(entry->base.request);
524 if ((fw = entry->watcher))
526 fw->entries = eina_list_remove(fw->entries, entry);
528 eina_hash_del_by_key(file_watch, fw->path);
533 eina_stringshare_del(entry->loader_data);
538 _hash_file_entry_free(void *data)
540 File_Data *entry = data;
541 // TODO: Add some checks to make sure that we are freeing an
544 _file_id_free(entry);
545 _file_entry_free(entry);
549 _file_watch_free(void *data)
551 File_Watch *fw = data;
552 cserve2_file_change_watch_del(fw->path);
553 eina_stringshare_del(fw->path);
554 eina_list_free(fw->entries);
559 _font_entry_cmp(const Font_Entry *k1, int k1_length __UNUSED__, const Font_Entry *k2, int k2_length __UNUSED__)
561 if (k1->src->name == k2->src->name)
563 if (k1->size == k2->size)
565 if (k1->rend_flags == k2->rend_flags)
567 if (k1->hint == k2->hint)
568 return k1->dpi - k2->dpi;
569 return k1->hint - k2->hint;
571 return k1->rend_flags - k2->rend_flags;
573 return k1->size - k2->size;
575 return strcmp(k1->src->name, k2->src->name);
579 _font_entry_key_hash(const Font_Entry *key, int key_length __UNUSED__)
582 hash = eina_hash_djb2(key->src->name, eina_stringshare_strlen(key->src->name) + 1);
583 hash ^= eina_hash_int32(&key->rend_flags, sizeof(int));
584 hash ^= eina_hash_int32(&key->size, sizeof(int));
585 hash ^= eina_hash_int32(&key->dpi, sizeof(int));
591 _font_entry_free(Font_Entry *fe)
597 _font_source_free(Font_Source *fs)
599 if (fs->name) eina_stringshare_del(fs->name);
600 if (fs->file) eina_stringshare_del(fs->file);
606 cserve2_cache_init(void)
608 file_ids = eina_hash_string_superfast_new(NULL);
609 file_entries = eina_hash_int32_new(_hash_file_entry_free);
610 image_ids = eina_hash_string_superfast_new(NULL);
611 image_entries = eina_hash_string_superfast_new(_hash_image_entry_free);
612 file_watch = eina_hash_string_superfast_new(_file_watch_free);
614 font_sources = eina_hash_string_small_new(EINA_FREE_CB(_font_source_free));
615 font_entries = eina_hash_new(NULL,
616 EINA_KEY_CMP(_font_entry_cmp),
617 EINA_KEY_HASH(_font_entry_key_hash),
618 EINA_FREE_CB(_font_entry_free),
623 cserve2_cache_shutdown(void)
625 eina_hash_free(image_entries);
626 eina_hash_free(image_ids);
627 eina_hash_free(file_entries);
628 eina_hash_free(file_ids);
629 eina_hash_free(file_watch);
631 eina_hash_free(font_entries);
632 eina_hash_free(font_sources);
636 _request_answer_del(Eina_List **requests, Request *req, Client *client, Error_Type err)
638 Eina_List *l, *l_next;
641 DBG("Removing answer requests from entry: %d, client: %d",
642 req->entry->id, client->id);
644 EINA_LIST_FOREACH_SAFE(req->waiters, l, l_next, it)
646 if (it->ref->client->id == client->id)
648 cserve2_client_error_send(client, it->rid, err);
649 req->waiters = eina_list_remove_list(req->waiters, l);
654 // FIXME: Should this be really here? I guess that it should be in the
655 // entry_free_cb function, or entry_reference_del, when there are no more
657 if (!req->entry && !req->waiters)
659 *requests = eina_list_remove(*requests, req);
665 _request_answer_all_del(Eina_List **requests, Request *req, Error_Type err)
669 DBG("Removing all answer requests from entry: %d", req->entry->id);
671 EINA_LIST_FREE(req->waiters, it)
673 cserve2_client_error_send(it->ref->client, it->rid, err);
677 *requests = eina_list_remove(*requests, req);
682 _request_answer_add(Request *req, Reference *ref, unsigned int rid, Message_Type type)
684 Waiter *w = malloc(sizeof(*w));
690 DBG("Add answer request for entry id: %d, client: %d, rid: %d",
691 req->entry->id, ref->client->id, rid);
692 req->waiters = eina_list_append(req->waiters, w);
696 _request_add(Eina_List **requests, Entry *entry, Reference *ref, unsigned int rid, Message_Type type)
700 // add the request if it doesn't exist yet
703 req = malloc(sizeof(*req));
706 req->processing = EINA_FALSE;
707 entry->request = req;
708 if (type == CSERVE2_OPEN)
709 req->funcs = &_open_funcs;
711 req->funcs = &_load_funcs;
712 *requests = eina_list_append(*requests, req);
713 DBG("Add request for entry id: %d, client: %d, rid: %d",
714 req->entry->id, ref->client->id, rid);
717 req = entry->request;
719 if (type != CSERVE2_SETOPTS)
720 _request_answer_add(req, ref, rid, type);
722 DBG("Adding entry for speculative preload: id=%d", req->entry->id);
726 _entry_reference_add(Entry *entry, Client *client, unsigned int client_entry_id)
730 // increase reference for this file
731 ref = malloc(sizeof(*ref));
732 ref->client = client;
734 ref->client_entry_id = client_entry_id;
736 entry->references = eina_list_append(entry->references, ref);
742 _cserve2_cache_open_requests_process(int nloaders)
745 char *slave_cmd_data;
748 while ((nloaders > 0) && (open_requests))
750 // remove the first element from the list and process this element
751 req = eina_list_data_get(open_requests);
752 open_requests = eina_list_remove_list(open_requests, open_requests);
754 DBG("Processing OPEN request for file entry: %d", req->entry->id);
756 slave_cmd_data = req->funcs->msg_create(req->entry, &slave_cmd_size);
758 cserve2_slave_cmd_dispatch(req, IMAGE_OPEN, slave_cmd_data,
761 free(slave_cmd_data);
763 req->processing = EINA_TRUE;
771 _cserve2_cache_load_requests_list_process(Eina_List **queue, int nloaders)
773 Eina_List *skipped = NULL;
776 while ((nloaders > 0) && (*queue))
782 // remove the first element from the list and process this element
783 req = eina_list_data_get(*queue);
784 *queue = eina_list_remove_list(*queue, *queue);
786 ientry = (Image_Data *)req->entry;
789 ERR("File entry doesn't exist for entry id %d", req->entry->id);
790 _request_failed(req->entry, CSERVE2_INVALID_CACHE);
794 if (ientry->file->base.request)
796 /* OPEN still pending, skip this request */
797 skipped = eina_list_append(skipped, req);
801 DBG("Processing LOAD request for image entry: %d", req->entry->id);
803 buf = req->funcs->msg_create(req->entry, &size);
805 cserve2_slave_cmd_dispatch(req, IMAGE_LOAD, buf, size);
809 req->processing = EINA_TRUE;
814 EINA_LIST_FREE(skipped, req)
815 *queue = eina_list_append(*queue, req);
821 _cserve2_cache_load_requests_process(int nloaders)
823 nloaders = _cserve2_cache_load_requests_list_process(&load_requests,
825 _cserve2_cache_load_requests_list_process(&spload_requests, nloaders - 1);
830 cserve2_cache_requests_process(void)
834 avail_loaders = cserve2_slave_available_get();
835 avail_loaders = _cserve2_cache_open_requests_process(avail_loaders);
836 _cserve2_cache_load_requests_process(avail_loaders);
840 _entry_unused_push(Image_Data *e)
842 int size = _image_entry_size_get(e);
844 if ((size > max_unused_mem_usage) || !(e->doload))
846 eina_hash_del_by_key(image_entries, &e->base.id);
849 while (size > (max_unused_mem_usage - unused_mem_usage))
851 Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
852 eina_hash_del_by_key(image_entries, &ie->id);
854 image_entries_lru = eina_list_append(image_entries_lru, e);
855 e->unused = EINA_TRUE;
856 unused_mem_usage += size;
860 _entry_reference_del(Entry *entry, Reference *ref)
862 entry->references = eina_list_remove(entry->references, ref);
864 if (entry->references)
867 if (entry->type == CSERVE2_IMAGE_FILE)
869 File_Data *fentry = (File_Data *)entry;
872 _file_entry_free(fentry);
876 EINA_LIST_FREE(fentry->images, ie)
878 eina_hash_del_by_key(file_entries, &entry->id);
881 else if (entry->type == CSERVE2_IMAGE_DATA)
883 Image_Data *ientry = (Image_Data *)entry;
886 eina_hash_del_by_key(image_entries, &entry->id);
887 else if (ientry->file->invalid)
888 _image_entry_free(ientry);
890 _entry_unused_push(ientry);
893 ERR("Wrong type of entry.");
900 _entry_free_cb(void *data)
902 Reference *ref = data;
905 DBG("Removing client reference for entry id: %d, client: %d",
906 ref->entry->id, ref->client->id);
910 if (entry->request && !entry->request->processing)
912 if (entry->type == CSERVE2_IMAGE_FILE)
913 _request_answer_del(&open_requests, entry->request, ref->client,
914 CSERVE2_REQUEST_CANCEL);
917 if (((Image_Data *)entry)->doload)
918 _request_answer_del(&load_requests, entry->request,
919 ref->client, CSERVE2_REQUEST_CANCEL);
921 _request_answer_del(&spload_requests, entry->request,
922 ref->client, CSERVE2_REQUEST_CANCEL);
926 _entry_reference_del(entry, ref);
930 cserve2_cache_client_new(Client *client)
932 client->files.referencing = eina_hash_int32_new(_entry_free_cb);
933 client->images.referencing = eina_hash_int32_new(_entry_free_cb);
937 cserve2_cache_client_del(Client *client)
939 // will call _entry_free_cb() for every entry
940 eina_hash_free(client->images.referencing);
941 // will call _entry_free_cb() for every entry
942 eina_hash_free(client->files.referencing);
946 _image_msg_new(Client *client, Msg_Setopts *msg)
949 Image_Data *im_entry;
951 ref = eina_hash_find(client->files.referencing, &msg->file_id);
954 ERR("Couldn't find file id: %d, for image id: %d",
955 msg->file_id, msg->image_id);
956 cserve2_client_error_send(client, msg->base.rid,
957 CSERVE2_INVALID_CACHE);
960 if (((File_Data *)ref->entry)->invalid)
962 cserve2_client_error_send(client, msg->base.rid,
963 CSERVE2_FILE_CHANGED);
967 im_entry = calloc(1, sizeof(*im_entry));
968 im_entry->base.type = CSERVE2_IMAGE_DATA;
969 im_entry->file_id = ref->entry->id;
970 im_entry->file = (File_Data *)ref->entry;
971 im_entry->opts.dpi = msg->opts.dpi;
972 im_entry->opts.w = msg->opts.w;
973 im_entry->opts.h = msg->opts.h;
974 im_entry->opts.scale_down = msg->opts.scale_down;
975 im_entry->opts.rx = msg->opts.rx;
976 im_entry->opts.ry = msg->opts.ry;
977 im_entry->opts.rw = msg->opts.rw;
978 im_entry->opts.rh = msg->opts.rh;
979 im_entry->opts.orientation = msg->opts.orientation;
985 _file_changed_cb(const char *path __UNUSED__, Eina_Bool deleted __UNUSED__, void *data)
987 File_Watch *fw = data;
991 EINA_LIST_FOREACH(fw->entries, l, e)
996 e->invalid = EINA_TRUE;
999 EINA_LIST_FOREACH(e->images, ll, ie)
1002 eina_hash_set(image_entries, &ie->base.id, NULL);
1003 if (ie->base.request && !ie->base.request->processing)
1006 _request_answer_all_del(&load_requests, ie->base.request,
1007 CSERVE2_FILE_CHANGED);
1009 _request_answer_all_del(&spload_requests, ie->base.request,
1010 CSERVE2_FILE_CHANGED);
1012 ie->base.request = NULL;
1014 _image_entry_free(ie);
1018 eina_hash_set(file_entries, &e->base.id, NULL);
1019 if (e->base.request && !e->base.request->processing)
1020 _request_answer_all_del(&open_requests, e->base.request,
1021 CSERVE2_FILE_CHANGED);
1022 e->base.request = NULL;
1023 if (!e->images && !e->base.references)
1024 _file_entry_free(e);
1027 eina_hash_del_by_key(file_watch, fw->path);
1031 cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid)
1033 unsigned int file_id;
1039 // look for this file on client references
1040 ref = eina_hash_find(client->files.referencing, &client_file_id);
1043 entry = (File_Data *)ref->entry;
1047 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
1051 DBG("found client file id: %d", client_file_id);
1054 // File already being loaded, just add the request to be replied
1055 if (entry->base.request)
1056 _request_answer_add(entry->base.request, ref, rid, CSERVE2_OPEN);
1058 _image_opened_send(client, entry, rid);
1062 // search whether the file is already opened by another client
1063 snprintf(buf, sizeof(buf), "%s:%s", path, key);
1064 file_id = (unsigned int)eina_hash_find(file_ids, buf);
1067 DBG("found file_id %u for client file id %d",
1068 file_id, client_file_id);
1069 entry = eina_hash_find(file_entries, &file_id);
1072 ERR("file \"%s\" is in file_ids hash but not in entries hash.",
1074 cserve2_client_error_send(client, rid, CSERVE2_INVALID_CACHE);
1077 ref = _entry_reference_add((Entry *)entry, client, client_file_id);
1078 eina_hash_add(client->files.referencing, &client_file_id, ref);
1079 if (entry->base.request)
1080 _request_answer_add(entry->base.request, ref, rid, CSERVE2_OPEN);
1081 else // File already loaded, otherwise there would be a request
1082 _image_opened_send(client, entry, rid);
1086 file_id = _file_id++;
1087 while ((file_id == 0) || (eina_hash_find(file_entries, &file_id)))
1088 file_id = _file_id++;
1090 DBG("Creating new entry with file_id: %u for file \"%s:%s\"",
1091 file_id, path, key);
1092 entry = calloc(1, sizeof(*entry));
1093 entry->base.type = CSERVE2_IMAGE_FILE;
1094 entry->path = strdup(path);
1095 entry->key = strdup(key);
1096 entry->base.id = file_id;
1097 eina_hash_add(file_entries, &file_id, entry);
1098 eina_hash_add(file_ids, buf, (void *)file_id);
1099 ref = _entry_reference_add((Entry *)entry, client, client_file_id);
1100 eina_hash_add(client->files.referencing, &client_file_id, ref);
1102 fw = eina_hash_find(file_watch, entry->path);
1105 fw = calloc(1, sizeof(File_Watch));
1106 fw->path = eina_stringshare_add(entry->path);
1107 cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw);
1108 eina_hash_direct_add(file_watch, fw->path, fw);
1110 fw->entries = eina_list_append(fw->entries, entry);
1111 entry->watcher = fw;
1113 _request_add(&open_requests, (Entry *)entry, ref, rid, CSERVE2_OPEN);
1115 // _open_image_default_set(entry);
1121 cserve2_cache_file_close(Client *client, unsigned int client_file_id)
1123 Reference *ref = eina_hash_find(client->files.referencing,
1127 ERR("Couldn't find file %d in client hash.", client_file_id);
1132 if (ref->count <= 0)
1133 // will call _entry_free_cb() for this entry
1134 eina_hash_del_by_key(client->files.referencing, &client_file_id);
1138 cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg)
1141 File_Data *fentry = NULL;
1142 Reference *ref, *oldref;
1143 unsigned int image_id;
1146 oldref = eina_hash_find(client->images.referencing, &msg->image_id);
1148 // search whether the image is already loaded by another client
1149 entry = _image_msg_new(client, msg);
1152 image_id = _img_opts_id_get(entry, buf, sizeof(buf));
1154 { // if so, just update the references
1156 DBG("found image_id %d for client image id %d",
1157 image_id, msg->image_id);
1158 entry = eina_hash_find(image_entries, &image_id);
1161 ERR("image id %d is in file_ids hash, but not in entries hash"
1162 "with entry id %d.", msg->image_id, image_id);
1163 cserve2_client_error_send(client, msg->base.rid,
1164 CSERVE2_INVALID_CACHE);
1170 DBG("Re-using old image entry (id: %d) from the LRU list.",
1172 entry->unused = EINA_FALSE;
1173 image_entries_lru = eina_list_remove(image_entries_lru, entry);
1174 unused_mem_usage -= _image_entry_size_get(entry);
1177 if (oldref && (oldref->entry->id == image_id))
1180 ref = _entry_reference_add((Entry *)entry, client, msg->image_id);
1183 eina_hash_del_by_key(client->images.referencing, &msg->image_id);
1185 eina_hash_add(client->images.referencing, &msg->image_id, ref);
1190 image_id = _image_id++;
1191 while ((image_id == 0) || (eina_hash_find(image_entries, &image_id)))
1192 image_id = _image_id++;
1194 entry->base.id = image_id;
1195 eina_hash_add(image_entries, &image_id, entry);
1196 eina_hash_add(image_ids, buf, (void *)image_id);
1197 ref = _entry_reference_add((Entry *)entry, client, msg->image_id);
1200 eina_hash_del_by_key(client->images.referencing, &msg->image_id);
1201 eina_hash_add(client->images.referencing, &msg->image_id, ref);
1203 fentry = entry->file;
1204 fentry->images = eina_list_append(fentry->images, entry);
1206 _request_add(&spload_requests, (Entry *)entry, ref, msg->base.rid,
1212 cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid)
1217 ref = eina_hash_find(client->images.referencing, &client_image_id);
1220 ERR("Can't load: client %d has no image id %d",
1221 client->id, client_image_id);
1225 entry = (Image_Data *)ref->entry;
1227 if (entry->file->invalid)
1229 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
1233 DBG("Loading image id: %d", ref->entry->id);
1235 // File already being loaded, just add the request to be replied
1236 if (entry->base.request)
1238 _request_answer_add(entry->base.request, ref, rid, CSERVE2_LOAD);
1239 if ((!entry->base.request->processing) && (!entry->doload))
1241 DBG("Removing entry %d from speculative preload and adding "
1242 "to normal load queue.", entry->base.id);
1243 spload_requests = eina_list_remove(spload_requests,
1244 entry->base.request);
1245 load_requests = eina_list_append(load_requests,
1246 entry->base.request);
1249 else if (entry->shm)
1250 _image_loaded_send(client, entry, rid);
1252 _request_add(&load_requests, (Entry *)entry, ref, rid, CSERVE2_LOAD);
1254 entry->doload = EINA_TRUE;
1258 cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid)
1263 ref = eina_hash_find(client->images.referencing, &client_image_id);
1266 ERR("Can't load: client %d has no image id %d",
1267 client->id, client_image_id);
1271 entry = (Image_Data *)ref->entry;
1273 if (entry->file->invalid)
1275 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
1279 DBG("Loading image id: %d", ref->entry->id);
1281 // File already being loaded, just add the request to be replied
1282 if (entry->base.request)
1284 _request_answer_add(entry->base.request, ref, rid, CSERVE2_PRELOAD);
1285 if ((!entry->base.request->processing) && (!entry->doload))
1287 DBG("Removing entry %d from speculative preload and adding "
1288 "to normal (pre)load queue.", entry->base.id);
1289 spload_requests = eina_list_remove(spload_requests,
1290 entry->base.request);
1291 load_requests = eina_list_append(load_requests,
1292 entry->base.request);
1295 else if (entry->shm)
1296 _image_preloaded_send(client, rid);
1298 _request_add(&load_requests, (Entry *)entry, ref, rid, CSERVE2_PRELOAD);
1300 entry->doload = EINA_TRUE;
1304 cserve2_cache_image_unload(Client *client, unsigned int client_image_id)
1306 Reference *ref = eina_hash_find(client->images.referencing,
1310 ERR("Couldn't find file %d in client hash.", client_image_id);
1315 if (ref->count <= 0)
1316 // will call _entry_free_cb() for this entry
1317 eina_hash_del_by_key(client->images.referencing, &client_image_id);
1321 cserve2_cache_requests_response(Slave_Command type, void *msg, void *data)
1323 Request *req = data;
1328 DBG("Request finished but it has no entry anymore.");
1329 EINA_LIST_FREE(req->waiters, w)
1331 cserve2_client_error_send(w->ref->client, w->rid,
1332 CSERVE2_REQUEST_CANCEL);
1338 else if (type == ERROR)
1340 Error_Type *error = msg;
1341 req->funcs->error(req->entry, *error);
1344 req->funcs->response(req->entry, msg);
1347 req->entry->request = NULL;