Do proper wayland teardown cleaning up listeners and fds#2066
Do proper wayland teardown cleaning up listeners and fds#20663v1n0 wants to merge 7 commits intoValveSoftware:masterfrom
Conversation
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
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
ed8b88b to
863aaca
Compare
| 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(); |
There was a problem hiding this comment.
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 ); |
There was a problem hiding this comment.
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" ); |
There was a problem hiding this comment.
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.
| drm_log.errorf_errno( "polling for DRM events failed" ); | ||
| break; | ||
| } | ||
| if ( ret == 0 ) { |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
The thread doesn't poll with a timeout AFAIU.
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.