From 995f9f9db82aac1902ef93533f0c59ff4427e34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 3 Mar 2023 22:37:43 +0100 Subject: [PATCH] onscreen/native: Hold output and CRTC refs until dispose We relied on them being valid longer to keep track of used GPUs. If we don't have the CRTC (or output) we don't have a way to fetch the pointer to the MetaGpu that drives the associated monitor. This avoids a crash when trying to fetch said pointer from what would be the NULL MetaCrtc pointer. Fixes: 08593ea872 ("onscreen/native: Hold ref to the output and CRTC until detached") Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2667 Part-of: --- src/backends/native/meta-onscreen-native.c | 5 +- src/tests/meson.build | 10 ++ src/tests/native-kms-hotplug.c | 116 +++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 src/tests/native-kms-hotplug.c diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index b73793d38..734648320 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -2334,6 +2334,9 @@ meta_onscreen_native_dispose (GObject *object) g_clear_pointer (&onscreen_native->gbm.surface, gbm_surface_destroy); g_clear_pointer (&onscreen_native->secondary_gpu_state, secondary_gpu_state_free); + + g_clear_object (&onscreen_native->output); + g_clear_object (&onscreen_native->crtc); } static void @@ -2369,6 +2372,4 @@ void meta_onscreen_native_detach (MetaOnscreenNative *onscreen_native) { clear_invalidation_handlers (onscreen_native); - g_clear_object (&onscreen_native->output); - g_clear_object (&onscreen_native->crtc); } diff --git a/src/tests/meson.build b/src/tests/meson.build index 36dcb888b..f1eb1d220 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -398,6 +398,16 @@ if have_native_tests 'suite': 'backend/native/kms', 'sources': [ 'native-kms-headless-start.c', ], }, + { + 'name': 'kms-hotplug', + 'suite': 'backends/native/kms', + 'sources': [ + 'meta-kms-test-utils.c', + 'meta-kms-test-utils.h', + 'native-kms-hotplug.c', + ], + 'variants': kms_test_variants, + }, ] privileged_test_cases += kms_test_cases diff --git a/src/tests/native-kms-hotplug.c b/src/tests/native-kms-hotplug.c new file mode 100644 index 000000000..d52ed7a6e --- /dev/null +++ b/src/tests/native-kms-hotplug.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023 Red Hat + * + * 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 "backends/meta-monitor-manager-private.h" +#include "meta-test/meta-context-test.h" + +typedef enum _State +{ + INIT, + PAINTED, + PRESENTED, +} State; + +static MetaContext *test_context; + +static void +on_after_paint (ClutterStage *stage, + ClutterStageView *view, + ClutterFrame *frame, + State *state) +{ + *state = PAINTED; +} + +static void +on_presented (ClutterStage *stage, + ClutterStageView *view, + ClutterFrameInfo *frame_info, + State *state) +{ + if (*state == PAINTED) + *state = PRESENTED; +} + +static void +meta_test_reload (void) +{ + MetaBackend *backend = meta_context_get_backend (test_context); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + ClutterActor *stage = meta_backend_get_stage (backend); + GList *logical_monitors; + gulong after_paint_handler_id; + gulong presented_handler_id; + g_autoptr (GError) error = NULL; + State state; + + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (logical_monitors), ==, 1); + + after_paint_handler_id = g_signal_connect (stage, "after-paint", + G_CALLBACK (on_after_paint), + &state); + presented_handler_id = g_signal_connect (stage, "presented", + G_CALLBACK (on_presented), + &state); + + state = INIT; + clutter_actor_queue_redraw (stage); + while (state < PAINTED) + g_main_context_iteration (NULL, TRUE); + + meta_monitor_manager_reload (monitor_manager); + + while (state < PRESENTED) + g_main_context_iteration (NULL, TRUE); + + state = INIT; + clutter_actor_queue_redraw (stage); + while (state < PRESENTED) + g_main_context_iteration (NULL, TRUE); + + g_signal_handler_disconnect (stage, after_paint_handler_id); + g_signal_handler_disconnect (stage, presented_handler_id); +} + +static void +init_tests (void) +{ + g_test_add_func ("/hotplug/reload", + meta_test_reload); +} + +int +main (int argc, char *argv[]) +{ + g_autoptr (MetaContext) context = NULL; + + context = meta_create_test_context (META_CONTEXT_TEST_TYPE_VKMS, + META_CONTEXT_TEST_FLAG_NO_X11); + g_assert (meta_context_configure (context, &argc, &argv, NULL)); + + init_tests (); + + test_context = context; + + return meta_context_test_run_tests (META_CONTEXT_TEST (context), + META_TEST_RUN_FLAG_NONE); +}