From 88fef1d02133e596951e7de438565175b55bdc15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 1 Sep 2023 23:32:06 +0200 Subject: [PATCH] wayland/idle-inhibit: Handle immediate inhibitor destruction If the inhibitor object was destroyed immediately, the proxy construction completing would try to update the inhibitation state, but this didn't work since it was already freed. Fix this by adding an 'initializing' state that keeps track of this. Fixes: a3c62bf8aa ("wayland/idle-inhibit: Add state tracking to fix races") Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2998 Part-of: --- src/tests/meson.build | 1 + src/tests/wayland-test-clients/idle-inhibit.c | 82 +++++++++++++++++++ src/tests/wayland-test-clients/meson.build | 3 + src/tests/wayland-unit-tests.c | 28 +++++++ src/wayland/meta-wayland-idle-inhibit.c | 4 + 5 files changed, 118 insertions(+) create mode 100644 src/tests/wayland-test-clients/idle-inhibit.c diff --git a/src/tests/meson.build b/src/tests/meson.build index c7d1e7725..e658c33b2 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -563,6 +563,7 @@ if have_native_tests 'depends': [ test_client, test_client_executables.get('buffer-transform'), + test_client_executables.get('idle-inhibit'), test_client_executables.get('invalid-subsurfaces'), test_client_executables.get('invalid-xdg-shell-actions'), test_client_executables.get('single-pixel-buffer'), diff --git a/src/tests/wayland-test-clients/idle-inhibit.c b/src/tests/wayland-test-clients/idle-inhibit.c new file mode 100644 index 000000000..23079e879 --- /dev/null +++ b/src/tests/wayland-test-clients/idle-inhibit.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include +#include + +#include "wayland-test-client-utils.h" + +#include "idle-inhibit-unstable-v1-client-protocol.h" + +static WaylandDisplay *display; +struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; + +static void +handle_registry_global (void *user_data, + struct wl_registry *registry, + uint32_t id, + const char *interface, + uint32_t version) +{ + if (strcmp (interface, "zwp_idle_inhibit_manager_v1") == 0) + { + idle_inhibit_manager = wl_registry_bind (registry, id, + &zwp_idle_inhibit_manager_v1_interface, + 1); + } +} + +static void +handle_registry_global_remove (void *user_data, + struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + handle_registry_global, + handle_registry_global_remove +}; + +int +main (int argc, + char **argv) +{ + struct wl_registry *registry; + WaylandSurface *surface; + struct zwp_idle_inhibitor_v1 *inhibitor; + + display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER); + registry = wl_display_get_registry (display->display); + wl_registry_add_listener (registry, ®istry_listener, NULL); + wl_display_roundtrip (display->display); + + surface = wayland_surface_new (display, + "idle-inhibit-client", + 20, 20, 0x11223344); + + inhibitor = + zwp_idle_inhibit_manager_v1_create_inhibitor (idle_inhibit_manager, + surface->wl_surface); + zwp_idle_inhibitor_v1_destroy (inhibitor); + + wl_display_roundtrip (display->display); + + return EXIT_SUCCESS; +} diff --git a/src/tests/wayland-test-clients/meson.build b/src/tests/wayland-test-clients/meson.build index da1fc6533..44f782080 100644 --- a/src/tests/wayland-test-clients/meson.build +++ b/src/tests/wayland-test-clients/meson.build @@ -54,6 +54,9 @@ wayland_test_clients = [ { 'name': 'fullscreen', }, + { + 'name': 'idle-inhibit', + }, { 'name': 'kms-cursor-hotplug-helper', 'extra_deps': [ diff --git a/src/tests/wayland-unit-tests.c b/src/tests/wayland-unit-tests.c index fc863d58b..5ad5d5815 100644 --- a/src/tests/wayland-unit-tests.c +++ b/src/tests/wayland-unit-tests.c @@ -839,6 +839,32 @@ wayland_registry_filter (void) g_assert_false (client3_saw_global); } +static gboolean +set_true (gpointer user_data) +{ + gboolean *done = user_data; + + *done = TRUE; + + return G_SOURCE_REMOVE; +} + +static void +wayland_idle_inhibit_instant_destroy (void) +{ + MetaWaylandTestClient *wayland_test_client; + gboolean done; + + wayland_test_client = + meta_wayland_test_client_new (test_context, "idle-inhibit"); + meta_wayland_test_client_finish (wayland_test_client); + + done = FALSE; + g_timeout_add_seconds (1, set_true, &done); + while (!done) + g_main_context_iteration (NULL, TRUE); +} + static void on_before_tests (void) { @@ -886,6 +912,8 @@ init_tests (void) xdg_foreign_set_parent_of); g_test_add_func ("/wayland/registry/filter", wayland_registry_filter); + g_test_add_func ("/wayland/idle-inhibit/instant-destroy", + wayland_idle_inhibit_instant_destroy); } int diff --git a/src/wayland/meta-wayland-idle-inhibit.c b/src/wayland/meta-wayland-idle-inhibit.c index 559aaa06c..b57f13718 100644 --- a/src/wayland/meta-wayland-idle-inhibit.c +++ b/src/wayland/meta-wayland-idle-inhibit.c @@ -32,6 +32,7 @@ typedef enum _IdleState { + IDLE_STATE_INITIALIZING, IDLE_STATE_UNINHIBITED, IDLE_STATE_INHIBITING, IDLE_STATE_INHIBITED, @@ -151,6 +152,7 @@ update_inhibitation (MetaWaylandIdleInhibitor *inhibitor) switch (inhibitor->state) { + case IDLE_STATE_INITIALIZING: case IDLE_STATE_UNINHIBITED: if (!inhibitor->resource) { @@ -227,6 +229,7 @@ inhibitor_proxy_completed (GObject *source, } inhibitor->session_proxy = proxy; + inhibitor->state = IDLE_STATE_UNINHIBITED; update_inhibitation (inhibitor); } @@ -248,6 +251,7 @@ idle_inhibitor_destructor (struct wl_resource *resource) case IDLE_STATE_UNINHIBITED: meta_wayland_inhibitor_free (inhibitor); return; + case IDLE_STATE_INITIALIZING: case IDLE_STATE_INHIBITED: case IDLE_STATE_INHIBITING: case IDLE_STATE_UNINHIBITING: