evas/cserve2: Add requests and slave workers
authorantognolli <antognolli@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 31 May 2012 21:33:59 +0000 (21:33 +0000)
committerantognolli <antognolli@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 31 May 2012 21:33:59 +0000 (21:33 +0000)
 management.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@71601 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/bin/evas_cserve2.h
src/bin/evas_cserve2_requests.c

index cdfe857..dc6c21c 100644 (file)
@@ -113,12 +113,14 @@ typedef struct _Slave_Msg_Image_Opened Slave_Msg_Image_Opened;
 typedef struct _Slave_Msg_Image_Load Slave_Msg_Image_Load;
 typedef struct _Slave_Msg_Image_Loaded Slave_Msg_Image_Loaded;
 
-typedef void *(*Font_Request_Msg_Create)(Client *c, void *data, int *size);
-typedef void (*Font_Request_Response)(Client *c, void *data, void *resp);
-typedef void (*Font_Request_Error)(Client *c, void *data, Error_Type error);
+typedef void *(*Font_Request_Msg_Create)(void *data, int *size);
+typedef void *(*Font_Request_Msg_Free)(void *data);
+typedef void (*Font_Request_Response)(Client *c, void *data, void *resp, unsigned int rid);
+typedef void (*Font_Request_Error)(Client *c, void *data, Error_Type error, unsigned int rid);
 
 struct _Font_Request_Funcs {
    Font_Request_Msg_Create msg_create;
+   Font_Request_Msg_Free msg_free;
    Font_Request_Response response;
    Font_Request_Error error;
 };
index ddfa3f8..84bd1b1 100644 (file)
@@ -4,15 +4,72 @@
 
 #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;
 };
@@ -78,7 +135,7 @@ cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
              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);
           }
@@ -90,6 +147,7 @@ cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
      {
         Eina_List **reqlist = &requests[req->type];
         *reqlist = eina_list_remove(*reqlist, req);
+        req->funcs->msg_free(req->msg);
         free(req);
      }
 
@@ -107,11 +165,12 @@ cserve2_request_cancel_all(Font_Request *req, Error_Type err)
         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);
 }
 
@@ -128,3 +187,161 @@ cserve2_requests_shutdown(void)
    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);
+
+           }
+      }
+}