chiark / gitweb /
logind: remove a session when its cgroup is gone
authorLennart Poettering <lennart@poettering.net>
Fri, 24 Jun 2011 18:41:56 +0000 (20:41 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 24 Jun 2011 18:41:56 +0000 (20:41 +0200)
src/logind-dbus.c
src/logind-session.c
src/logind.c
src/logind.h

index 2a85749..0f3de41 100644 (file)
@@ -896,6 +896,36 @@ const DBusObjectPathVTable bus_manager_vtable = {
         .message_function = manager_message_handler
 };
 
+DBusHandlerResult bus_message_filter(
+                DBusConnection *connection,
+                DBusMessage *message,
+                void *userdata) {
+
+        Manager *m = userdata;
+        DBusError error;
+
+        assert(m);
+        assert(connection);
+        assert(message);
+
+        dbus_error_init(&error);
+
+        if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
+                const char *cgroup;
+
+                if (!dbus_message_get_args(message, &error,
+                                           DBUS_TYPE_STRING, &cgroup,
+                                           DBUS_TYPE_INVALID))
+                        log_error("Failed to parse Released message: %s", bus_error_message(&error));
+                else
+                        manager_cgroup_notify_empty(m, cgroup);
+        }
+
+        dbus_error_free(&error);
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
 int manager_send_changed(Manager *manager, const char *properties) {
         DBusMessage *m;
         int r = -ENOMEM;
index 74f8ad1..9278f30 100644 (file)
@@ -83,6 +83,9 @@ void session_free(Session *s) {
                 LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s);
         }
 
+        if (s->cgroup_path)
+                hashmap_remove(s->manager->cgroups, s->cgroup_path);
+
         free(s->cgroup_path);
         strv_free(s->controllers);
 
@@ -468,6 +471,8 @@ static int session_create_cgroup(Session *s) {
                 }
         }
 
+        hashmap_put(s->manager->cgroups, s->cgroup_path, s);
+
         return 0;
 }
 
@@ -562,6 +567,8 @@ static int session_kill_cgroup(Session *s) {
         STRV_FOREACH(k, s->user->manager->controllers)
                 cg_trim(*k, s->cgroup_path, true);
 
+        hashmap_remove(s->manager->cgroups, s->cgroup_path);
+
         free(s->cgroup_path);
         s->cgroup_path = NULL;
 
index cdb4da7..2665ab9 100644 (file)
@@ -56,6 +56,7 @@ Manager *manager_new(void) {
         m->seats = hashmap_new(string_hash_func, string_compare_func);
         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);
 
         if (!m->devices || !m->seats || !m->sessions || !m->users) {
                 manager_free(m);
@@ -100,6 +101,7 @@ void manager_free(Manager *m) {
         hashmap_free(m->users);
         hashmap_free(m->devices);
         hashmap_free(m->seats);
+        hashmap_free(m->cgroups);
 
         if (m->console_active_fd >= 0)
                 close_nointr_nofail(m->console_active_fd);
@@ -682,12 +684,34 @@ int manager_spawn_autovt(Manager *m, int vtnr) {
         return 0;
 }
 
-static DBusHandlerResult login_message_filter(
-                DBusConnection *connection,
-                DBusMessage *message,
-                void *userdata) {
+void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
+        Session *s;
+        char *p;
+
+        assert(m);
+        assert(cgroup);
+
+        p = strdup(cgroup);
+        if (!p) {
+                log_error("Out of memory.");
+                return;
+        }
+
+        for (;;) {
+                char *e;
 
-        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+                if (isempty(p) || streq(p, "/"))
+                        break;
+
+                s = hashmap_get(m->cgroups, p);
+                if (s)
+                        session_add_to_gc_queue(s);
+
+                assert_se(e = strrchr(p, '/'));
+                *e = 0;
+        }
+
+        free(p);
 }
 
 static int manager_connect_bus(Manager *m) {
@@ -712,7 +736,7 @@ static int manager_connect_bus(Manager *m) {
             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
-            !dbus_connection_add_filter(m->bus, login_message_filter, m, NULL)) {
+            !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
                 log_error("Not enough memory");
                 r = -ENOMEM;
                 goto fail;
@@ -958,6 +982,8 @@ int manager_run(Manager *m) {
                 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
                         continue;
 
+                manager_gc(m);
+
                 n = epoll_wait(m->epoll_fd, &event, 1, -1);
                 if (n < 0) {
                         if (errno == EINTR || errno == EAGAIN)
index 22eab55..d8674e7 100644 (file)
@@ -37,7 +37,7 @@
  * recreate VTs when disallocated
  * spawn user systemd
  * direct client API
- * subscribe to cgroup changes, fd HUP
+ * subscribe to fd HUP
  * D-Bus method: AttachDevice(seat, device);
  * D-Bus method: PermitLinger(user, bool b);
  *
@@ -84,6 +84,8 @@ struct Manager {
         bool kill_user_processes;
 
         unsigned long session_counter;
+
+        Hashmap *cgroups;
 };
 
 Manager *manager_new(void);
@@ -109,6 +111,8 @@ int manager_startup(Manager *m);
 int manager_run(Manager *m);
 int manager_spawn_autovt(Manager *m, int vtnr);
 
+void manager_cgroup_notify_empty(Manager *m, const char *cgroup);
+
 void manager_gc(Manager *m);
 
 int manager_get_idle_hint(Manager *m, dual_timestamp *t);
@@ -117,6 +121,8 @@ bool x11_display_is_local(const char *display);
 
 extern const DBusObjectPathVTable bus_manager_vtable;
 
+DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata);
+
 int manager_send_changed(Manager *manager, const char *properties);
 
 #endif