Skip to content

modesetting: VT switch can permanently freeze the desktop (lost Present completion)#3411

Open
galternat wants to merge 1 commit into
X11Libre:masterfrom
galternat:fix/modesetting-present-vblank-rearm
Open

modesetting: VT switch can permanently freeze the desktop (lost Present completion)#3411
galternat wants to merge 1 commit into
X11Libre:masterfrom
galternat:fix/modesetting-present-vblank-rearm

Conversation

@galternat

Copy link
Copy Markdown

I switch VTs quite often, and hit this issue maybe once a day before the fix.
I had to use SAK to kill the entire session which very annoying, as you can imagine.
It's been working fine for a almost a month now, rebased on top of xlibre-xserver-25.2.0.

I couldn't reproduce it at all without an external monitor plugged into my laptop.
Here follows the Opus 4.8 report from our joint investigation and testing.


What happens

After switching to another VT and back, the screen stays frozen on the
last frame. The pointer still moves and changes shape, and sound and
background tasks keep running, but nothing repaints and input has no
visible effect. Another VT switch doesn't help; restarting the
compositor does. The log shows this at the first switch:

(WW) modeset(0): failed to queue next vblank event, aborting lost events

Root cause

With a compositor presenting through DRI3/Present in copy mode, each
frame waits for its present to complete before the next is drawn.
During a VT switch the CRTC has no active vblank, so ms_queue_vblank()
returns EINVAL. The re-arm in ms_drm_sequence_handler()
(hw/xfree86/drivers/video/modesetting/vblank.c) then aborts the pending
coalesced vblank events via ms_drm_abort_one(), freeing them without
present_event_notify(). Present never learns those frames completed, so
the compositor stays blocked in xcb_wait_for_special_event() (under
loader_dri3_swap_buffers_msc) indefinitely. The server is otherwise
idle, which is why the cursor still moves.

Reproducing

It's a timing race, so it's intermittent. To raise the odds:

  • Two outputs on one X screen plus a compositor that throttles on
    Present (most GL compositors). This keeps Present in copy mode
    (present_flipping=0) with coalesced waits in flight.

  • Keep something animating, then loop VT switches:

    while :; do chvt 3; sleep 3; chvt 1; sleep 3; done
    
  • It hangs when a DRM event reaches the re-arm during the switch while
    a coalesced wait is pending; the "aborting lost events" line marks
    that moment.

Fix

When the re-arm can't queue the next vblank, complete the waiting
events (delivering their Present completions) instead of aborting them,
so clients aren't left waiting.

On a VT switch the CRTC has no active vblank, so ms_queue_vblank()
fails with EINVAL. When that happens ms_drm_sequence_handler() logs
"aborting lost events" and drops every pending coalesced vblank for
the CRTC via ms_drm_abort_one(), freeing them without calling
present_event_notify().

A Present client waiting on one of those completions (e.g. a
compositor whose DRI3/Present SwapBuffers is throttled in copy mode)
is then never notified and blocks forever, freezing the desktop while
the server itself stays idle.

When re-arming fails, complete the stranded coalesced waits instead of
dropping them, so their Present completions are still delivered.

Fixes: 2d272b7 ("modesetting: coalesce vblank events to avoid DRM event queue exhaustion")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: galternat <galternat.twins223@simplelogin.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant