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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3234>
This commit is contained in:
Jonas Ådahl 2023-09-01 23:32:06 +02:00 committed by Marge Bot
parent 10d8c5fa82
commit 88fef1d021
5 changed files with 118 additions and 0 deletions

View File

@ -563,6 +563,7 @@ if have_native_tests
'depends': [ 'depends': [
test_client, test_client,
test_client_executables.get('buffer-transform'), test_client_executables.get('buffer-transform'),
test_client_executables.get('idle-inhibit'),
test_client_executables.get('invalid-subsurfaces'), test_client_executables.get('invalid-subsurfaces'),
test_client_executables.get('invalid-xdg-shell-actions'), test_client_executables.get('invalid-xdg-shell-actions'),
test_client_executables.get('single-pixel-buffer'), test_client_executables.get('single-pixel-buffer'),

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib.h>
#include <wayland-client.h>
#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, &registry_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;
}

View File

@ -54,6 +54,9 @@ wayland_test_clients = [
{ {
'name': 'fullscreen', 'name': 'fullscreen',
}, },
{
'name': 'idle-inhibit',
},
{ {
'name': 'kms-cursor-hotplug-helper', 'name': 'kms-cursor-hotplug-helper',
'extra_deps': [ 'extra_deps': [

View File

@ -839,6 +839,32 @@ wayland_registry_filter (void)
g_assert_false (client3_saw_global); 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 static void
on_before_tests (void) on_before_tests (void)
{ {
@ -886,6 +912,8 @@ init_tests (void)
xdg_foreign_set_parent_of); xdg_foreign_set_parent_of);
g_test_add_func ("/wayland/registry/filter", g_test_add_func ("/wayland/registry/filter",
wayland_registry_filter); wayland_registry_filter);
g_test_add_func ("/wayland/idle-inhibit/instant-destroy",
wayland_idle_inhibit_instant_destroy);
} }
int int

View File

@ -32,6 +32,7 @@
typedef enum _IdleState typedef enum _IdleState
{ {
IDLE_STATE_INITIALIZING,
IDLE_STATE_UNINHIBITED, IDLE_STATE_UNINHIBITED,
IDLE_STATE_INHIBITING, IDLE_STATE_INHIBITING,
IDLE_STATE_INHIBITED, IDLE_STATE_INHIBITED,
@ -151,6 +152,7 @@ update_inhibitation (MetaWaylandIdleInhibitor *inhibitor)
switch (inhibitor->state) switch (inhibitor->state)
{ {
case IDLE_STATE_INITIALIZING:
case IDLE_STATE_UNINHIBITED: case IDLE_STATE_UNINHIBITED:
if (!inhibitor->resource) if (!inhibitor->resource)
{ {
@ -227,6 +229,7 @@ inhibitor_proxy_completed (GObject *source,
} }
inhibitor->session_proxy = proxy; inhibitor->session_proxy = proxy;
inhibitor->state = IDLE_STATE_UNINHIBITED;
update_inhibitation (inhibitor); update_inhibitation (inhibitor);
} }
@ -248,6 +251,7 @@ idle_inhibitor_destructor (struct wl_resource *resource)
case IDLE_STATE_UNINHIBITED: case IDLE_STATE_UNINHIBITED:
meta_wayland_inhibitor_free (inhibitor); meta_wayland_inhibitor_free (inhibitor);
return; return;
case IDLE_STATE_INITIALIZING:
case IDLE_STATE_INHIBITED: case IDLE_STATE_INHIBITED:
case IDLE_STATE_INHIBITING: case IDLE_STATE_INHIBITING:
case IDLE_STATE_UNINHIBITING: case IDLE_STATE_UNINHIBITING: