#include "evas_cserve2.h"
-struct _Font_Request {
+#define MAX_SLAVES 1
+
+typedef enum
+{
+ SLAVE_IMAGE,
+ SLAVE_FONT,
+ SLAVE_NONE
+} Slave_Type;
+
+struct _Slave_Worker
+{
+ void *data;
+ Slave *slave;
+ Eina_Binbuf *ret;
+ int ret_size;
+ Eina_Bool done;
+ Eina_Bool delete_me;
+};
+
+typedef struct _Slave_Worker Slave_Worker;
+
+/* This struct is used to match font request types to the respective slave
+ * type, and the message type that will be used for that request. The order
+ * of the request types on it is the order in which these requests will
+ * be processed.
+ */
+static struct _Request_Match
+{
+ Font_Request_Type rtype;
+ Slave_Type stype;
+ Message_Type mtype;
+} _request_match[] =
+{
+ { CSERVE2_REQ_FONT_LOAD, SLAVE_FONT, CSERVE2_FONT_LOAD },
+ { CSERVE2_REQ_FONT_GLYPHS_LOAD, SLAVE_FONT, CSERVE2_FONT_GLYPHS_LOAD },
+ { CSERVE2_REQ_LAST, 0 }
+};
+
+static Slave *_create_image_slave(void *data);
+static Slave *_create_font_slave(void *data);
+
+static struct _Worker
+{
+ Slave_Type type;
+ unsigned int max;
+ Eina_List *idle;
+ Eina_List *working;
+ Slave *(*create_slave)(void *data);
+} _workers[] =
+{
+ { SLAVE_IMAGE, 3, NULL, NULL, _create_image_slave },
+ { SLAVE_FONT, 1, NULL, NULL, _create_font_slave },
+};
+
+struct _Font_Request
+{
Font_Request_Type type;
void *data;
+ void *msg;
Eina_List *waiters;
Eina_Bool processing;
Font_Request_Funcs *funcs;
};
-struct _Waiter {
+struct _Waiter
+{
unsigned int rid;
Client *client;
};
DBG("Removing answer from waiter client: %d, rid: %d",
client->id, w->rid);
if (req->funcs && req->funcs->error)
- req->funcs->error(client, req->data, err);
+ req->funcs->error(client, req->data, err, w->rid);
req->waiters = eina_list_remove_list(req->waiters, l);
free(w);
}
{
Eina_List **reqlist = &requests[req->type];
*reqlist = eina_list_remove(*reqlist, req);
+ req->funcs->msg_free(req->msg);
free(req);
}
DBG("Removing answer from waiter client: %d, rid: %d",
w->client->id, w->rid);
if (req->funcs && req->funcs->error)
- req->funcs->error(w->client, req->data, err);
+ req->funcs->error(w->client, req->data, err, w->rid);
free(w);
}
requests[req->type] = eina_list_remove(requests[req->type], req);
+ req->funcs->msg_free(req->msg);
free(req);
}
DBG("Shutting down requests.");
free(requests);
}
+
+static void
+_image_slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd __UNUSED__, void *msg __UNUSED__, void *data __UNUSED__)
+{
+}
+
+static void
+_image_slave_dead_cb(Slave *s __UNUSED__, void *data __UNUSED__)
+{
+}
+
+static Slave *
+_create_image_slave(void *data)
+{
+ char *exe;
+ Slave *slave;
+
+ exe = getenv("EVAS_CSERVE2_SLAVE");
+ if (!exe) exe = "evas_cserve2_slave";
+
+ slave = cserve2_slave_run(exe, _image_slave_read_cb,
+ _image_slave_dead_cb, data);
+
+ return slave;
+}
+
+static Slave *
+_create_font_slave(void *data __UNUSED__)
+{
+ return NULL;
+}
+
+static Slave_Worker *
+_slave_for_request_create(Slave_Type type)
+{
+ Slave_Worker *sw;
+ Slave *slave;
+
+ sw = calloc(1, sizeof(Slave_Worker));
+ if (!sw) return NULL;
+
+ slave = _workers[type].create_slave(sw);
+ if (!slave)
+ {
+ ERR("Could not launch slave process");
+ free(sw);
+ return NULL;
+ }
+
+ sw->slave = slave;
+ _workers[type].idle = eina_list_append(_workers[type].idle, sw);
+
+ return sw;
+}
+
+static Eina_Bool
+_cserve2_request_dispatch(Slave_Worker *sw, Message_Type mtype, Font_Request *req)
+{
+ int size;
+ char *slave_msg = req->funcs->msg_create(req->data, &size);
+
+ if (!slave_msg)
+ {
+ ERR("Could not create slave message for request type %d.", req->type);
+ return EINA_FALSE;
+ }
+
+ req->msg = slave_msg;
+ sw->data = req;
+ cserve2_slave_send(sw->slave, mtype, slave_msg, size);
+ req->processing = EINA_TRUE;
+
+ return EINA_TRUE;
+}
+
+static void
+_cserve2_request_failed(Font_Request *req, Error_Type type)
+{
+ Waiter *w;
+
+ EINA_LIST_FREE(req->waiters, w)
+ {
+ req->funcs->error(w->client, req->data, type, w->rid);
+ free(w);
+ }
+
+ req->funcs->msg_free(req->msg);
+ free(req);
+}
+
+void
+cserve2_requests_process(void)
+{
+ int rtype, j;
+
+ for (rtype = 0; rtype < CSERVE2_REQ_LAST; rtype++)
+ {
+ Slave_Type type = SLAVE_NONE;
+ Message_Type mtype;
+ unsigned int max_workers;
+ Eina_List **idle, **working;
+
+ for (j = 0; _request_match[j].rtype != CSERVE2_REQ_LAST; j++)
+ {
+ if (_request_match[j].rtype == j)
+ {
+ type = _request_match[j].stype;
+ mtype = _request_match[j].mtype;
+ break;
+ }
+ }
+
+ if (type == SLAVE_NONE)
+ continue;
+
+ if (!requests[rtype])
+ continue;
+
+ /* Now we have the worker type to use (image or font), and the list
+ * of requests to process. Just process as many requests as we can.
+ */
+ max_workers = _workers[type].max;
+ idle = &_workers[type].idle;
+ working = &_workers[type].working;
+
+ while (requests[j] &&
+ (eina_list_count(*working) < max_workers))
+ {
+ Slave_Worker *sw;
+ Font_Request *req = eina_list_data_get(requests[rtype]);
+ requests[rtype] = eina_list_remove_list(requests[rtype],
+ requests[rtype]);
+
+ if (!(*idle))
+ sw = _slave_for_request_create(type);
+
+ if (!(*idle))
+ {
+ ERR("No idle slave available to process request type %d.",
+ rtype);
+ _cserve2_request_failed(req, CSERVE2_GENERIC);
+ continue;
+ }
+
+ sw = eina_list_data_get(*idle);
+ if (!_cserve2_request_dispatch(sw, mtype, req))
+ {
+ ERR("Could not dispatch request.");
+ _cserve2_request_failed(req, CSERVE2_GENERIC);
+ continue;
+ }
+
+ *idle = eina_list_remove_list(*idle, *idle);
+ *working = eina_list_append(*working, sw);
+
+ }
+ }
+}