84bd1b176e55eba6d0f8d4736b21016a5e0fc863
[profile/ivi/evas.git] / src / bin / evas_cserve2_requests.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "evas_cserve2.h"
6
7 #define MAX_SLAVES 1
8
9 typedef enum
10 {
11    SLAVE_IMAGE,
12    SLAVE_FONT,
13    SLAVE_NONE
14 } Slave_Type;
15
16 struct _Slave_Worker
17 {
18    void *data;
19    Slave *slave;
20    Eina_Binbuf *ret;
21    int ret_size;
22    Eina_Bool done;
23    Eina_Bool delete_me;
24 };
25
26 typedef struct _Slave_Worker Slave_Worker;
27
28 /* This struct is used to match font request types to the respective slave
29  * type, and the message type that will be used for that request. The order
30  * of the request types on it is the order in which these requests will
31  * be processed.
32  */
33 static struct _Request_Match
34 {
35    Font_Request_Type rtype;
36    Slave_Type stype;
37    Message_Type mtype;
38 } _request_match[] =
39 {
40    { CSERVE2_REQ_FONT_LOAD, SLAVE_FONT, CSERVE2_FONT_LOAD },
41    { CSERVE2_REQ_FONT_GLYPHS_LOAD, SLAVE_FONT, CSERVE2_FONT_GLYPHS_LOAD },
42    { CSERVE2_REQ_LAST, 0 }
43 };
44
45 static Slave *_create_image_slave(void *data);
46 static Slave *_create_font_slave(void *data);
47
48 static struct _Worker
49 {
50    Slave_Type type;
51    unsigned int max;
52    Eina_List *idle;
53    Eina_List *working;
54    Slave *(*create_slave)(void *data);
55 } _workers[] =
56 {
57    { SLAVE_IMAGE, 3, NULL, NULL, _create_image_slave },
58    { SLAVE_FONT, 1, NULL, NULL, _create_font_slave },
59 };
60
61 struct _Font_Request
62 {
63    Font_Request_Type type;
64    void *data;
65    void *msg;
66    Eina_List *waiters;
67    Eina_Bool processing;
68    Font_Request_Funcs *funcs;
69 };
70
71 struct _Waiter
72 {
73    unsigned int rid;
74    Client *client;
75 };
76
77 typedef struct _Waiter Waiter;
78
79 static Eina_List **requests = NULL;
80
81 static void
82 _request_waiter_add(Font_Request *req, Client *client, unsigned int rid)
83 {
84    Waiter *w = malloc(sizeof(*w));
85
86    DBG("Add waiter to request. Client: %d, rid: %d", client->id, rid);
87
88    w->client = client;
89    w->rid = rid;
90
91    req->waiters = eina_list_append(req->waiters, w);
92 }
93
94 Font_Request *
95 cserve2_request_add(Font_Request_Type type, unsigned int rid, Client *client, Font_Request_Funcs *funcs, void *data)
96 {
97    Font_Request *req, *r;
98    Eina_List *l;
99
100    req = NULL;
101    EINA_LIST_FOREACH(requests[type], l, r)
102      {
103         if (r->data != data)
104           continue;
105
106         req = r;
107         break;
108      }
109
110    if (!req)
111      {
112         DBG("Add request for rid: %d", rid);
113         req = malloc(sizeof(*req));
114         req->data = data;
115         req->waiters = NULL;
116         req->processing = EINA_FALSE;
117         requests[type] = eina_list_append(requests[type], req);
118      }
119
120    _request_waiter_add(req, client, rid);
121
122    return req;
123 }
124
125 void
126 cserve2_request_cancel(Font_Request *req, Client *client, Error_Type err)
127 {
128    Eina_List *l, *l_next;
129    Waiter *w;
130
131    EINA_LIST_FOREACH_SAFE(req->waiters, l, l_next, w)
132      {
133         if (w->client->id == client->id)
134           {
135              DBG("Removing answer from waiter client: %d, rid: %d",
136                  client->id, w->rid);
137              if (req->funcs && req->funcs->error)
138                req->funcs->error(client, req->data, err, w->rid);
139              req->waiters = eina_list_remove_list(req->waiters, l);
140              free(w);
141           }
142      }
143
144    // TODO: When we have speculative preload, there may be no waiters,
145    // so we need a flag or something else to make things still load.
146    if (!req->waiters)
147      {
148         Eina_List **reqlist = &requests[req->type];
149         *reqlist = eina_list_remove(*reqlist, req);
150         req->funcs->msg_free(req->msg);
151         free(req);
152      }
153
154 }
155
156 void
157 cserve2_request_cancel_all(Font_Request *req, Error_Type err)
158 {
159    Waiter *w;
160
161    DBG("Removing all answers.");
162
163    EINA_LIST_FREE(req->waiters, w)
164      {
165         DBG("Removing answer from waiter client: %d, rid: %d",
166             w->client->id, w->rid);
167         if (req->funcs && req->funcs->error)
168           req->funcs->error(w->client, req->data, err, w->rid);
169         free(w);
170      }
171
172    requests[req->type] = eina_list_remove(requests[req->type], req);
173    req->funcs->msg_free(req->msg);
174    free(req);
175 }
176
177 void
178 cserve2_requests_init(void)
179 {
180    DBG("Initializing requests.");
181    requests = calloc(CSERVE2_REQ_LAST, sizeof(Eina_List *));
182 }
183
184 void
185 cserve2_requests_shutdown(void)
186 {
187    DBG("Shutting down requests.");
188    free(requests);
189 }
190
191 static void
192 _image_slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd __UNUSED__, void *msg __UNUSED__, void *data __UNUSED__)
193 {
194 }
195
196 static void
197 _image_slave_dead_cb(Slave *s __UNUSED__, void *data __UNUSED__)
198 {
199 }
200
201 static Slave *
202 _create_image_slave(void *data)
203 {
204    char *exe;
205    Slave *slave;
206
207    exe = getenv("EVAS_CSERVE2_SLAVE");
208    if (!exe) exe = "evas_cserve2_slave";
209
210    slave = cserve2_slave_run(exe, _image_slave_read_cb,
211                              _image_slave_dead_cb, data);
212
213    return slave;
214 }
215
216 static Slave *
217 _create_font_slave(void *data __UNUSED__)
218 {
219    return NULL;
220 }
221
222 static Slave_Worker *
223 _slave_for_request_create(Slave_Type type)
224 {
225    Slave_Worker *sw;
226    Slave *slave;
227
228    sw = calloc(1, sizeof(Slave_Worker));
229    if (!sw) return NULL;
230
231    slave = _workers[type].create_slave(sw);
232    if (!slave)
233      {
234         ERR("Could not launch slave process");
235         free(sw);
236         return NULL;
237      }
238
239    sw->slave = slave;
240    _workers[type].idle = eina_list_append(_workers[type].idle, sw);
241
242    return sw;
243 }
244
245 static Eina_Bool
246 _cserve2_request_dispatch(Slave_Worker *sw, Message_Type mtype, Font_Request *req)
247 {
248    int size;
249    char *slave_msg = req->funcs->msg_create(req->data, &size);
250
251    if (!slave_msg)
252      {
253         ERR("Could not create slave message for request type %d.", req->type);
254         return EINA_FALSE;
255      }
256
257    req->msg = slave_msg;
258    sw->data = req;
259    cserve2_slave_send(sw->slave, mtype, slave_msg, size);
260    req->processing = EINA_TRUE;
261
262    return EINA_TRUE;
263 }
264
265 static void
266 _cserve2_request_failed(Font_Request *req, Error_Type type)
267 {
268    Waiter *w;
269
270    EINA_LIST_FREE(req->waiters, w)
271      {
272         req->funcs->error(w->client, req->data, type, w->rid);
273         free(w);
274      }
275
276    req->funcs->msg_free(req->msg);
277    free(req);
278 }
279
280 void
281 cserve2_requests_process(void)
282 {
283     int rtype, j;
284
285     for (rtype = 0; rtype < CSERVE2_REQ_LAST; rtype++)
286       {
287          Slave_Type type = SLAVE_NONE;
288          Message_Type mtype;
289          unsigned int max_workers;
290          Eina_List **idle, **working;
291
292          for (j = 0; _request_match[j].rtype != CSERVE2_REQ_LAST; j++)
293            {
294               if (_request_match[j].rtype == j)
295                 {
296                    type = _request_match[j].stype;
297                    mtype = _request_match[j].mtype;
298                    break;
299                 }
300            }
301
302          if (type == SLAVE_NONE)
303            continue;
304
305          if (!requests[rtype])
306            continue;
307
308          /* Now we have the worker type to use (image or font), and the list
309           * of requests to process. Just process as many requests as we can.
310           */
311          max_workers = _workers[type].max;
312          idle = &_workers[type].idle;
313          working = &_workers[type].working;
314
315          while (requests[j] &&
316                 (eina_list_count(*working) < max_workers))
317            {
318               Slave_Worker *sw;
319               Font_Request *req = eina_list_data_get(requests[rtype]);
320               requests[rtype] = eina_list_remove_list(requests[rtype],
321                                                       requests[rtype]);
322
323               if (!(*idle))
324                 sw = _slave_for_request_create(type);
325
326               if (!(*idle))
327                 {
328                    ERR("No idle slave available to process request type %d.",
329                        rtype);
330                    _cserve2_request_failed(req, CSERVE2_GENERIC);
331                    continue;
332                 }
333
334               sw = eina_list_data_get(*idle);
335               if (!_cserve2_request_dispatch(sw, mtype, req))
336                 {
337                    ERR("Could not dispatch request.");
338                    _cserve2_request_failed(req, CSERVE2_GENERIC);
339                    continue;
340                 }
341
342               *idle = eina_list_remove_list(*idle, *idle);
343               *working = eina_list_append(*working, sw);
344
345            }
346       }
347 }