[gdm: 1/2] display-factory: avoid removing a display from store while iterating it



commit feb1cf50ccc9d5e8066aa47d69c53bb39f9dff82
Author: Lubomir Rintel <lkundrak v3 sk>
Date:   Tue Jul 17 20:20:55 2018 +0000

    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) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]