diff options
author | Richard Hansen <rhansen@rhansen.org> | 2023-04-17 04:44:18 -0400 |
---|---|---|
committer | Robert Ancell <robert.ancell@gmail.com> | 2023-04-28 13:34:51 +1200 |
commit | 8493ec0a100c2bfcc399bfe5ccd2132eef78cd80 (patch) | |
tree | 160be93ca5f88714006964c627aef062620ee94c | |
parent | abf43606f09cb4e340597b407d2fe3b1cb64d5eb (diff) | |
download | lightdm-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.c | 18 | ||||
-rw-r--r-- | tests/scripts/multi-seat-wayland.conf | 5 |
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 |