1262 lines
34 KiB
C
1262 lines
34 KiB
C
|
#ifdef HAVE_CONFIG_H
|
||
|
# include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "evas_cserve2.h"
|
||
|
|
||
|
typedef struct _Request Request;
|
||
|
typedef struct _Entry Entry;
|
||
|
typedef struct _Reference Reference;
|
||
|
typedef struct _Waiter Waiter;
|
||
|
typedef struct _File_Data File_Data;
|
||
|
typedef struct _Image_Data Image_Data;
|
||
|
typedef struct _File_Watch File_Watch;
|
||
|
|
||
|
typedef enum {
|
||
|
CSERVE2_IMAGE_FILE,
|
||
|
CSERVE2_IMAGE_DATA
|
||
|
} Entry_Type;
|
||
|
|
||
|
struct _Request {
|
||
|
Entry *entry;
|
||
|
Eina_List *waiters;
|
||
|
Eina_Bool processing;
|
||
|
};
|
||
|
|
||
|
struct _File_Data {
|
||
|
char *path;
|
||
|
char *key;
|
||
|
int w, h;
|
||
|
int frame_count;
|
||
|
int loop_count;
|
||
|
int loop_hint;
|
||
|
const char *loader_data;
|
||
|
File_Watch *watcher;
|
||
|
Eina_List *images;
|
||
|
Eina_Bool alpha : 1;
|
||
|
Eina_Bool invalid : 1;
|
||
|
};
|
||
|
|
||
|
// Default values for load options commented below
|
||
|
struct _Image_Data {
|
||
|
unsigned int file_id;
|
||
|
Entry *file;
|
||
|
struct {
|
||
|
double dpi; // dpi < -1
|
||
|
int w, h; // w and h < -1
|
||
|
int scale_down; // scale_down < -1
|
||
|
int rx, ry, rw, rh; // rx, ry, rw, rh < -1
|
||
|
Eina_Bool orientation; // orientation == 0
|
||
|
} opts;
|
||
|
Shm_Handle *shm;
|
||
|
Eina_Bool alpha_sparse : 1;
|
||
|
Eina_Bool unused : 1;
|
||
|
Eina_Bool doload : 1;
|
||
|
};
|
||
|
|
||
|
struct _Entry {
|
||
|
unsigned int id;
|
||
|
Eina_List *references;
|
||
|
Request *request;
|
||
|
Entry_Type type;
|
||
|
union {
|
||
|
File_Data file;
|
||
|
Image_Data image;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
struct _Reference {
|
||
|
Client *client;
|
||
|
Entry *entry;
|
||
|
unsigned int client_entry_id; // for reverse lookup
|
||
|
int count;
|
||
|
};
|
||
|
|
||
|
struct _Waiter {
|
||
|
Reference *ref;
|
||
|
unsigned int rid;
|
||
|
Message_Type type;
|
||
|
};
|
||
|
|
||
|
struct _File_Watch {
|
||
|
const char *path;
|
||
|
Eina_List *entries;
|
||
|
};
|
||
|
|
||
|
static unsigned int _file_id = 0; // id unique number
|
||
|
static unsigned int _image_id = 0; // id unique number
|
||
|
static Eina_Hash *file_ids = NULL; // maps path + key --> file_id
|
||
|
static Eina_Hash *file_entries = NULL; // maps file_id --> entry
|
||
|
static Eina_List *open_requests = NULL;
|
||
|
|
||
|
static Eina_Hash *image_ids = NULL; // maps file id + load opts --> image id
|
||
|
static Eina_Hash *image_entries = NULL; // maps image_id --> entry
|
||
|
static Eina_List *load_requests = NULL;
|
||
|
static Eina_List *spload_requests = NULL; // speculative preload requests
|
||
|
|
||
|
static Eina_Hash *file_watch = NULL;
|
||
|
|
||
|
static Eina_List *image_entries_lru = NULL;
|
||
|
|
||
|
static int max_unused_mem_usage = 5 * 1024; /* in kbytes */
|
||
|
static int unused_mem_usage = 0;
|
||
|
|
||
|
static unsigned int
|
||
|
_img_opts_id_get(Image_Data *im, char *buf, int size)
|
||
|
{
|
||
|
uintptr_t image_id;
|
||
|
|
||
|
snprintf(buf, size, "%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:%d",
|
||
|
im->file_id, im->opts.dpi, im->opts.w, im->opts.h,
|
||
|
im->opts.scale_down, im->opts.rx, im->opts.ry,
|
||
|
im->opts.rw, im->opts.rh, im->opts.orientation);
|
||
|
|
||
|
image_id = (uintptr_t)eina_hash_find(image_ids, buf);
|
||
|
|
||
|
return image_id;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
_image_entry_size_get(Entry *e)
|
||
|
{
|
||
|
int size = sizeof(Entry);
|
||
|
/* XXX: get the overhead of the shm handler too */
|
||
|
if (e->image.shm)
|
||
|
size += cserve2_shm_size_get(e->image.shm);
|
||
|
return size / 1024;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_file_id_free(Entry *entry)
|
||
|
{
|
||
|
char buf[4096];
|
||
|
|
||
|
DBG("Removing entry file id: %d, file: \"%s:%s\"",
|
||
|
entry->id, entry->file.path, entry->file.key);
|
||
|
snprintf(buf, sizeof(buf), "%s:%s", entry->file.path, entry->file.key);
|
||
|
eina_hash_del_by_key(file_ids, buf);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_image_id_free(Entry *entry)
|
||
|
{
|
||
|
char buf[4096];
|
||
|
|
||
|
DBG("Removing entry image id: %d", entry->id);
|
||
|
|
||
|
_img_opts_id_get(&entry->image, buf, sizeof(buf));
|
||
|
eina_hash_del_by_key(image_ids, buf);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_image_entry_free(Entry *entry)
|
||
|
{
|
||
|
Entry *fentry = entry->image.file;
|
||
|
|
||
|
if (entry->request)
|
||
|
{
|
||
|
if (entry->request->processing)
|
||
|
entry->request->entry = NULL;
|
||
|
else if (!entry->request->waiters)
|
||
|
{
|
||
|
if (entry->image.doload)
|
||
|
load_requests = eina_list_remove(load_requests, entry->request);
|
||
|
else
|
||
|
spload_requests = eina_list_remove(spload_requests,
|
||
|
entry->request);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (entry->image.unused)
|
||
|
{
|
||
|
image_entries_lru = eina_list_remove(image_entries_lru, entry);
|
||
|
unused_mem_usage -= _image_entry_size_get(entry);
|
||
|
}
|
||
|
|
||
|
if (fentry)
|
||
|
fentry->file.images = eina_list_remove(fentry->file.images, entry);
|
||
|
if (entry->image.shm)
|
||
|
cserve2_shm_unref(entry->image.shm);
|
||
|
free(entry);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_hash_image_entry_free(void *data)
|
||
|
{
|
||
|
Entry *entry = data;
|
||
|
|
||
|
_image_id_free(entry);
|
||
|
_image_entry_free(entry);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_file_entry_free(Entry *entry)
|
||
|
{
|
||
|
File_Watch *fw;
|
||
|
|
||
|
// Should we call free for each of the images too?
|
||
|
// If everything goes fine, it's not necessary.
|
||
|
if (entry->file.images)
|
||
|
{
|
||
|
ERR("Freeing file %d (\"%s:%s\") image data still referenced.",
|
||
|
entry->id, entry->file.path, entry->file.key);
|
||
|
eina_list_free(entry->file.images);
|
||
|
}
|
||
|
|
||
|
if (entry->request)
|
||
|
{
|
||
|
if (entry->request->processing)
|
||
|
entry->request->entry = NULL;
|
||
|
else if (!entry->request->waiters)
|
||
|
{
|
||
|
open_requests = eina_list_remove(open_requests, entry->request);
|
||
|
free(entry->request);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((fw = entry->file.watcher))
|
||
|
{
|
||
|
fw->entries = eina_list_remove(fw->entries, entry);
|
||
|
if (!fw->entries)
|
||
|
eina_hash_del_by_key(file_watch, fw->path);
|
||
|
}
|
||
|
|
||
|
free(entry->file.key);
|
||
|
free(entry->file.path);
|
||
|
eina_stringshare_del(entry->file.loader_data);
|
||
|
free(entry);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_hash_file_entry_free(void *data)
|
||
|
{
|
||
|
Entry *entry = data;
|
||
|
// TODO: Add some checks to make sure that we are freeing an
|
||
|
// unused entry.
|
||
|
|
||
|
_file_id_free(entry);
|
||
|
_file_entry_free(entry);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_file_watch_free(void *data)
|
||
|
{
|
||
|
File_Watch *fw = data;
|
||
|
cserve2_file_change_watch_del(fw->path);
|
||
|
eina_stringshare_del(fw->path);
|
||
|
eina_list_free(fw->entries);
|
||
|
free(fw);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
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);
|
||
|
file_watch = eina_hash_string_superfast_new(_file_watch_free);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_shutdown(void)
|
||
|
{
|
||
|
eina_hash_free(image_entries);
|
||
|
eina_hash_free(image_ids);
|
||
|
eina_hash_free(file_entries);
|
||
|
eina_hash_free(file_ids);
|
||
|
eina_hash_free(file_watch);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_request_answer_del(Eina_List **requests, Request *req, Client *client, Error_Type err)
|
||
|
{
|
||
|
Eina_List *l, *l_next;
|
||
|
Waiter *it;
|
||
|
|
||
|
DBG("Removing answer requests from entry: %d, client: %d",
|
||
|
req->entry->id, client->id);
|
||
|
|
||
|
EINA_LIST_FOREACH_SAFE(req->waiters, l, l_next, it)
|
||
|
{
|
||
|
if (it->ref->client->id == client->id)
|
||
|
{
|
||
|
cserve2_client_error_send(client, it->rid, err);
|
||
|
req->waiters = eina_list_remove_list(req->waiters, l);
|
||
|
free(it);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// FIXME: Should this be really here? I guess that it should be in the
|
||
|
// entry_free_cb function, or entry_reference_del, when there are no more
|
||
|
// references
|
||
|
if (!req->waiters && !req->entry)
|
||
|
{
|
||
|
*requests = eina_list_remove(*requests, req);
|
||
|
free(req);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_request_answer_all_del(Eina_List **requests, Request *req, Error_Type err)
|
||
|
{
|
||
|
Waiter *it;
|
||
|
|
||
|
DBG("Removing all answer requests from entry: %d", req->entry->id);
|
||
|
|
||
|
EINA_LIST_FREE(req->waiters, it)
|
||
|
{
|
||
|
cserve2_client_error_send(it->ref->client, it->rid, err);
|
||
|
free(it);
|
||
|
}
|
||
|
|
||
|
*requests = eina_list_remove(*requests, req);
|
||
|
free(req);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
static void
|
||
|
_open_request_del(Request *req)
|
||
|
{
|
||
|
Waiter *it;
|
||
|
|
||
|
EINA_LIST_FREE(req->waiters, it)
|
||
|
free(it);
|
||
|
|
||
|
req->entry->request = NULL;
|
||
|
|
||
|
open_requests = eina_list_remove(open_requests, req);
|
||
|
free(req);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
_request_answer_add(Request *req, Reference *ref, unsigned int rid, Message_Type type)
|
||
|
{
|
||
|
Waiter *w = malloc(sizeof(*w));
|
||
|
|
||
|
w->ref = ref;
|
||
|
w->rid = rid;
|
||
|
w->type = type;
|
||
|
|
||
|
DBG("Add answer request for entry id: %d, client: %d, rid: %d",
|
||
|
req->entry->id, ref->client->id, rid);
|
||
|
req->waiters = eina_list_append(req->waiters, w);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_request_add(Eina_List **requests, Entry *entry, Reference *ref, unsigned int rid, Message_Type type)
|
||
|
{
|
||
|
Request *req;
|
||
|
|
||
|
// add the request if it doesn't exist yet
|
||
|
if (!entry->request)
|
||
|
{
|
||
|
req = malloc(sizeof(*req));
|
||
|
req->entry = entry;
|
||
|
req->waiters = NULL;
|
||
|
req->processing = EINA_FALSE;
|
||
|
entry->request = req;
|
||
|
*requests = eina_list_append(*requests, req);
|
||
|
DBG("Add request for entry id: %d, client: %d, rid: %d",
|
||
|
req->entry->id, ref->client->id, rid);
|
||
|
}
|
||
|
else
|
||
|
req = entry->request;
|
||
|
|
||
|
if (type != CSERVE2_SETOPTS)
|
||
|
_request_answer_add(req, ref, rid, type);
|
||
|
else
|
||
|
DBG("Adding entry for speculative preload: id=%d", req->entry->id);
|
||
|
}
|
||
|
|
||
|
static Reference *
|
||
|
_entry_reference_add(Entry *entry, Client *client, unsigned int client_entry_id)
|
||
|
{
|
||
|
Reference *ref;
|
||
|
|
||
|
// increase reference for this file
|
||
|
ref = malloc(sizeof(*ref));
|
||
|
ref->client = client;
|
||
|
ref->entry = entry;
|
||
|
ref->client_entry_id = client_entry_id;
|
||
|
ref->count = 1;
|
||
|
entry->references = eina_list_append(entry->references, ref);
|
||
|
|
||
|
return ref;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
_cserve2_cache_open_requests_process(int nloaders)
|
||
|
{
|
||
|
Request *req;
|
||
|
Slave_Msg_Image_Open msg;
|
||
|
Entry *entry;
|
||
|
char slave_cmd_data[4096];
|
||
|
int slave_cmd_size;
|
||
|
int path_len, key_len;
|
||
|
|
||
|
while ((nloaders > 0) && (open_requests))
|
||
|
{
|
||
|
|
||
|
// remove the first element from the list and process this element
|
||
|
req = eina_list_data_get(open_requests);
|
||
|
open_requests = eina_list_remove_list(open_requests, open_requests);
|
||
|
|
||
|
entry = req->entry;
|
||
|
DBG("Processing OPEN request for file entry: %d", entry->id);
|
||
|
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
memcpy(slave_cmd_data, &msg, sizeof(msg));
|
||
|
|
||
|
path_len = strlen(entry->file.path) + 1;
|
||
|
key_len = strlen(entry->file.key) + 1;
|
||
|
slave_cmd_size = sizeof(msg) + path_len + key_len;
|
||
|
memcpy(slave_cmd_data + sizeof(msg), entry->file.path, path_len);
|
||
|
memcpy(slave_cmd_data + sizeof(msg) + path_len, entry->file.key,
|
||
|
key_len);
|
||
|
cserve2_slave_cmd_dispatch(req, IMAGE_OPEN, slave_cmd_data,
|
||
|
slave_cmd_size);
|
||
|
|
||
|
req->processing = EINA_TRUE;
|
||
|
nloaders--;
|
||
|
}
|
||
|
|
||
|
return nloaders;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_image_preloaded_send(Client *client, unsigned int rid)
|
||
|
{
|
||
|
int size;
|
||
|
Msg_Preloaded msg;
|
||
|
|
||
|
DBG("Sending PRELOADED reply for RID: %d.", rid);
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
msg.base.rid = rid;
|
||
|
msg.base.type = CSERVE2_PRELOADED;
|
||
|
|
||
|
size = sizeof(msg);
|
||
|
cserve2_client_send(client, &size, sizeof(size));
|
||
|
cserve2_client_send(client, &msg, size);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_image_loaded_send(Client *client, Entry *entry, unsigned int rid)
|
||
|
{
|
||
|
int size;
|
||
|
const char *shmpath = cserve2_shm_name_get(entry->image.shm);
|
||
|
Msg_Loaded msg;
|
||
|
int path_len;
|
||
|
char *buf;
|
||
|
|
||
|
DBG("Sending LOADED reply for entry %d and RID: %d.", entry->id, rid);
|
||
|
path_len = strlen(shmpath) + 1;
|
||
|
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
msg.base.rid = rid;
|
||
|
msg.base.type = CSERVE2_LOADED;
|
||
|
|
||
|
msg.shm.mmap_offset = cserve2_shm_map_offset_get(entry->image.shm);
|
||
|
msg.shm.use_offset = cserve2_shm_offset_get(entry->image.shm);
|
||
|
msg.shm.mmap_size = cserve2_shm_map_size_get(entry->image.shm);
|
||
|
msg.shm.image_size = cserve2_shm_size_get(entry->image.shm);
|
||
|
msg.alpha_sparse = entry->image.alpha_sparse;
|
||
|
|
||
|
buf = malloc(sizeof(msg) + path_len);
|
||
|
|
||
|
memcpy(buf, &msg, sizeof(msg));
|
||
|
memcpy(buf + sizeof(msg), shmpath, path_len);
|
||
|
|
||
|
size = sizeof(msg) + path_len;
|
||
|
|
||
|
cserve2_client_send(client, &size, sizeof(size));
|
||
|
cserve2_client_send(client, buf, size);
|
||
|
|
||
|
free(buf);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_cserve2_cache_load_request_run(Request *req)
|
||
|
{
|
||
|
Entry *fentry;
|
||
|
Shm_Handle *shm;
|
||
|
const char *shmpath, *file, *key, *loader;
|
||
|
int shmlen, filelen, keylen, loaderlen;
|
||
|
Slave_Msg_Image_Load msg;
|
||
|
char *buf, *cur;
|
||
|
Entry *ientry;
|
||
|
size_t size;
|
||
|
|
||
|
ientry = req->entry;
|
||
|
|
||
|
fentry = ientry->image.file;
|
||
|
// opening shm for this file
|
||
|
shm = cserve2_shm_request(fentry->file.w * fentry->file.h * 4);
|
||
|
shmpath = cserve2_shm_name_get(shm);
|
||
|
shmlen = strlen(shmpath) + 1;
|
||
|
|
||
|
file = fentry->file.path;
|
||
|
filelen = strlen(file) + 1;
|
||
|
|
||
|
key = fentry->file.key;
|
||
|
keylen = strlen(key) + 1;
|
||
|
|
||
|
loader = fentry->file.loader_data;
|
||
|
if (!loader)
|
||
|
loaderlen = 0;
|
||
|
else
|
||
|
loaderlen = strlen(loader) + 1;
|
||
|
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
msg.w = ientry->image.file->file.w;
|
||
|
msg.h = ientry->image.file->file.h;
|
||
|
msg.alpha = ientry->image.file->file.alpha;
|
||
|
msg.opts.w = ientry->image.opts.w;
|
||
|
msg.opts.h = ientry->image.opts.h;
|
||
|
msg.opts.rx = ientry->image.opts.rx;
|
||
|
msg.opts.ry = ientry->image.opts.ry;
|
||
|
msg.opts.rw = ientry->image.opts.rw;
|
||
|
msg.opts.rh = ientry->image.opts.rh;
|
||
|
msg.opts.scale_down_by = ientry->image.opts.scale_down;
|
||
|
msg.opts.dpi = ientry->image.opts.dpi;
|
||
|
msg.opts.orientation = ientry->image.opts.orientation;
|
||
|
|
||
|
msg.shm.mmap_offset = cserve2_shm_map_offset_get(shm);
|
||
|
msg.shm.image_offset = cserve2_shm_offset_get(shm);
|
||
|
msg.shm.mmap_size = cserve2_shm_map_size_get(shm);
|
||
|
msg.shm.image_size = cserve2_shm_size_get(shm);
|
||
|
|
||
|
msg.has_loader_data = !!loaderlen;
|
||
|
|
||
|
size = sizeof(msg) + shmlen + filelen + keylen + loaderlen;
|
||
|
|
||
|
buf = calloc(1, size);
|
||
|
|
||
|
memcpy(buf, &msg, sizeof(msg));
|
||
|
cur = buf + sizeof(msg);
|
||
|
memcpy(cur, shmpath, shmlen);
|
||
|
|
||
|
cur += shmlen;
|
||
|
memcpy(cur, file, filelen);
|
||
|
|
||
|
cur += filelen;
|
||
|
memcpy(cur, key, keylen);
|
||
|
|
||
|
cur += keylen;
|
||
|
memcpy(cur, loader, loaderlen);
|
||
|
|
||
|
ientry->image.shm = shm;
|
||
|
|
||
|
cserve2_slave_cmd_dispatch(req, IMAGE_LOAD, buf, size);
|
||
|
|
||
|
free(buf);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
_cserve2_cache_load_requests_list_process(Eina_List **queue, int nloaders)
|
||
|
{
|
||
|
Eina_List *skipped = NULL;
|
||
|
Request *req;
|
||
|
|
||
|
while ((nloaders > 0) && (*queue))
|
||
|
{
|
||
|
// remove the first element from the list and process this element
|
||
|
req = eina_list_data_get(*queue);
|
||
|
*queue = eina_list_remove_list(*queue, *queue);
|
||
|
|
||
|
if (!req->entry->image.file)
|
||
|
{
|
||
|
ERR("File entry doesn't exist for entry id %d", req->entry->id);
|
||
|
cserve2_cache_request_failed(req, CSERVE2_INVALID_CACHE);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (req->entry->image.file->request)
|
||
|
{
|
||
|
/* OPEN still pending, skip this request */
|
||
|
skipped = eina_list_append(skipped, req);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
DBG("Processing LOAD request for image entry: %d", req->entry->id);
|
||
|
|
||
|
_cserve2_cache_load_request_run(req);
|
||
|
|
||
|
req->processing = EINA_TRUE;
|
||
|
|
||
|
nloaders--;
|
||
|
}
|
||
|
|
||
|
EINA_LIST_FREE(skipped, req)
|
||
|
*queue = eina_list_append(*queue, req);
|
||
|
|
||
|
return nloaders;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_cserve2_cache_load_requests_process(int nloaders)
|
||
|
{
|
||
|
nloaders = _cserve2_cache_load_requests_list_process(&load_requests,
|
||
|
nloaders);
|
||
|
_cserve2_cache_load_requests_list_process(&spload_requests, nloaders - 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
cserve2_cache_requests_process(void)
|
||
|
{
|
||
|
int avail_loaders;
|
||
|
|
||
|
avail_loaders = cserve2_slave_available_get();
|
||
|
avail_loaders = _cserve2_cache_open_requests_process(avail_loaders);
|
||
|
_cserve2_cache_load_requests_process(avail_loaders);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_entry_unused_push(Entry *e)
|
||
|
{
|
||
|
int size = _image_entry_size_get(e);
|
||
|
|
||
|
if ((size > max_unused_mem_usage) || !(e->image.doload))
|
||
|
{
|
||
|
eina_hash_del_by_key(image_entries, &e->id);
|
||
|
return;
|
||
|
}
|
||
|
while (size > (max_unused_mem_usage - unused_mem_usage))
|
||
|
{
|
||
|
Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
|
||
|
eina_hash_del_by_key(image_entries, &ie->id);
|
||
|
}
|
||
|
image_entries_lru = eina_list_append(image_entries_lru, e);
|
||
|
e->image.unused = EINA_TRUE;
|
||
|
unused_mem_usage += size;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_entry_reference_del(Entry *entry, Reference *ref)
|
||
|
{
|
||
|
entry->references = eina_list_remove(entry->references, ref);
|
||
|
|
||
|
if (entry->references)
|
||
|
goto free_ref;
|
||
|
|
||
|
if (entry->type == CSERVE2_IMAGE_FILE)
|
||
|
{
|
||
|
if (entry->file.invalid)
|
||
|
_file_entry_free(entry);
|
||
|
else
|
||
|
{
|
||
|
if (entry->file.images)
|
||
|
{
|
||
|
Entry *ie;
|
||
|
EINA_LIST_FREE(entry->file.images, ie)
|
||
|
ie->image.file = NULL;
|
||
|
entry->file.images = NULL;
|
||
|
}
|
||
|
eina_hash_del_by_key(file_entries, &entry->id);
|
||
|
}
|
||
|
}
|
||
|
else if (entry->type == CSERVE2_IMAGE_DATA)
|
||
|
{
|
||
|
if (!entry->image.file)
|
||
|
eina_hash_del_by_key(image_entries, &entry->id);
|
||
|
else if (entry->image.file->file.invalid)
|
||
|
_image_entry_free(entry);
|
||
|
else
|
||
|
_entry_unused_push(entry);
|
||
|
}
|
||
|
else
|
||
|
ERR("Wrong type of entry.");
|
||
|
|
||
|
free_ref:
|
||
|
free(ref);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
_entry_free_cb(void *data)
|
||
|
{
|
||
|
Reference *ref = data;
|
||
|
Entry *entry;
|
||
|
|
||
|
DBG("Removing client reference for entry id: %d, client: %d",
|
||
|
ref->entry->id, ref->client->id);
|
||
|
|
||
|
entry = ref->entry;
|
||
|
|
||
|
if (entry->request && !entry->request->processing)
|
||
|
{
|
||
|
if (entry->type == CSERVE2_IMAGE_FILE)
|
||
|
_request_answer_del(&open_requests, entry->request, ref->client,
|
||
|
CSERVE2_REQUEST_CANCEL);
|
||
|
else
|
||
|
{
|
||
|
if (entry->image.doload)
|
||
|
_request_answer_del(&load_requests, entry->request,
|
||
|
ref->client, CSERVE2_REQUEST_CANCEL);
|
||
|
else
|
||
|
_request_answer_del(&spload_requests, entry->request,
|
||
|
ref->client, CSERVE2_REQUEST_CANCEL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_entry_reference_del(entry, ref);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_client_new(Client *client)
|
||
|
{
|
||
|
client->files.referencing = eina_hash_int32_new(_entry_free_cb);
|
||
|
client->images.referencing = eina_hash_int32_new(_entry_free_cb);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_client_del(Client *client)
|
||
|
{
|
||
|
// will call _entry_free_cb() for every entry
|
||
|
eina_hash_free(client->images.referencing);
|
||
|
// will call _entry_free_cb() for every entry
|
||
|
eina_hash_free(client->files.referencing);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
_image_opened_send(Client *client, Entry *entry, unsigned int rid)
|
||
|
{
|
||
|
int size;
|
||
|
Msg_Opened msg;
|
||
|
|
||
|
DBG("Sending OPENED reply for entry: %d and RID: %d.", entry->id, rid);
|
||
|
// clear the struct with possible paddings, since it is not aligned.
|
||
|
memset(&msg, 0, sizeof(msg));
|
||
|
msg.base.rid = rid;
|
||
|
msg.base.type = CSERVE2_OPENED;
|
||
|
msg.image.w = entry->file.w;
|
||
|
msg.image.h = entry->file.h;
|
||
|
msg.image.frame_count = entry->file.frame_count;
|
||
|
msg.image.loop_count = entry->file.loop_count;
|
||
|
msg.image.loop_hint = entry->file.loop_hint;
|
||
|
msg.image.alpha = entry->file.alpha;
|
||
|
|
||
|
size = sizeof(msg);
|
||
|
cserve2_client_send(client, &size, sizeof(size));
|
||
|
cserve2_client_send(client, &msg, sizeof(msg));
|
||
|
// _cserve2_cache_load_requests_process();
|
||
|
}
|
||
|
|
||
|
static Entry *
|
||
|
_image_msg_new(Client *client, Msg_Setopts *msg)
|
||
|
{
|
||
|
Reference *ref;
|
||
|
Entry *im_entry;
|
||
|
|
||
|
ref = eina_hash_find(client->files.referencing, &msg->file_id);
|
||
|
if (!ref)
|
||
|
{
|
||
|
ERR("Couldn't find file id: %d, for image id: %d",
|
||
|
msg->file_id, msg->image_id);
|
||
|
cserve2_client_error_send(client, msg->base.rid,
|
||
|
CSERVE2_INVALID_CACHE);
|
||
|
return NULL;
|
||
|
}
|
||
|
if (ref->entry->file.invalid)
|
||
|
{
|
||
|
cserve2_client_error_send(client, msg->base.rid,
|
||
|
CSERVE2_FILE_CHANGED);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
im_entry = calloc(1, sizeof(*im_entry));
|
||
|
im_entry->type = CSERVE2_IMAGE_DATA;
|
||
|
im_entry->image.file_id = ref->entry->id;
|
||
|
im_entry->image.file = ref->entry;
|
||
|
im_entry->image.opts.dpi = msg->opts.dpi;
|
||
|
im_entry->image.opts.w = msg->opts.w;
|
||
|
im_entry->image.opts.h = msg->opts.h;
|
||
|
im_entry->image.opts.scale_down = msg->opts.scale_down;
|
||
|
im_entry->image.opts.rx = msg->opts.rx;
|
||
|
im_entry->image.opts.ry = msg->opts.ry;
|
||
|
im_entry->image.opts.rw = msg->opts.rw;
|
||
|
im_entry->image.opts.rh = msg->opts.rh;
|
||
|
im_entry->image.opts.orientation = msg->opts.orientation;
|
||
|
|
||
|
return im_entry;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
static Entry *
|
||
|
_image_default_new(Entry *file_entry)
|
||
|
{
|
||
|
Entry *im_entry = calloc(1, sizeof(*im_entry));
|
||
|
im_entry->image.file_id = file_entry->id;
|
||
|
im_entry->image.opts.dpi = -1;
|
||
|
im_entry->image.opts.w = -1;
|
||
|
im_entry->image.opts.h = -1;
|
||
|
im_entry->image.opts.scale_down = -1;
|
||
|
im_entry->image.opts.rx = -1;
|
||
|
im_entry->image.opts.ry = -1;
|
||
|
im_entry->image.opts.rw = -1;
|
||
|
im_entry->image.opts.rh = -1;
|
||
|
im_entry->image.opts.orientation = 0;
|
||
|
|
||
|
return im_entry;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
static void
|
||
|
_file_changed_cb(const char *path __UNUSED__, Eina_Bool deleted __UNUSED__, void *data)
|
||
|
{
|
||
|
File_Watch *fw = data;
|
||
|
Entry *e;
|
||
|
Eina_List *l;
|
||
|
|
||
|
EINA_LIST_FOREACH(fw->entries, l, e)
|
||
|
{
|
||
|
Eina_List *ll;
|
||
|
Entry *ie;
|
||
|
|
||
|
e->file.invalid = EINA_TRUE;
|
||
|
e->file.watcher = NULL;
|
||
|
|
||
|
EINA_LIST_FOREACH(e->file.images, ll, ie)
|
||
|
{
|
||
|
_image_id_free(ie);
|
||
|
eina_hash_set(image_entries, &ie->id, NULL);
|
||
|
if (ie->request && !ie->request->processing)
|
||
|
{
|
||
|
if (ie->image.doload)
|
||
|
_request_answer_all_del(&load_requests, ie->request,
|
||
|
CSERVE2_FILE_CHANGED);
|
||
|
else
|
||
|
_request_answer_all_del(&spload_requests, ie->request,
|
||
|
CSERVE2_FILE_CHANGED);
|
||
|
}
|
||
|
ie->request = NULL;
|
||
|
if (ie->image.unused)
|
||
|
_image_entry_free(ie);
|
||
|
}
|
||
|
|
||
|
_file_id_free(e);
|
||
|
eina_hash_set(file_entries, &e->id, NULL);
|
||
|
if (e->request && !e->request->processing)
|
||
|
_request_answer_all_del(&open_requests, ie->request,
|
||
|
CSERVE2_FILE_CHANGED);
|
||
|
e->request = NULL;
|
||
|
if (!e->file.images && !e->references)
|
||
|
_file_entry_free(e);
|
||
|
}
|
||
|
|
||
|
eina_hash_del_by_key(file_watch, fw->path);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid)
|
||
|
{
|
||
|
uintptr_t file_id;
|
||
|
Entry *entry;
|
||
|
Reference *ref;
|
||
|
File_Watch *fw;
|
||
|
char buf[4906];
|
||
|
|
||
|
// look for this file on client references
|
||
|
ref = eina_hash_find(client->files.referencing, &client_file_id);
|
||
|
if (ref)
|
||
|
{
|
||
|
entry = ref->entry;
|
||
|
|
||
|
if (entry->file.invalid)
|
||
|
{
|
||
|
cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
DBG("found client file id: %d", client_file_id);
|
||
|
ref->count++;
|
||
|
|
||
|
// File already being loaded, just add the request to be replied
|
||
|
if (entry->request)
|
||
|
_request_answer_add(entry->request, ref, rid, CSERVE2_OPEN);
|
||
|
else
|
||
|
_image_opened_send(client, entry, rid);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// search whether the file is already opened by another client
|
||
|
snprintf(buf, sizeof(buf), "%s:%s", path, key);
|
||
|
file_id = (uintptr_t)eina_hash_find(file_ids, buf);
|
||
|
if (file_id)
|
||
|
{
|
||
|
DBG("found file_id %d for client file id %d",
|
||
|
file_id, client_file_id);
|
||
|
entry = eina_hash_find(file_entries, &file_id);
|
||
|
if (!entry)
|
||
|
{
|
||
|
ERR("file \"%s\" is in file_ids hash but not in entries hash.",
|
||
|
buf);
|
||
|
cserve2_client_error_send(client, rid, CSERVE2_INVALID_CACHE);
|
||
|
return -1;
|
||
|
}
|
||
|
ref = _entry_reference_add(entry, client, client_file_id);
|
||
|
eina_hash_add(client->files.referencing, &client_file_id, ref);
|
||
|
if (entry->request)
|
||
|
_request_answer_add(entry->request, ref, rid, CSERVE2_OPEN);
|
||
|
else // File already loaded, otherwise there would be a request
|
||
|
_image_opened_send(client, entry, rid);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
file_id = _file_id++;
|
||
|
while ((file_id == 0) || (eina_hash_find(file_entries, &file_id)))
|
||
|
file_id = _file_id++;
|
||
|
|
||
|
DBG("Creating new entry with file_id: %d for file \"%s:%s\"",
|
||
|
file_id, path, key);
|
||
|
entry = calloc(1, sizeof(*entry));
|
||
|
entry->type = CSERVE2_IMAGE_FILE;
|
||
|
entry->file.path = strdup(path);
|
||
|
entry->file.key = strdup(key);
|
||
|
entry->id = file_id;
|
||
|
eina_hash_add(file_entries, &file_id, entry);
|
||
|
eina_hash_add(file_ids, buf, (void *)file_id);
|
||
|
ref = _entry_reference_add(entry, client, client_file_id);
|
||
|
eina_hash_add(client->files.referencing, &client_file_id, ref);
|
||
|
|
||
|
fw = eina_hash_find(file_watch, entry->file.path);
|
||
|
if (!fw)
|
||
|
{
|
||
|
fw = calloc(1, sizeof(File_Watch));
|
||
|
fw->path = eina_stringshare_add(entry->file.path);
|
||
|
cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw);
|
||
|
eina_hash_direct_add(file_watch, fw->path, fw);
|
||
|
}
|
||
|
fw->entries = eina_list_append(fw->entries, entry);
|
||
|
entry->file.watcher = fw;
|
||
|
|
||
|
_request_add(&open_requests, entry, ref, rid, CSERVE2_OPEN);
|
||
|
|
||
|
// _open_image_default_set(entry);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_file_close(Client *client, unsigned int client_file_id)
|
||
|
{
|
||
|
Reference *ref = eina_hash_find(client->files.referencing,
|
||
|
&client_file_id);
|
||
|
if (!ref)
|
||
|
{
|
||
|
ERR("Couldn't find file %d in client hash.", client_file_id);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ref->count--;
|
||
|
if (ref->count <= 0)
|
||
|
// will call _entry_free_cb() for this entry
|
||
|
eina_hash_del_by_key(client->files.referencing, &client_file_id);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
cserve2_cache_image_opts_set(Client *client, Msg_Setopts *msg)
|
||
|
{
|
||
|
Entry *entry;
|
||
|
Entry *fentry = NULL;
|
||
|
Reference *ref, *oldref;
|
||
|
unsigned int image_id;
|
||
|
char buf[4096];
|
||
|
|
||
|
oldref = eina_hash_find(client->images.referencing, &msg->image_id);
|
||
|
|
||
|
// search whether the image is already loaded by another client
|
||
|
entry = _image_msg_new(client, msg);
|
||
|
if (!entry)
|
||
|
return -1;
|
||
|
image_id = _img_opts_id_get(&entry->image, buf, sizeof(buf));
|
||
|
if (image_id)
|
||
|
{ // if so, just update the references
|
||
|
free(entry);
|
||
|
DBG("found image_id %d for client image id %d",
|
||
|
image_id, msg->image_id);
|
||
|
entry = eina_hash_find(image_entries, &image_id);
|
||
|
if (!entry)
|
||
|
{
|
||
|
ERR("image id %d is in file_ids hash, but not in entries hash"
|
||
|
"with entry id %d.", msg->image_id, image_id);
|
||
|
cserve2_client_error_send(client, msg->base.rid,
|
||
|
CSERVE2_INVALID_CACHE);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (entry->image.unused)
|
||
|
{
|
||
|
DBG("Re-using old image entry (id: %d) from the LRU list.",
|
||
|
entry->id);
|
||
|
entry->image.unused = EINA_FALSE;
|
||
|
image_entries_lru = eina_list_remove(image_entries_lru, entry);
|
||
|
unused_mem_usage -= _image_entry_size_get(entry);
|
||
|
}
|
||
|
|
||
|
if (oldref && (oldref->entry->id == image_id))
|
||
|
return 0;
|
||
|
|
||
|
ref = _entry_reference_add(entry, client, msg->image_id);
|
||
|
|
||
|
if (oldref)
|
||
|
eina_hash_del_by_key(client->images.referencing, &msg->image_id);
|
||
|
|
||
|
eina_hash_add(client->images.referencing, &msg->image_id, ref);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
image_id = _image_id++;
|
||
|
while ((image_id == 0) || (eina_hash_find(image_entries, &image_id)))
|
||
|
image_id = _image_id++;
|
||
|
|
||
|
entry->id = image_id;
|
||
|
eina_hash_add(image_entries, &image_id, entry);
|
||
|
eina_hash_add(image_ids, buf, (void *)image_id);
|
||
|
ref = _entry_reference_add(entry, client, msg->image_id);
|
||
|
|
||
|
if (oldref)
|
||
|
eina_hash_del_by_key(client->images.referencing, &msg->image_id);
|
||
|
eina_hash_add(client->images.referencing, &msg->image_id, ref);
|
||
|
|
||
|
fentry = entry->image.file;
|
||
|
fentry->file.images = eina_list_append(fentry->file.images, entry);
|
||
|
|
||
|
_request_add(&spload_requests, entry, ref, msg->base.rid, CSERVE2_SETOPTS);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid)
|
||
|
{
|
||
|
Entry *entry;
|
||
|
Reference *ref;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
if (ref->entry->image.file->file.invalid)
|
||
|
{
|
||
|
cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DBG("Loading image id: %d", ref->entry->id);
|
||
|
|
||
|
entry = ref->entry;
|
||
|
|
||
|
// File already being loaded, just add the request to be replied
|
||
|
if (entry->request)
|
||
|
{
|
||
|
_request_answer_add(entry->request, ref, rid, CSERVE2_LOAD);
|
||
|
if ((!entry->request->processing) && (!entry->image.doload))
|
||
|
{
|
||
|
DBG("Removing entry %d from speculative preload and adding "
|
||
|
"to normal load queue.", entry->id);
|
||
|
spload_requests = eina_list_remove(spload_requests,
|
||
|
entry->request);
|
||
|
load_requests = eina_list_append(load_requests, entry->request);
|
||
|
}
|
||
|
}
|
||
|
else if (entry->image.shm)
|
||
|
_image_loaded_send(client, entry, rid);
|
||
|
else
|
||
|
_request_add(&load_requests, entry, ref, rid, CSERVE2_LOAD);
|
||
|
|
||
|
entry->image.doload = EINA_TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid)
|
||
|
{
|
||
|
Entry *entry;
|
||
|
Reference *ref;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
if (ref->entry->image.file->file.invalid)
|
||
|
{
|
||
|
cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DBG("Loading image id: %d", ref->entry->id);
|
||
|
|
||
|
entry = ref->entry;
|
||
|
|
||
|
// File already being loaded, just add the request to be replied
|
||
|
if (entry->request)
|
||
|
{
|
||
|
_request_answer_add(entry->request, ref, rid, CSERVE2_PRELOAD);
|
||
|
if ((!entry->request->processing) && (!entry->image.doload))
|
||
|
{
|
||
|
DBG("Removing entry %d from speculative preload and adding "
|
||
|
"to normal (pre)load queue.", entry->id);
|
||
|
spload_requests = eina_list_remove(spload_requests,
|
||
|
entry->request);
|
||
|
load_requests = eina_list_append(load_requests, entry->request);
|
||
|
}
|
||
|
}
|
||
|
else if (entry->image.shm)
|
||
|
_image_preloaded_send(client, rid);
|
||
|
else
|
||
|
_request_add(&load_requests, entry, ref, rid, CSERVE2_PRELOAD);
|
||
|
|
||
|
entry->image.doload = EINA_TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_image_unload(Client *client, unsigned int client_image_id)
|
||
|
{
|
||
|
Reference *ref = eina_hash_find(client->images.referencing,
|
||
|
&client_image_id);
|
||
|
if (!ref)
|
||
|
{
|
||
|
ERR("Couldn't find file %d in client hash.", client_image_id);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ref->count--;
|
||
|
if (ref->count <= 0)
|
||
|
// will call _entry_free_cb() for this entry
|
||
|
eina_hash_del_by_key(client->images.referencing, &client_image_id);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_request_opened(Slave_Msg_Image_Opened *resp, void *data)
|
||
|
{
|
||
|
Waiter *w;
|
||
|
Request *req = data;
|
||
|
Entry *entry;
|
||
|
|
||
|
entry = req->entry;
|
||
|
if (!entry)
|
||
|
{
|
||
|
Error_Type err = entry->file.invalid
|
||
|
? CSERVE2_FILE_CHANGED
|
||
|
: CSERVE2_REQUEST_CANCEL;
|
||
|
DBG("File entry for request doesn't exist anymore.");
|
||
|
cserve2_cache_request_failed(req, err);
|
||
|
entry->request = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
entry->request = NULL;
|
||
|
|
||
|
entry->file.w = resp->w;
|
||
|
entry->file.h = resp->h;
|
||
|
entry->file.frame_count = resp->frame_count;
|
||
|
entry->file.loop_count = resp->loop_count;
|
||
|
entry->file.loop_hint = resp->loop_hint;
|
||
|
entry->file.alpha = resp->alpha;
|
||
|
if (resp->has_loader_data)
|
||
|
{
|
||
|
const char *ldata = (const char *)resp +
|
||
|
sizeof(Slave_Msg_Image_Opened);
|
||
|
entry->file.loader_data = eina_stringshare_add(ldata);
|
||
|
}
|
||
|
|
||
|
DBG("Finished opening file %d. Notifying %d waiters.", entry->id,
|
||
|
req->waiters ? eina_list_count(req->waiters) : 0);
|
||
|
EINA_LIST_FREE(req->waiters, w)
|
||
|
{
|
||
|
_image_opened_send(w->ref->client, entry, w->rid);
|
||
|
free(w);
|
||
|
}
|
||
|
|
||
|
free(req);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_request_loaded(Slave_Msg_Image_Loaded *resp, void *data)
|
||
|
{
|
||
|
Waiter *w;
|
||
|
Request *req = data;
|
||
|
Entry *entry;
|
||
|
|
||
|
entry = req->entry;
|
||
|
if (!entry)
|
||
|
{
|
||
|
// FIXME: Wouldn't we keep the entry alive when the file changed
|
||
|
// until we send the errors needed and just then delete it? Right now
|
||
|
// the check below just makes no sense.
|
||
|
// Error_Type err = entry->image.file->file.invalid
|
||
|
// ? CSERVE2_FILE_CHANGED
|
||
|
// : CSERVE2_REQUEST_CANCEL;
|
||
|
DBG("Image entry for request doesn't exist anymore.");
|
||
|
cserve2_cache_request_failed(req, CSERVE2_REQUEST_CANCEL);
|
||
|
entry->request = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
entry->request = NULL;
|
||
|
entry->image.alpha_sparse = resp->alpha_sparse;
|
||
|
if (!entry->image.doload)
|
||
|
DBG("Entry %d loaded by speculative preload.", entry->id);
|
||
|
|
||
|
DBG("Finished loading image %d. Notifying %d waiters.", entry->id,
|
||
|
req->waiters ? eina_list_count(req->waiters) : 0);
|
||
|
EINA_LIST_FREE(req->waiters, w)
|
||
|
{
|
||
|
if (w->type == CSERVE2_LOAD)
|
||
|
_image_loaded_send(w->ref->client, entry, w->rid);
|
||
|
else if (w->type == CSERVE2_PRELOAD)
|
||
|
_image_preloaded_send(w->ref->client, w->rid);
|
||
|
// else w->type == CSERVE2_SETOPTS --> do nothing
|
||
|
|
||
|
free(w);
|
||
|
}
|
||
|
|
||
|
free(req);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
cserve2_cache_request_failed(void *data, Error_Type type)
|
||
|
{
|
||
|
Waiter *w;
|
||
|
Request *req = data;
|
||
|
Entry *entry;
|
||
|
Eina_List *l;
|
||
|
Reference *ref;
|
||
|
|
||
|
DBG("Request for entry %p failed with error %d", req->entry, type);
|
||
|
EINA_LIST_FREE(req->waiters, w)
|
||
|
{
|
||
|
cserve2_client_error_send(w->ref->client, w->rid, type);
|
||
|
|
||
|
w->ref->count--;
|
||
|
free(w);
|
||
|
}
|
||
|
|
||
|
entry = req->entry;
|
||
|
if (!entry)
|
||
|
goto free_req;
|
||
|
|
||
|
EINA_LIST_FOREACH(entry->references, l, ref)
|
||
|
{
|
||
|
Eina_Hash *hash;
|
||
|
if (entry->type == CSERVE2_IMAGE_FILE)
|
||
|
hash = ref->client->files.referencing;
|
||
|
else if (entry->type == CSERVE2_IMAGE_DATA)
|
||
|
hash = ref->client->images.referencing;
|
||
|
|
||
|
eina_hash_del_by_key(hash, &(ref->client_entry_id));
|
||
|
}
|
||
|
|
||
|
free_req:
|
||
|
free(req);
|
||
|
}
|