#include "debug.h" #include "fs.h" #include "exec.h" #include "util.h" static EfsdConnection *ec = NULL; static Evas_List fs_handlers = NULL; static Evas_List fs_restart_handlers = NULL; static pid_t efsd_pid = 0; static void e_fs_child_handle(Ecore_Event *ev); static void e_fs_fd_handle(int fd); static void e_fs_restarter(int val, void *data); static void e_fs_idle(void *data); static void e_fs_flush_timeout(int val, void *data); static void e_fs_flush_timeout(int val, void *data) { D_ENTER; if (!ec) D_RETURN; if (efsd_commands_pending(ec) > 0) { if (efsd_flush(ec) > 0) ecore_add_event_timer("e_fs_flush_timeout()", 0.00, e_fs_flush_timeout, 0, NULL); } D_RETURN; UN(data); UN(val); } static void e_fs_idle(void *data) { D_ENTER; e_fs_flush_timeout(0, NULL); D_RETURN; UN(data); } static void e_fs_child_handle(Ecore_Event *ev) { Ecore_Event_Child *e; D_ENTER; e = ev->event; D("pid went splat! (%i)\n", e->pid); if (e->pid == efsd_pid) { D("it was efsd!\n"); if (ec) efsd_close(ec); ec = NULL; efsd_pid = 0; e_fs_restarter(1, NULL); } D_RETURN; } static void e_fs_fd_handle(int fd) { double start, current; D_ENTER; start = ecore_get_time(); while ((ec) && efsd_events_pending(ec)) { EfsdEvent ev; if (efsd_next_event(ec, &ev) >= 0) { Evas_List l; for (l = fs_handlers; l; l = l->next) { void (*func) (EfsdEvent *ev); func = l->data; func(&ev); } efsd_event_cleanup(&ev); } else { efsd_close(ec); ecore_del_event_fd(fd); ec = NULL; e_fs_restarter(0, NULL); /* FIXME: need to queue a popup dialog here saying */ /* efsd went wonky */ D("EEEEEEEEEEK efsd went wonky. Bye bye efsd.\n"); } /* spent more thna 1/20th of a second here.. get out */ current = ecore_get_time(); if ((current - start) > 0.05) { D("fs... too much time spent..\n"); break; } } D_RETURN; } static void e_fs_restarter(int val, void *data) { D_ENTER; if (ec) D_RETURN; ec = efsd_open(); if ((!ec) && (val > 0)) { if (efsd_pid <= 0) { efsd_pid = e_exec_run("efsd -f"); D("launch efsd... %i\n", efsd_pid); } if (efsd_pid > 0) ec = efsd_open(); } if (ec) { Evas_List l; ecore_add_event_fd(efsd_get_connection_fd(ec), e_fs_fd_handle); for (l = fs_restart_handlers; l; l = l->next) { E_FS_Restarter *rs; rs = l->data; rs->func(rs->data); } } else { double gap; gap = (double)val / 10; if (gap > 10.0) gap = 10.0; ecore_add_event_timer("e_fs_restarter", gap, e_fs_restarter, val + 1, NULL); } D_RETURN; UN(data); } E_FS_Restarter * e_fs_add_restart_handler(void (*func) (void *data), void *data) { E_FS_Restarter *rs; D_ENTER; rs = NEW(E_FS_Restarter, 1); ZERO(rs, E_FS_Restarter, 1); rs->func = func; rs->data = data; fs_restart_handlers = evas_list_append(fs_restart_handlers, rs); D_RETURN_(rs); } void e_fs_del_restart_handler(E_FS_Restarter *rs) { D_ENTER; if (evas_list_find(fs_restart_handlers, rs)) { fs_restart_handlers = evas_list_remove(fs_restart_handlers, rs); FREE(rs); } D_RETURN; } void e_fs_add_event_handler(void (*func) (EfsdEvent *ev)) { D_ENTER; if (!func) D_RETURN; fs_handlers = evas_list_append(fs_handlers, func); D_RETURN; } void e_fs_init(void) { D_ENTER; /* Hook in an fs handler that gets called whenever a child of this process exits. */ ecore_event_filter_handler_add(ECORE_EVENT_CHILD, e_fs_child_handle); /* Also hook in an idle handler to flush efsd's write queue. FIXME: This should be handled by letting ecore report when Efsd's file descriptor becomes writeable, and then calling efsd_flush(). */ ecore_event_filter_idle_handler_add(e_fs_idle, NULL); e_fs_restarter(0, NULL); D_RETURN; } void e_fs_cleanup(void) { D_ENTER; efsd_close(ec); D("Connection to Efsd closed.\n"); D_RETURN; } EfsdConnection * e_fs_get_connection(void) { D_ENTER; D_RETURN_(ec); }