desktop-shell: don't run fade animation if compositor is inactive

When a window is closed, Weston will, by default, run a fade out animation and
defer destroying the underlying surface until it completes. However, if the
compositor is sleeping, and therefore not rendering any frames, this animation
will *never* complete. Therefore, if windows are repeatedly created and
destroyed while in sleep mode, these surfaces will keep accumulating, and since
the buffers attached to them may be backed by an fd, eventually the ulimit will
be reached resulting in a potential crash or other errors.

This can be demonstrated repeatedly launching and killing an X11 application
with Xwayland running.

while true; do xterm & pid=$!; sleep 0.5; kill $pid; done

As soon as the compositor goes to sleep, one can observe a steadily growing
list of dmabufs in the output of lsof.

As a fix, desktop_surface_removed should check whether the compositor is active
before kicking off the fade animation. If it is not, it should instead drop the
extra reference taken in desktop_surface_committed and then destroy the surface
immediately.

Signed-off-by: Erik Kurzinger <ekurzinger@nvidia.com>
This commit is contained in:
Erik Kurzinger 2021-05-18 11:49:37 -04:00 committed by Daniel Stone
parent eb34f827dd
commit 04918f3b0b
1 changed files with 15 additions and 9 deletions

View File

@ -2464,22 +2464,28 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
weston_desktop_surface_unlink_view(shsurf->view);
if (weston_surface_is_mapped(surface) &&
shsurf->shell->win_close_animation_type == ANIMATION_FADE) {
if (shsurf->shell->compositor->state == WESTON_COMPOSITOR_ACTIVE) {
pixman_region32_fini(&surface->pending.input);
pixman_region32_init(&surface->pending.input);
pixman_region32_fini(&surface->input);
pixman_region32_init(&surface->input);
weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
fade_out_done, shsurf);
} else {
weston_view_destroy(shsurf->view);
if (shsurf->output_destroy_listener.notify) {
wl_list_remove(&shsurf->output_destroy_listener.link);
shsurf->output_destroy_listener.notify = NULL;
}
free(shsurf);
return;
} else {
--surface->ref_count;
}
}
weston_surface_destroy(surface);
if (shsurf->output_destroy_listener.notify) {
wl_list_remove(&shsurf->output_destroy_listener.link);
shsurf->output_destroy_listener.notify = NULL;
}
free(shsurf);
}
static void