[gnome-session/wip/benzea/systemd-user-switch: 12/19] main: Add systemd gnome-session monitoring code for leader
- From: Benjamin Berg <bberg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-session/wip/benzea/systemd-user-switch: 12/19] main: Add systemd gnome-session monitoring code for leader
- Date: Mon, 13 May 2019 11:42:17 +0000 (UTC)
commit 83aebf10f40e2f3817521a45b4b0baf53ca2f64d
Author: Benjamin Berg <bberg redhat com>
Date: Sat Apr 20 01:22:38 2019 +0200
main: Add systemd gnome-session monitoring code for leader
We are in the situation that gnome-session-binary is the session leader
process for the user. This process is managed via logind and is inside
the session scope of the user. This process has an important role for
the session lifetime management, but we cannot track or manage its state
from the systemd user instance.
This adds a simple protocol to allow us managing the state. The
counterpart is in gnome-session-ctl.c.
It works by creating a named fifo called gnome-session-leader-fifo in
the users runtime directory. The session leader opens it for writing,
the monitoring process opens it for reading.
By closing the FD the monitor process can signal to the leader that the
session has been shut down normally. By writing to the FD the leader can
signal the monitoring process to initiate a clean shutdown of the
session. If either process crashes or is killed, the FD is closed and
the other side will also quit.
gnome-session/main.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
---
diff --git a/gnome-session/main.c b/gnome-session/main.c
index e934ac1f..6112655c 100644
--- a/gnome-session/main.c
+++ b/gnome-session/main.c
@@ -26,9 +26,11 @@
#include <locale.h>
#include <unistd.h>
#include <errno.h>
+#include <sys/stat.h>
#include <glib/gi18n.h>
#include <glib.h>
+#include <glib/gstdio.h>
#include <glib-unix.h>
#include <gio/gio.h>
@@ -263,6 +265,112 @@ initialize_gio (void)
}
}
+#ifdef ENABLE_SYSTEMD_SESSION
+static gboolean
+leader_term_or_int_signal_cb (gpointer data)
+{
+ gint fifo_fd = GPOINTER_TO_INT (data);
+
+ /* Start a shutdown explicitly. */
+ gsm_util_start_systemd_unit ("gnome-session-shutdown.target", "replace-irreversibly", NULL);
+
+ if (fifo_fd >= 0) {
+ int res;
+
+ /* If we have a fifo, try to signal the other side. */
+ res = write (fifo_fd, "S", 1);
+ if (res < 0) {
+ g_warning ("Error signaling shutdown to monitoring process: %m");
+ gsm_quit ();
+ }
+ } else {
+ /* Otherwise quit immediately as we cannot wait on systemd */
+ gsm_quit ();
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+/**
+ * systemd_leader_run:
+ *
+ * This is the session leader when running under systemd, i.e. it is the only
+ * process that is *not* managed by the systemd user instance, this process
+ * is the one executed by the GDM helpers and is part of the session scope in
+ * the system systemd instance.
+ *
+ * This process works together with a service running in the user systemd
+ * instance (currently gnome-session-ctl@monitor.service):
+ *
+ * - It needs to signal shutdown to the user session when receiving SIGTERM
+ *
+ * - It needs to quit just after the user session is done
+ *
+ * - The monitor instance needs to know if this process was killed
+ *
+ * All this is achieved by opening a named fifo in a well known location.
+ * If this process receives SIGTERM or SIGINT then it will write a single byte
+ * causing the monitor service to signal STOPPING=1 to systemd, triggering a
+ * clean shutdown, solving the first item. The other two items are solved by
+ * waiting for EOF/HUP on both sides and quitting immediately when receiving
+ * that signal.
+ *
+ * As an example, a shutdown might look as follows:
+ *
+ * - session-X.scope for user is stopped
+ * - Leader process receive SIGTERM
+ * - Leader sends single byte
+ * - Monitor process receives byte and signals STOPPING=1
+ * - Systemd user instance starts session teardown
+ * - Session is torn down, last job run is stopping monitor process (SIGTERM)
+ * - Monitor process quits, closing FD in the process
+ * - Leader process receives HUP and quits
+ * - GDM shuts down its processes in the users scope
+ *
+ * The result is that the session is stopped cleanly.
+ */
+static void
+systemd_leader_run(void)
+{
+ g_autofree char *fifo_name = NULL;
+ int res;
+ int fifo_fd;
+
+ fifo_name = g_strdup_printf ("%s/gnome-session-leader-fifo",
+ g_get_user_runtime_dir ());
+ res = mkfifo (fifo_name, 0666);
+ if (res < 0 && errno != -EEXIST)
+ g_warning ("Error creating FIFO: %m");
+
+ fifo_fd = g_open (fifo_name, O_WRONLY | O_CLOEXEC, 0666);
+ if (fifo_fd >= 0) {
+ struct stat buf;
+
+ res = fstat (fifo_fd, &buf);
+ if (res < 0) {
+ g_warning ("Unable to watch systemd session: fstat failed with %m");
+ close (fifo_fd);
+ fifo_fd = -1;
+ } else if (!(buf.st_mode & S_IFIFO)) {
+ g_warning ("Unable to watch systemd session: FD is not a FIFO");
+ close (fifo_fd);
+ fifo_fd = -1;
+ } else {
+ g_unix_fd_add (fifo_fd, G_IO_HUP, (GUnixFDSourceFunc) gsm_quit, NULL);
+ }
+ } else {
+ g_warning ("Unable to watch systemd session: Opening FIFO failed with %m");
+ }
+
+ g_unix_signal_add (SIGTERM, leader_term_or_int_signal_cb, GINT_TO_POINTER (fifo_fd));
+ g_unix_signal_add (SIGINT, leader_term_or_int_signal_cb, GINT_TO_POINTER (fifo_fd));
+
+ /* Sleep until we receive HUP or are killed. */
+ gsm_main ();
+ exit(0);
+}
+#endif /* ENABLE_SYSTEMD_SESSION */
+
int
main (int argc, char **argv)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]