[mutter/gnome-3-26] monitor-manager: Don't free old state until logical monitors are replaced
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/gnome-3-26] monitor-manager: Don't free old state until logical monitors are replaced
- Date: Mon, 30 Oct 2017 10:54:05 +0000 (UTC)
commit 634f48a1cf20ae8f4ccc5eef2c52f7566bad0382
Author: Jonas Ådahl <jadahl gmail com>
Date: Wed Sep 6 11:10:27 2017 +0800
monitor-manager: Don't free old state until logical monitors are replaced
Logical monitors keep pointers around to monitor objects, which themself
keep pointers aronud to outputs, which keeps pointer to modes and CRTCs.
To avoid causing crashes when using the logical monitor API (which
might use monitor APIs etc) between a hot plug and the time the logical
monitors are regenerated (which is done synchronously in the native
backend but asynchronously in the X11 backend), postpone the freeing of
the state that logical monitor references, until the logical monitor
state is regenerated.
On the native backend, this should have no significant effect, as the
logical state is always regenerated immediately after the hardware
state is updated, but on X11, this should fix race conditions when
events being processed between the hot plug and the hot plug result
tries to access the yet to be up to date state.
https://bugzilla.gnome.org/show_bug.cgi?id=786929
src/backends/meta-monitor-manager-private.h | 13 ++++
src/backends/meta-monitor-manager.c | 91 +++++++++++++++++++++++---
2 files changed, 93 insertions(+), 11 deletions(-)
---
diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index 072e765..6f6d7b7 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -328,6 +328,19 @@ struct _MetaMonitorManager
GList *monitors;
+ struct {
+ MetaOutput *outputs;
+ unsigned int n_outputs;
+
+ MetaCrtcMode *modes;
+ unsigned int n_modes;
+
+ MetaCrtc *crtcs;
+ unsigned int n_crtcs;
+
+ GList *monitors;
+ } pending_cleanup;
+
GList *logical_monitors;
MetaLogicalMonitor *primary_logical_monitor;
diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
index df51ca0..f2ad3f3 100644
--- a/src/backends/meta-monitor-manager.c
+++ b/src/backends/meta-monitor-manager.c
@@ -77,6 +77,9 @@ meta_monitor_manager_is_config_complete (MetaMonitorManager *manager,
MetaMonitorsConfig *config);
static void
+cleanup_pending_cleanup_state (MetaMonitorManager *manager);
+
+static void
meta_monitor_manager_init (MetaMonitorManager *manager)
{
}
@@ -802,6 +805,8 @@ meta_monitor_manager_finalize (GObject *object)
meta_monitor_manager_free_crtc_array (manager->crtcs, manager->n_crtcs);
g_list_free_full (manager->logical_monitors, g_object_unref);
+ cleanup_pending_cleanup_state (manager);
+
g_signal_handler_disconnect (meta_get_backend (),
manager->experimental_features_changed_handler_id);
@@ -2482,16 +2487,10 @@ meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
}
static void
-rebuild_monitors (MetaMonitorManager *manager)
+generate_monitors (MetaMonitorManager *manager)
{
unsigned int i;
- if (manager->monitors)
- {
- g_list_free_full (manager->monitors, g_object_unref);
- manager->monitors = NULL;
- }
-
for (i = 0; i < manager->n_outputs; i++)
{
MetaOutput *output = &manager->outputs[i];
@@ -2551,6 +2550,37 @@ meta_monitor_manager_is_transform_handled (MetaMonitorManager *manager,
return manager_class->is_transform_handled (manager, crtc, transform);
}
+static void
+cleanup_pending_cleanup_state (MetaMonitorManager *manager)
+{
+ if (manager->pending_cleanup.monitors)
+ {
+ g_list_free_full (manager->pending_cleanup.monitors, g_object_unref);
+ manager->pending_cleanup.monitors = NULL;
+ }
+ if (manager->pending_cleanup.outputs)
+ {
+ meta_monitor_manager_free_output_array (manager->pending_cleanup.outputs,
+ manager->pending_cleanup.n_outputs);
+ manager->pending_cleanup.outputs = NULL;
+ manager->pending_cleanup.n_outputs = 0;
+ }
+ if (manager->pending_cleanup.modes)
+ {
+ meta_monitor_manager_free_mode_array (manager->pending_cleanup.modes,
+ manager->pending_cleanup.n_modes);
+ manager->pending_cleanup.modes = NULL;
+ manager->pending_cleanup.n_modes = 0;
+ }
+ if (manager->pending_cleanup.crtcs)
+ {
+ meta_monitor_manager_free_crtc_array (manager->pending_cleanup.crtcs,
+ manager->pending_cleanup.n_crtcs);
+ manager->pending_cleanup.crtcs = NULL;
+ manager->pending_cleanup.n_crtcs = 0;
+ }
+}
+
void
meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
{
@@ -2572,11 +2602,46 @@ meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
manager->serial++;
META_MONITOR_MANAGER_GET_CLASS (manager)->read_current (manager);
- rebuild_monitors (manager);
+ /*
+ * We must delay cleaning up the old hardware state, because the current
+ * logical state, when running on top of X11/Xrandr, may still be based on it
+ * for some time. The logical state may not be updated immediately, in case
+ * it is reconfigured, but after getting the response from a logical state
+ * configuration request to the X server. To be able to handle events and
+ * other things needing the logical state between the request and the
+ * response, the hardware state the logical state points to must be kept
+ * alive.
+ *
+ * If there is already a hardware state pending cleaning up, it means that
+ * the current logical state is still using that hardware state, so we can
+ * destroy the just replaced state immedietaley.
+ */
+ if (manager->pending_cleanup.outputs ||
+ manager->pending_cleanup.crtcs ||
+ manager->pending_cleanup.monitors)
+ {
+ if (manager->monitors)
+ {
+ g_list_free_full (manager->monitors, g_object_unref);
+ manager->monitors = NULL;
+ }
+ meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
+ meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
+ meta_monitor_manager_free_crtc_array (old_crtcs, n_old_crtcs);
+ }
+ else
+ {
+ manager->pending_cleanup.outputs = old_outputs;
+ manager->pending_cleanup.n_outputs = n_old_outputs;
+ manager->pending_cleanup.modes = old_modes;
+ manager->pending_cleanup.n_modes = n_old_modes;
+ manager->pending_cleanup.crtcs = old_crtcs;
+ manager->pending_cleanup.n_crtcs = n_old_crtcs;
+ manager->pending_cleanup.monitors = manager->monitors;
+ manager->monitors = NULL;
+ }
- meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
- meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
- meta_monitor_manager_free_crtc_array (old_crtcs, n_old_crtcs);
+ generate_monitors (manager);
}
static void
@@ -2668,6 +2733,8 @@ meta_monitor_manager_rebuild (MetaMonitorManager *manager,
meta_monitor_manager_notify_monitors_changed (manager);
g_list_free_full (old_logical_monitors, g_object_unref);
+
+ cleanup_pending_cleanup_state (manager);
}
static void
@@ -2710,6 +2777,8 @@ meta_monitor_manager_rebuild_derived (MetaMonitorManager *manager,
meta_monitor_manager_notify_monitors_changed (manager);
g_list_free_full (old_logical_monitors, g_object_unref);
+
+ cleanup_pending_cleanup_state (manager);
}
void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]