summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hansen <rhansen@rhansen.org>2023-04-17 04:44:18 -0400
committerRobert Ancell <robert.ancell@gmail.com>2023-04-28 13:34:51 +1200
commit8493ec0a100c2bfcc399bfe5ccd2132eef78cd80 (patch)
tree160be93ca5f88714006964c627aef062620ee94c
parentabf43606f09cb4e340597b407d2fe3b1cb64d5eb (diff)
downloadlightdm-git-8493ec0a100c2bfcc399bfe5ccd2132eef78cd80.tar.gz
Use systemd-logind to discover active session on non-seat0 seats
Before, `seat_local_get_active_session` would always return `NULL` for non-`seat0` seats. This broke Wayland sessions on non-`seat0` seats: 1. User logged in to a Wayland session on `seat1`. 2. LightDM properly terminated the X server to allow Wayland to take over the seat's hardware. (See the side note below.) 3. Wayland session started. 4. The X server termination triggered a call to `display_server_stopped_cb`. 5. `display_server_stopped_cb` called `seat_get_active_session` to see if it needed to start a greeter to replace a terminated session associated with the terminated display. 6. `seat_get_active_session` called `seat_local_get_active_session`. 7. `seat_local_get_active_session` erroneously probed the active VT even though VTs are only associated with `seat0`. 8. After finding no matching session associated with both `seat1` and the active VT, `seat_local_get_active_session` returned `NULL` when it should have returned the new Wayland session. 9. Due to the `NULL` response, `display_server_stopped_cb` erroneously arrived at the conclusion that a greeter must be started on `seat1`. 10. LightDM started a new X server and greeter on `seat1`, stomping on the newly created Wayland session. Side note: I don't think that terminating X to allow Wayland to take over the seat's hardware is required because I believe X and most?/all? Wayland compositors cooperatively share the devices via systemd-logind or maybe libseat. When switching sessions, logind uses a hand-off protocol to smoothly change which process is allowed to access the devices. This makes session switching possible even without virtual terminals. For details, see <https://dvdhrm.wordpress.com/2013/08/25/sane-session-switching/>. The above sequence of events is apparent in the debug log from a minimal script (the script is not included in this commit; the relevant lines from the log are copied below, with annotations): # # User logs in to seat1 with a Wayland session: # GREETER-X-1 AUTHENTICATION-COMPLETE USERNAME=no-password2 AUTHENTICATED=TRUE *GREETER-X-1 START-SESSION [+0.32s] DEBUG: Seat seat1: Creating display server of type wayland [+0.32s] DEBUG: Seat seat1: Display server ready, running session [+0.32s] DEBUG: Registering session with bus path /org/freedesktop/DisplayManager/Session0 [+0.32s] DEBUG: Session pid=1309577: Running command /home/rhansen/floss/lightdm/tests/src/lightdm-session test-session # # LightDM starts shutting down X+greeter for seat1 while # concurrently activating the new Wayland session (c1 = the # stopping seat1 greeter session, c2 = the starting Wayland # session). # [+0.33s] DEBUG: Seat seat1: Stopping greeter [+0.33s] DEBUG: Terminating login1 session c1 [+0.33s] DEBUG: Session pid=1309572: Sending SIGTERM [+0.33s] DEBUG: Activating login1 session c2 GREETER-X-1 TERMINATE SIGNAL=15 LOGIN1 ACTIVATE-SESSION SESSION=c2 # # The greeter session and X exit. # [+0.33s] DEBUG: Session pid=1309572: Exited with return value 0 [+0.33s] DEBUG: Seat seat1: Session stopped [+0.33s] DEBUG: Seat seat1: Stopping display server, no sessions require it [+0.33s] DEBUG: Sending signal 15 to process 1309569 XSERVER-1 TERMINATE SIGNAL=15 [+0.33s] DEBUG: Process 1309569 exited with return value 0 [+0.33s] DEBUG: XServer 1: X server stopped [+0.33s] DEBUG: Seat seat1: Display server stopped # # The start of the problem: LightDM should not restart the greeter # until the Wayland session terminates: # [+0.33s] DEBUG: Seat seat1: Active display server stopped, starting greeter [+0.33s] DEBUG: Seat seat1: Creating greeter session [+0.33s] DEBUG: Seat seat1: Creating display server of type x [+0.33s] DEBUG: Seat seat1: Starting local X display [+0.33s] DEBUG: XServer 1: Launching X Server [+0.33s] DEBUG: Launching process 1309583: /home/rhansen/floss/lightdm/tests/src/X :1 -seat seat1 -auth /var/run/lightdm/root/:1 -nolisten tcp [+0.33s] DEBUG: XServer 1: Waiting for ready signal from X server :1 XSERVER-1 START SEAT=seat1 # # The Wayland session has started concurrently with the # replacement X+greeter. # SESSION-WAYLAND START XDG_SEAT=seat1 XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/no-password2 XDG_SESSION_TYPE=wayland XDG_SESSION_DESKTOP=wayland USER=no-password2 *XSERVER-1 INDICATE-READY XSERVER-1 INDICATE-READY [+0.34s] DEBUG: Got signal 10 from process 1309583 [+0.34s] DEBUG: XServer 1: Got signal from X server :1 [+0.34s] DEBUG: XServer 1: Connecting to XServer :1 XSERVER-1 ACCEPT-CONNECT [+0.34s] DEBUG: Seat seat1: Display server ready, starting session authentication [+0.34s] DEBUG: Session pid=1309587: Started with service 'lightdm-greeter', username 'lightdm' [+0.40s] DEBUG: Session pid=1309587: Running command /home/rhansen/floss/lightdm/tests/src/.libs/test-gobject-greeter # # Finally, the replacement greeter stomps on the new Wayland # session. # [+0.40s] DEBUG: Locking login1 session c2 LOGIN1 LOCK-SESSION SESSION=c2
-rw-r--r--src/seat-local.c18
-rw-r--r--tests/scripts/multi-seat-wayland.conf5
2 files changed, 23 insertions, 0 deletions
diff --git a/src/seat-local.c b/src/seat-local.c
index 90bb1455..65207145 100644
--- a/src/seat-local.c
+++ b/src/seat-local.c
@@ -261,6 +261,24 @@ seat_local_set_active_session (Seat *seat, Session *session)
static Session *
seat_local_get_active_session (Seat *seat)
{
+ /*
+ * In the past, virtual terminal switching was the only way to switch
+ * between multiple sessions associated with a seat. Due to operating
+ * system limitations, virtual terminal switching is limited to seat0, so
+ * the vt_* family of functions from vt.h must only be used with seat0.
+ *
+ * Nowadays, systemd-logind (via the org.freedesktop.login1 dbus interface)
+ * can be used to switch sessions. logind supports multiple sessions even
+ * on non-seat0 seats. Whenever logind switches sessions, a callback
+ * updates priv->active_session, so seat_get_expected_active_session should
+ * always return the currently active session.
+ *
+ * FIXME: Use seat_get_expected_active_session even for seat0, falling back
+ * to VT probing if the systemd-logind service is unavailable.
+ */
+ if (strcmp (seat_get_name (seat), "seat0") != 0)
+ return seat_get_expected_active_session (seat);
+
gint vt = vt_get_active ();
if (vt < 0)
return NULL;
diff --git a/tests/scripts/multi-seat-wayland.conf b/tests/scripts/multi-seat-wayland.conf
index a9b6871c..a3356214 100644
--- a/tests/scripts/multi-seat-wayland.conf
+++ b/tests/scripts/multi-seat-wayland.conf
@@ -42,6 +42,11 @@ user-session=wayland
#?SESSION-WAYLAND START XDG_SEAT=seat1 XDG_GREETER_DATA_DIR=.*/no-password2 XDG_SESSION_TYPE=wayland XDG_SESSION_DESKTOP=wayland USER=no-password2
#?LOGIN1 ACTIVATE-SESSION SESSION=c2
+# Ensure that the X server and greeter for seat1 are not restarted until after
+# the user logs out.
+#?*WAIT
+#?*FENCE
+
# Log out. The X server and greeter for seat1 should start again.
#?*SESSION-WAYLAND LOGOUT
#?XSERVER-1 START SEAT=seat1