Skip to content

Do proper wayland teardown cleaning up listeners and fds#2066

Open
3v1n0 wants to merge 7 commits intoValveSoftware:masterfrom
3v1n0:disconnect-from-signals
Open

Do proper wayland teardown cleaning up listeners and fds#2066
3v1n0 wants to merge 7 commits intoValveSoftware:masterfrom
3v1n0:disconnect-from-signals

Conversation

@3v1n0
Copy link

@3v1n0 3v1n0 commented Jan 21, 2026

In debian we're already using wlroots-0.19, but with it every time a client window is closed or when gamescope itself is closed, we crash with an assertion error.

So remove event listeners (helping #1990) and close the drm FD, ensuring that the page-flip thread is completed.

See commits for details.

3v1n0 added 2 commits January 21, 2026 04:51
If we do not do this newer wlroots would rightly assert every time that
a surface gets closed with:

  gamescope: types/wlr_compositor.c:734:
     surface_handle_resource_destroy:
       Assertion `wl_list_empty(&surface->events.commit.listener_list)'
       failed.

  gamescope: types/wlr_compositor.c:737:
    surface_handle_resource_destroy:
      Assertion `wl_list_empty(&surface->events.destroy.listener_list)'
      failed.
Prevents:
  gamescope: xwayland/server.c:462: wlr_xwayland_server_destroy:
    Assertion `wl_list_empty(&server->events.ready.listener_list)' failed
@3v1n0 3v1n0 mentioned this pull request Jan 21, 2026
1 task
@3v1n0 3v1n0 changed the title Do proper wayland teardown cleanning up listeners and fds Do proper wayland teardown cleaning up listeners and fds Jan 21, 2026
3v1n0 added 5 commits January 21, 2026 05:20
Starting from wlroots 0.19 all these would trigger assertion errors
Destroy the event signals handlers on shutdown
We were not closing the KMS session on destruction since the DRM FD
might be still being polled by the page-flip thread.

Handle this gracefully now by:
 - Create an event-fd
 - Pass the event-fd to the thread
 - Make the thread to repeatedly and atomically check if it should exit

When we're about to finish the drm backend:
 - Mark the thread as thread as completed
 - Write to the event-fd to signal the thread that we're done
 - Join the thread to wait its completion
 - Finally close KMS on wayland side and unset the drm fd

This allows to finally close all the remaining resources or signal
connections that we created on wayland side
struct wl_listener *listener = new wl_listener();
listener->notify = kms_device_handle_change;
wl_signal_add( &wlserver.wlr.device->events.change, listener );
wlserver.wlr.device_change_listener = new wl_listener();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Orthogonal nit: would be slightly nicer to not use new here and just embed the listener in the parent struct. Just something I'm noticing when reading the code, not something that needs fixing in this PR.

std::thread flip_handler_thread( flip_handler_thread_run );
flip_handler_thread.detach();
// Create an eventfd to wake the flip handler poll for immediate exit.
g_page_flip_eventfd = eventfd( 0, EFD_NONBLOCK | EFD_CLOEXEC );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need an eventfd here? Wouldn't a pipe be enough if we close the write end to wake up the pageflip thread and detect HANGUP?

// Create an eventfd to wake the flip handler poll for immediate exit.
g_page_flip_eventfd = eventfd( 0, EFD_NONBLOCK | EFD_CLOEXEC );
if ( g_page_flip_eventfd == -1 ) {
drm_log.errorf_errno( "page-flip eventfd creation failed" );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just fail startup if we can't create the FD? Having to handle missing FD everywhere is painful and will likely just result in a deadlock.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, fair enough

drm_log.errorf_errno( "polling for DRM events failed" );
break;
}
if ( ret == 0 ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot happen, timeout is -1.


// Signal the page-flip handler thread to exit and join it so it won't be
// using the DRM fd while we clean it up. The thread polls with a
// timeout, so this join will return shortly.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thread doesn't poll with a timeout AFAIU.

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.

2 participants