From: Lennart Poettering Date: Fri, 24 Jun 2011 21:25:28 +0000 (+0200) Subject: logind: use pipe fd to detect when a session is dead X-Git-Tag: v30~152 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=31b79c2b4a34961eefc3b3680704124d8490d105;hp=094062918c50cd5a34f7b6510fe206bf78d7cc58;p=elogind.git logind: use pipe fd to detect when a session is dead --- diff --git a/src/logind-dbus.c b/src/logind-dbus.c index d48d68c2b..136f610cb 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -437,7 +437,9 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess goto fail; } - session->pipe_fd = pipe_fds[0]; + r = session_set_pipe_fd(session, pipe_fds[0]); + if (r < 0) + goto fail; pipe_fds[0] = -1; if (s) { diff --git a/src/logind-session.c b/src/logind-session.c index 9278f3075..16d6c177d 100644 --- a/src/logind-session.c +++ b/src/logind-session.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "logind-session.h" #include "strv.h" @@ -97,8 +98,7 @@ void session_free(Session *s) { hashmap_remove(s->manager->sessions, s->id); - if (s->pipe_fd >= 0) - close_nointr_nofail(s->pipe_fd); + session_unset_pipe_fd(s); free(s->state_file); free(s); @@ -729,6 +729,45 @@ void session_set_idle_hint(Session *s, bool b) { "IdleSinceHintMonotonic\0"); } +int session_set_pipe_fd(Session *s, int fd) { + struct epoll_event ev; + int r; + + assert(s); + assert(fd >= 0); + assert(s->pipe_fd < 0); + + r = hashmap_put(s->manager->pipe_fds, INT_TO_PTR(fd + 1), s); + if (r < 0) + return r; + + zero(ev); + ev.events = 0; + ev.data.u32 = FD_PIPE_BASE + fd; + + if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { + assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(fd + 1)) == s); + return -errno; + } + + s->pipe_fd = fd; + return 0; +} + +void session_unset_pipe_fd(Session *s) { + assert(s); + + if (s->pipe_fd < 0) + return; + + assert_se(hashmap_remove(s->manager->pipe_fds, INT_TO_PTR(s->pipe_fd + 1)) == s); + + assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->pipe_fd, NULL) == 0); + + close_nointr_nofail(s->pipe_fd); + s->pipe_fd = -1; +} + int session_check_gc(Session *s) { int r; diff --git a/src/logind-session.h b/src/logind-session.h index 01c9504dd..7a8001eca 100644 --- a/src/logind-session.h +++ b/src/logind-session.h @@ -91,6 +91,8 @@ int session_activate(Session *s); bool session_is_active(Session *s); int session_get_idle_hint(Session *s, dual_timestamp *t); void session_set_idle_hint(Session *s, bool b); +int session_set_pipe_fd(Session *s, int fd); +void session_unset_pipe_fd(Session *s); int session_start(Session *s); int session_stop(Session *s); int session_save(Session *s); diff --git a/src/logind.c b/src/logind.c index 2665ab910..25773209e 100644 --- a/src/logind.c +++ b/src/logind.c @@ -33,12 +33,6 @@ #include "dbus-common.h" #include "dbus-loop.h" -enum { - FD_UDEV, - FD_CONSOLE, - FD_BUS -}; - Manager *manager_new(void) { Manager *m; @@ -57,6 +51,7 @@ Manager *manager_new(void) { m->sessions = hashmap_new(string_hash_func, string_compare_func); m->users = hashmap_new(trivial_hash_func, trivial_compare_func); m->cgroups = hashmap_new(string_hash_func, string_compare_func); + m->pipe_fds = hashmap_new(trivial_hash_func, trivial_compare_func); if (!m->devices || !m->seats || !m->sessions || !m->users) { manager_free(m); @@ -102,6 +97,7 @@ void manager_free(Manager *m) { hashmap_free(m->devices); hashmap_free(m->seats); hashmap_free(m->cgroups); + hashmap_free(m->pipe_fds); if (m->console_active_fd >= 0) close_nointr_nofail(m->console_active_fd); @@ -714,6 +710,19 @@ void manager_cgroup_notify_empty(Manager *m, const char *cgroup) { free(p); } +static void manager_pipe_notify_eof(Manager *m, int fd) { + Session *s; + + assert_se(m); + assert_se(fd >= 0); + + assert_se(s = hashmap_get(m->pipe_fds, INT_TO_PTR(fd + 1))); + assert(s->pipe_fd == fd); + session_unset_pipe_fd(s); + + session_add_to_gc_queue(s); +} + static int manager_connect_bus(Manager *m) { DBusError error; int r; @@ -1006,6 +1015,10 @@ int manager_run(Manager *m) { case FD_BUS: bus_loop_dispatch(m->bus_fd); break; + + default: + if (event.data.u32 >= FD_PIPE_BASE) + manager_pipe_notify_eof(m, event.data.u32 - FD_PIPE_BASE); } } diff --git a/src/logind.h b/src/logind.h index d8674e751..d512c3ee2 100644 --- a/src/logind.h +++ b/src/logind.h @@ -37,9 +37,8 @@ * recreate VTs when disallocated * spawn user systemd * direct client API - * subscribe to fd HUP * D-Bus method: AttachDevice(seat, device); - * D-Bus method: PermitLinger(user, bool b); + * D-Bus method: SetLinger(user, bool b); * * non-local X11 server * reboot/shutdown halt management @@ -86,6 +85,14 @@ struct Manager { unsigned long session_counter; Hashmap *cgroups; + Hashmap *pipe_fds; +}; + +enum { + FD_UDEV, + FD_CONSOLE, + FD_BUS, + FD_PIPE_BASE }; Manager *manager_new(void);