From feb1cf50ccc9d5e8066aa47d69c53bb39f9dff82 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 17 Jul 2018 20:20:55 +0000 Subject: display-factory: avoid removing a display from store while iterating it --- daemon/gdm-display-factory.c | 41 ++++++++++++++++++++++++++++++++++++++ daemon/gdm-display-factory.h | 1 + daemon/gdm-local-display-factory.c | 7 ++----- daemon/gdm-xdmcp-display-factory.c | 7 ++----- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/daemon/gdm-display-factory.c b/daemon/gdm-display-factory.c index d86a4c8a..c520e108 100644 --- a/daemon/gdm-display-factory.c +++ b/daemon/gdm-display-factory.c @@ -35,6 +35,7 @@ struct GdmDisplayFactoryPrivate { GdmDisplayStore *display_store; + guint purge_displays_id; }; enum { @@ -59,6 +60,41 @@ gdm_display_factory_error_quark (void) return ret; } +static gboolean +purge_display (char *id, + GdmDisplay *display, + gpointer user_data) +{ + int status; + + status = gdm_display_get_status (display); + + switch (status) { + case GDM_DISPLAY_FINISHED: + case GDM_DISPLAY_FAILED: + return TRUE; + default: + return FALSE; + } +} + +static void +purge_displays (GdmDisplayFactory *factory) +{ + factory->priv->purge_displays_id = 0; + gdm_display_store_foreach_remove (factory->priv->display_store, + (GdmDisplayStoreFunc)purge_display, + NULL); +} + +void +gdm_display_factory_queue_purge_displays (GdmDisplayFactory *factory) +{ + if (factory->priv->purge_displays_id == 0) { + factory->priv->purge_displays_id = g_idle_add ((GSourceFunc) purge_displays, factory); + } +} + GdmDisplayStore * gdm_display_factory_get_display_store (GdmDisplayFactory *factory) { @@ -187,5 +223,10 @@ gdm_display_factory_finalize (GObject *object) g_return_if_fail (factory->priv != NULL); + if (factory->priv->purge_displays_id != 0) { + g_source_remove (factory->priv->purge_displays_id); + factory->priv->purge_displays_id = 0; + } + G_OBJECT_CLASS (gdm_display_factory_parent_class)->finalize (object); } diff --git a/daemon/gdm-display-factory.h b/daemon/gdm-display-factory.h index 6b30f83d..1cffa1bd 100644 --- a/daemon/gdm-display-factory.h +++ b/daemon/gdm-display-factory.h @@ -64,6 +64,7 @@ GType gdm_display_factory_get_type (void); gboolean gdm_display_factory_start (GdmDisplayFactory *manager); gboolean gdm_display_factory_stop (GdmDisplayFactory *manager); GdmDisplayStore * gdm_display_factory_get_display_store (GdmDisplayFactory *manager); +void gdm_display_factory_queue_purge_displays (GdmDisplayFactory *manager); G_END_DECLS diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index b29f5ac5..25d30f5b 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -249,7 +249,6 @@ on_display_status_changed (GdmDisplay *display, GdmLocalDisplayFactory *factory) { int status; - GdmDisplayStore *store; int num; char *seat_id = NULL; char *session_type = NULL; @@ -259,8 +258,6 @@ on_display_status_changed (GdmDisplay *display, num = -1; gdm_display_get_x11_display_number (display, &num, NULL); - store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); - g_object_get (display, "seat-id", &seat_id, "is-initial", &is_initial, @@ -278,7 +275,7 @@ on_display_status_changed (GdmDisplay *display, if (num != -1) { g_hash_table_remove (factory->priv->used_display_numbers, GUINT_TO_POINTER (num)); } - gdm_display_store_remove (store, display); + gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); /* if this is a local display, do a full resync. Only * seats without displays will get created anyway. This @@ -295,7 +292,7 @@ on_display_status_changed (GdmDisplay *display, case GDM_DISPLAY_FAILED: /* leave the display number in factory->priv->used_display_numbers so that it doesn't get reused */ - gdm_display_store_remove (store, display); + gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); /* Create a new equivalent display if it was static */ if (is_local) { diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c index 46a0d9ff..5b5786c6 100644 --- a/daemon/gdm-xdmcp-display-factory.c +++ b/daemon/gdm-xdmcp-display-factory.c @@ -2066,15 +2066,12 @@ on_display_status_changed (GdmDisplay *display, GdmXdmcpDisplayFactory *factory) { int status; - GdmDisplayStore *store; GdmLaunchEnvironment *launch_environment; GdmSession *session; GdmAddress *address; gint32 session_number; int display_number; - store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); - launch_environment = NULL; g_object_get (display, "launch-environment", &launch_environment, NULL); @@ -2095,10 +2092,10 @@ on_display_status_changed (GdmDisplay *display, NULL); gdm_xdmcp_send_alive (factory, address, display_number, session_number); - gdm_display_store_remove (store, display); + gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); break; case GDM_DISPLAY_FAILED: - gdm_display_store_remove (store, display); + gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); break; case GDM_DISPLAY_UNMANAGED: if (session != NULL) { -- cgit v1.2.1