summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-06-24 23:25:28 +0200
committerLennart Poettering <lennart@poettering.net>2011-06-24 23:25:28 +0200
commit31b79c2b4a34961eefc3b3680704124d8490d105 (patch)
tree36b93e5f01b564b975c773f9fa95505dacdcf4ba
parent094062918c50cd5a34f7b6510fe206bf78d7cc58 (diff)
logind: use pipe fd to detect when a session is dead
-rw-r--r--src/logind-dbus.c4
-rw-r--r--src/logind-session.c43
-rw-r--r--src/logind-session.h2
-rw-r--r--src/logind.c25
-rw-r--r--src/logind.h11
5 files changed, 74 insertions, 11 deletions
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index d48d68c2bb..136f610cb6 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 9278f30754..16d6c177d2 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -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;
diff --git a/src/logind-session.h b/src/logind-session.h
index 01c9504dd4..7a8001eca6 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 2665ab910d..25773209ea 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 d8674e7511..d512c3ee2f 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);