Chaining two clients through a kept (keep-alive) Mutter display segfaults
gnome-shell in meta_monitor_manager_rebuild (libmutter-18) and takes the whole
desktop down; every later session then fails RemoteDesktop.CreateSession:
ServiceUnknown until GDM restarts. A/B'd on .21: byte-identical on released
0.27.0 and the 0.28.0 RC, so it was never a regression — the trigger has been
there all along.
TOPOLOGY_LOCK already serialized every topology-mutating D-Bus call, but two
gaps still let Mutter's REBUILDS overlap:
- Teardown was fire-and-forget: StopGuard::drop set a flag and returned, and
the session thread only noticed on its ≤200 ms park tick. The A2 dead-reuse
path (reused kept display dead on first frame → mark_failed → re-create)
therefore issued its fresh RecordVirtual with the doomed monitor's removal
still pending — the fresh session could even win the lock BEFORE the old
thread had woken to take it, adding a monitor while the dead one still stood.
The drop now waits (bounded, 20 s) for the session thread to finish.
- The lock was released while the shell was still rebuilding: Stop /
RecordVirtual / ApplyMonitorsConfig all return mid-rebuild, and a temporary
(APPLY_TEMPORARY) config auto-reverts asynchronously on top. Every locked
mutation section now ends with settle_topology() — poll GetCurrentState
until a removed connector is actually gone and the config serial holds still
across two consecutive reads — before the guard drops. Bounded at 4 s and
best-effort (a read error means the shell is gone; a hotplug storm must not
park sessions), degrading to exactly the old behavior.
Cost when Mutter is already quiet: one confirming read plus one 150 ms recheck
per setup/teardown. The live_mutter_create_drop harness sheds its grace sleep —
the synchronous drop IS the teardown confirmation now.
Not fixed here, documented on TOPOLOGY_LOCK: the mid-stream mode-switch rebuild
is create-before-drop by design (H2), so its RecordVirtual still lands while
the superseded monitor exists; the settle makes Mutter quiescent at that point
but cannot remove the coexistence itself.