chiark / gitweb /
logind: use pipe fd to detect when a session is dead
authorLennart Poettering <lennart@poettering.net>
Fri, 24 Jun 2011 21:25:28 +0000 (23:25 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 24 Jun 2011 21:25:28 +0000 (23:25 +0200)
src/logind-dbus.c
src/logind-session.c
src/logind-session.h
src/logind.c
src/logind.h

index d48d68c2bb70b4b64d5bdd3fc63c7a54dc43e134..136f610cb625b746931d166cad087e0aae6c73c4 100644 (file)
@@ -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) {
index 9278f30754be4f0fcfbf6e06d5128a28c948fcd4..16d6c177d2b5fd298d00b0ebcf6878b0693193f3 100644 (file)
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/epoll.h>
 
 #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;
 
index 01c9504dd4aca5846024310e36ebf4bcfcdb7b9c..7a8001eca6807461754bf54353c36a8128d0f9a8 100644 (file)
@@ -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);
index 2665ab910d95f08c20b29d529ff6fae6dd651b30..25773209ea0945bd78e853828f07ade626db0468 100644 (file)
 #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);
                 }
         }
 
index d8674e75116a5fed8d77bba1e9c06eb8f678bb30..d512c3ee2ffd9c135facd240fd75e1aa812c171b 100644 (file)
@@ -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);