9 #include "evas_cserve2.h"
11 #ifdef CSERVE2_BIN_DEFAULT_COLOR
12 #undef CSERVE2_BIN_DEFAULT_COLOR
14 #define CSERVE2_BIN_DEFAULT_COLOR EINA_COLOR_BLUE
18 struct _Slave_Worker {
28 typedef struct _Slave_Worker Slave_Worker;
30 int _evas_cserve2_bin_log_dom = -1;
31 static unsigned int _client_id = 0;
32 static Eina_Hash *client_list = NULL;
33 static Eina_Inlist *slaves_idle = NULL;
34 static Eina_Inlist *slaves_working = NULL;
37 cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
42 // clear the struct with possible paddings, since it is not aligned.
43 memset(&msg, 0, sizeof(msg));
45 msg.base.type = CSERVE2_ERROR;
46 msg.error = error_code;
49 cserve2_client_send(client, &size, sizeof(size));
50 cserve2_client_send(client, &msg, sizeof(msg));
54 _cserve2_client_image_setoptsed(Client *client, unsigned int rid)
59 memset(&msg, 0, sizeof(msg));
61 msg.base.type = CSERVE2_SETOPTSED;
64 cserve2_client_send(client, &size, sizeof(size));
65 cserve2_client_send(client, &msg, size);
69 _slave_dead_cb(Slave_Proc *s __UNUSED__, void *data)
71 Slave_Worker *sw = data;
75 DBG("Slave killed by cserve2. Restart routine.");
82 WRN("Slave died with no pending job, but not requested.");
83 slaves_idle = eina_inlist_remove(slaves_idle, EINA_INLIST_GET(sw));
88 slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
90 cserve2_cache_requests_response(ERROR, (Error_Type[]){ CSERVE2_LOADER_DIED }, sw->data);
92 eina_binbuf_free(sw->ret);
97 _slave_read_cb(Slave_Proc *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
99 Slave_Worker *sw = data;
101 DBG("Received reply command '%d' from slave '%p'", cmd, sw->slave);
106 sw->done = EINA_TRUE;
111 ERR("Unrecognized command received from slave: %d", cmd);
113 cserve2_cache_requests_response(cmd, msg, sw->data);
116 // slave finishes its work, put it back to idle list
118 slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
120 if (!sw->delete_me) // if it is being deleted, it shouldn't be in any list
121 slaves_idle = eina_inlist_append(slaves_idle, EINA_INLIST_GET(sw));
123 cserve2_cache_requests_process();
127 cserve2_slave_available_get(void)
129 return MAX_SLAVES - eina_inlist_count(slaves_working);
133 cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int size)
138 DBG("Dispatching command to slave. %d idle slaves, %d working slaves.",
139 eina_inlist_count(slaves_idle), eina_inlist_count(slaves_working));
141 // first check if there's an available slave
144 sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
145 slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
146 slaves_working = eina_inlist_append(slaves_working,
147 EINA_INLIST_GET(sw));
150 DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
151 cserve2_slave_send(sw->slave, cmd, msg, size);
155 // no available slave, start a new one
156 sw = calloc(1, sizeof(Slave_Worker));
157 if (!sw) return EINA_FALSE;
160 exe = getenv("EVAS_CSERVE2_SLAVE");
161 if (!exe) exe = "evas_cserve2_slave";
162 sw->slave = cserve2_slave_run(exe, _slave_read_cb, _slave_dead_cb, sw);
165 ERR("Could not launch slave process");
166 cserve2_cache_requests_response(ERROR, (Error_Type[]){ CSERVE2_LOADER_EXEC_ERR }, sw->data);
170 DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
171 cserve2_slave_send(sw->slave, cmd, msg, size);
173 slaves_working = eina_inlist_append(slaves_working, EINA_INLIST_GET(sw));
179 _cserve2_client_close(Client *client)
181 Msg_Close *msg = (Msg_Close *)client->msg.buf;
183 INF("Received CLOSE command: RID=%d", msg->base.rid);
184 INF("File_ID: %d\n", msg->file_id);
186 cserve2_cache_file_close(client, msg->file_id);
190 _cserve2_client_unload(Client *client)
192 Msg_Unload *msg = (Msg_Unload *)client->msg.buf;
194 INF("Received UNLOAD command: RID=%d", msg->base.rid);
195 INF("Image_ID: %d\n", msg->image_id);
197 cserve2_cache_image_unload(client, msg->image_id);
201 _cserve2_client_preload(Client *client)
203 Msg_Preload *msg = (Msg_Preload *)client->msg.buf;
205 INF("Received PRELOAD command: RID=%d", msg->base.rid);
206 INF("Image_ID: %d\n", msg->image_id);
208 cserve2_cache_image_preload(client, msg->image_id, msg->base.rid);
209 cserve2_cache_requests_process();
213 _cserve2_client_load(Client *client)
215 Msg_Load *msg = (Msg_Load *)client->msg.buf;
217 INF("Received LOAD command: RID=%d", msg->base.rid);
218 INF("Image_ID: %d\n", msg->image_id);
220 cserve2_cache_image_load(client, msg->image_id, msg->base.rid);
221 cserve2_cache_requests_process();
225 _cserve2_client_setopts(Client *client)
227 Msg_Setopts *msg = (Msg_Setopts *)client->msg.buf;
229 INF("Received SETOPTS command: RID=%d", msg->base.rid);
230 INF("File_ID: %d, Image_ID: %d", msg->file_id, msg->image_id);
231 INF("Load Options:");
232 INF("\tdpi: %03.1f", msg->opts.dpi);
233 INF("\tsize: %dx%d", msg->opts.w, msg->opts.h);
234 INF("\tscale down: %d", msg->opts.scale_down);
235 INF("\tregion: %d,%d + %dx%d",
236 msg->opts.rx, msg->opts.ry, msg->opts.rw, msg->opts.rh);
237 INF("\torientation: %d\n", msg->opts.orientation);
239 if (cserve2_cache_image_opts_set(client, msg) != 0)
242 _cserve2_client_image_setoptsed(client, msg->base.rid);
246 _cserve2_client_open(Client *client)
248 Msg_Open *msg = (Msg_Open *)client->msg.buf;
249 const char *path, *key;
251 path = ((const char *)msg) + sizeof(*msg) + msg->path_offset;
252 key = ((const char *)msg) + sizeof(*msg) + msg->key_offset;
254 INF("Received OPEN command: RID=%d", msg->base.rid);
255 INF("File_ID: %d, path=\"%s\", key=\"%s\"\n",
256 msg->file_id, path, key);
258 cserve2_cache_file_open(client, msg->file_id, path, key, msg->base.rid);
259 cserve2_cache_requests_process();
263 cserve2_command_run(Client *client, Message_Type type)
268 _cserve2_client_open(client);
270 case CSERVE2_SETOPTS:
271 _cserve2_client_setopts(client);
274 _cserve2_client_load(client);
276 case CSERVE2_PRELOAD:
277 _cserve2_client_preload(client);
280 _cserve2_client_unload(client);
283 _cserve2_client_close(client);
286 WRN("Unhandled message");
291 _slave_quit_send(Slave_Worker *sw)
293 cserve2_slave_send(sw->slave, SLAVE_QUIT, NULL, 0);
297 _slaves_restart(void)
299 Slave_Worker *list, *sw;
301 while (slaves_idle) // remove idle workers from idle list
303 sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
304 slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
305 sw->delete_me = EINA_TRUE;
306 _slave_quit_send(sw);
309 // working workers will be removed from the working list when they
310 // finish processing their jobs
311 list = EINA_INLIST_CONTAINER_GET(slaves_working, Slave_Worker);
312 EINA_INLIST_FOREACH(list, sw)
314 sw->delete_me = EINA_TRUE;
315 _slave_quit_send(sw);
322 static unsigned int slaves_restart = 0;
326 if (slaves_restart == 10)
333 cserve2_timeout_cb_set(3000, _timeout_cb);
337 cserve2_client_accept(int fd)
339 Client *client = calloc(1, sizeof(*client));
342 client->id = _client_id++;
344 while (eina_hash_find(client_list, &client->id))
345 client->id = _client_id++;
347 if (!eina_hash_add(client_list, &client->id, client))
349 Eina_Error err = eina_error_get();
350 ERR("Could not add client to the list: \"%s\"",
351 eina_error_msg_get(err));
356 cserve2_fd_watch_add(fd, FD_READ | FD_ERROR, cserve2_message_handler,
358 INF("Client %d connection accepted.", client->id);
360 cserve2_cache_client_new(client);
364 cserve2_client_del(Client *client)
366 eina_hash_del_by_key(client_list, &client->id);
370 _client_free(void *data)
372 Client *client = data;
373 cserve2_cache_client_del(client);
374 if (client->msg.pending)
375 eina_binbuf_free(client->msg.pending);
376 cserve2_fd_watch_del(client->socket);
377 close(client->socket);
384 client_list = eina_hash_int32_new(_client_free);
388 _clients_finish(void)
390 eina_hash_free(client_list);
394 main(int argc __UNUSED__, const char *argv[] __UNUSED__)
398 _evas_cserve2_bin_log_dom = eina_log_domain_register
399 ("evas_cserve2_bin", CSERVE2_BIN_DEFAULT_COLOR);
400 if (_evas_cserve2_bin_log_dom < 0)
402 EINA_LOG_ERR("impossible to create a log domain.");
407 if (!cserve2_main_loop_setup())
409 ERR("could not setup main loop.");
413 if (!cserve2_slaves_init())
415 ERR("Could not init slaves subsystem.");
419 cserve2_cache_init();
423 cserve2_timeout_cb_set(3000, _timeout_cb);
425 cserve2_main_loop_run();
429 cserve2_cache_shutdown();
432 cserve2_slaves_shutdown();
434 cserve2_main_loop_finish();
436 eina_log_domain_unregister(_evas_cserve2_bin_log_dom);
441 eina_log_domain_unregister(_evas_cserve2_bin_log_dom);