Blame SOURCES/0005-display-factory-avoid-removing-a-display-from-store-.patch

c4edd0
From b322fd907ef49a77a11ed6e5b9c858a7dd43d064 Mon Sep 17 00:00:00 2001
c4edd0
From: Lubomir Rintel <lkundrak@v3.sk>
c4edd0
Date: Tue, 17 Jul 2018 20:20:55 +0000
c4edd0
Subject: [PATCH 5/7] display-factory: avoid removing a display from store
c4edd0
 while iterating it
c4edd0
c4edd0
---
c4edd0
 daemon/gdm-display-factory.c       | 41 ++++++++++++++++++++++++++++++
c4edd0
 daemon/gdm-display-factory.h       |  1 +
c4edd0
 daemon/gdm-local-display-factory.c |  7 ++---
c4edd0
 daemon/gdm-xdmcp-display-factory.c |  7 ++---
c4edd0
 4 files changed, 46 insertions(+), 10 deletions(-)
c4edd0
c4edd0
diff --git a/daemon/gdm-display-factory.c b/daemon/gdm-display-factory.c
c4edd0
index d86a4c8ad..c520e1088 100644
c4edd0
--- a/daemon/gdm-display-factory.c
c4edd0
+++ b/daemon/gdm-display-factory.c
c4edd0
@@ -8,84 +8,120 @@
c4edd0
  * (at your option) any later version.
c4edd0
  *
c4edd0
  * This program is distributed in the hope that it will be useful,
c4edd0
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
c4edd0
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
c4edd0
  * GNU General Public License for more details.
c4edd0
  *
c4edd0
  * You should have received a copy of the GNU General Public License
c4edd0
  * along with this program; if not, write to the Free Software
c4edd0
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
c4edd0
  *
c4edd0
  */
c4edd0
 
c4edd0
 #include "config.h"
c4edd0
 
c4edd0
 #include <stdlib.h>
c4edd0
 #include <stdio.h>
c4edd0
 
c4edd0
 #include <glib.h>
c4edd0
 #include <glib/gi18n.h>
c4edd0
 #include <glib-object.h>
c4edd0
 
c4edd0
 #include "gdm-display-factory.h"
c4edd0
 #include "gdm-display-store.h"
c4edd0
 
c4edd0
 #define GDM_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY_FACTORY, GdmDisplayFactoryPrivate))
c4edd0
 
c4edd0
 struct GdmDisplayFactoryPrivate
c4edd0
 {
c4edd0
         GdmDisplayStore *display_store;
c4edd0
+        guint            purge_displays_id;
c4edd0
 };
c4edd0
 
c4edd0
 enum {
c4edd0
         PROP_0,
c4edd0
         PROP_DISPLAY_STORE,
c4edd0
 };
c4edd0
 
c4edd0
 static void     gdm_display_factory_class_init  (GdmDisplayFactoryClass *klass);
c4edd0
 static void     gdm_display_factory_init        (GdmDisplayFactory      *factory);
c4edd0
 static void     gdm_display_factory_finalize    (GObject                *object);
c4edd0
 
c4edd0
 G_DEFINE_ABSTRACT_TYPE (GdmDisplayFactory, gdm_display_factory, G_TYPE_OBJECT)
c4edd0
 
c4edd0
 GQuark
c4edd0
 gdm_display_factory_error_quark (void)
c4edd0
 {
c4edd0
         static GQuark ret = 0;
c4edd0
         if (ret == 0) {
c4edd0
                 ret = g_quark_from_static_string ("gdm_display_factory_error");
c4edd0
         }
c4edd0
 
c4edd0
         return ret;
c4edd0
 }
c4edd0
 
c4edd0
+static gboolean
c4edd0
+purge_display (char       *id,
c4edd0
+               GdmDisplay *display,
c4edd0
+               gpointer    user_data)
c4edd0
+{
c4edd0
+        int status;
c4edd0
+
c4edd0
+        status = gdm_display_get_status (display);
c4edd0
+
c4edd0
+        switch (status) {
c4edd0
+        case GDM_DISPLAY_FINISHED:
c4edd0
+        case GDM_DISPLAY_FAILED:
c4edd0
+                return TRUE;
c4edd0
+        default:
c4edd0
+                return FALSE;
c4edd0
+        }
c4edd0
+}
c4edd0
+
c4edd0
+static void
c4edd0
+purge_displays (GdmDisplayFactory *factory)
c4edd0
+{
c4edd0
+        factory->priv->purge_displays_id = 0;
c4edd0
+        gdm_display_store_foreach_remove (factory->priv->display_store,
c4edd0
+                                          (GdmDisplayStoreFunc)purge_display,
c4edd0
+                                          NULL);
c4edd0
+}
c4edd0
+
c4edd0
+void
c4edd0
+gdm_display_factory_queue_purge_displays (GdmDisplayFactory *factory)
c4edd0
+{
c4edd0
+        if (factory->priv->purge_displays_id == 0) {
c4edd0
+                factory->priv->purge_displays_id = g_idle_add ((GSourceFunc) purge_displays, factory);
c4edd0
+        }
c4edd0
+}
c4edd0
+
c4edd0
 GdmDisplayStore *
c4edd0
 gdm_display_factory_get_display_store (GdmDisplayFactory *factory)
c4edd0
 {
c4edd0
         g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), NULL);
c4edd0
 
c4edd0
         return factory->priv->display_store;
c4edd0
 }
c4edd0
 
c4edd0
 gboolean
c4edd0
 gdm_display_factory_start (GdmDisplayFactory *factory)
c4edd0
 {
c4edd0
         gboolean ret;
c4edd0
 
c4edd0
         g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE);
c4edd0
 
c4edd0
         g_object_ref (factory);
c4edd0
         ret = GDM_DISPLAY_FACTORY_GET_CLASS (factory)->start (factory);
c4edd0
         g_object_unref (factory);
c4edd0
 
c4edd0
         return ret;
c4edd0
 }
c4edd0
 
c4edd0
 gboolean
c4edd0
 gdm_display_factory_stop (GdmDisplayFactory *factory)
c4edd0
 {
c4edd0
         gboolean ret;
c4edd0
 
c4edd0
         g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE);
c4edd0
 
c4edd0
         g_object_ref (factory);
c4edd0
@@ -160,32 +196,37 @@ gdm_display_factory_class_init (GdmDisplayFactoryClass *klass)
c4edd0
 
c4edd0
         g_object_class_install_property (object_class,
c4edd0
                                          PROP_DISPLAY_STORE,
c4edd0
                                          g_param_spec_object ("display-store",
c4edd0
                                                               "display store",
c4edd0
                                                               "display store",
c4edd0
                                                               GDM_TYPE_DISPLAY_STORE,
c4edd0
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
c4edd0
 
c4edd0
         g_type_class_add_private (klass, sizeof (GdmDisplayFactoryPrivate));
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_display_factory_init (GdmDisplayFactory *factory)
c4edd0
 {
c4edd0
         factory->priv = GDM_DISPLAY_FACTORY_GET_PRIVATE (factory);
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 gdm_display_factory_finalize (GObject *object)
c4edd0
 {
c4edd0
         GdmDisplayFactory *factory;
c4edd0
 
c4edd0
         g_return_if_fail (object != NULL);
c4edd0
         g_return_if_fail (GDM_IS_DISPLAY_FACTORY (object));
c4edd0
 
c4edd0
         factory = GDM_DISPLAY_FACTORY (object);
c4edd0
 
c4edd0
         g_return_if_fail (factory->priv != NULL);
c4edd0
 
c4edd0
+        if (factory->priv->purge_displays_id != 0) {
c4edd0
+                g_source_remove (factory->priv->purge_displays_id);
c4edd0
+                factory->priv->purge_displays_id = 0;
c4edd0
+        }
c4edd0
+
c4edd0
         G_OBJECT_CLASS (gdm_display_factory_parent_class)->finalize (object);
c4edd0
 }
c4edd0
diff --git a/daemon/gdm-display-factory.h b/daemon/gdm-display-factory.h
c4edd0
index 6b30f83dc..1cffa1bd5 100644
c4edd0
--- a/daemon/gdm-display-factory.h
c4edd0
+++ b/daemon/gdm-display-factory.h
c4edd0
@@ -37,34 +37,35 @@ G_BEGIN_DECLS
c4edd0
 
c4edd0
 typedef struct GdmDisplayFactoryPrivate GdmDisplayFactoryPrivate;
c4edd0
 
c4edd0
 typedef struct
c4edd0
 {
c4edd0
         GObject                   parent;
c4edd0
         GdmDisplayFactoryPrivate *priv;
c4edd0
 } GdmDisplayFactory;
c4edd0
 
c4edd0
 typedef struct
c4edd0
 {
c4edd0
         GObjectClass   parent_class;
c4edd0
 
c4edd0
         gboolean (*start)                  (GdmDisplayFactory *factory);
c4edd0
         gboolean (*stop)                   (GdmDisplayFactory *factory);
c4edd0
 } GdmDisplayFactoryClass;
c4edd0
 
c4edd0
 typedef enum
c4edd0
 {
c4edd0
          GDM_DISPLAY_FACTORY_ERROR_GENERAL
c4edd0
 } GdmDisplayFactoryError;
c4edd0
 
c4edd0
 #define GDM_DISPLAY_FACTORY_ERROR gdm_display_factory_error_quark ()
c4edd0
 
c4edd0
 GQuark                     gdm_display_factory_error_quark             (void);
c4edd0
 GType                      gdm_display_factory_get_type                (void);
c4edd0
 
c4edd0
 gboolean                   gdm_display_factory_start                   (GdmDisplayFactory *manager);
c4edd0
 gboolean                   gdm_display_factory_stop                    (GdmDisplayFactory *manager);
c4edd0
 GdmDisplayStore *          gdm_display_factory_get_display_store       (GdmDisplayFactory *manager);
c4edd0
+void                       gdm_display_factory_queue_purge_displays    (GdmDisplayFactory *manager);
c4edd0
 
c4edd0
 G_END_DECLS
c4edd0
 
c4edd0
 #endif /* __GDM_DISPLAY_FACTORY_H */
c4edd0
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
c4edd0
index 6856d30d0..1c7daeb14 100644
c4edd0
--- a/daemon/gdm-local-display-factory.c
c4edd0
+++ b/daemon/gdm-local-display-factory.c
c4edd0
@@ -224,128 +224,125 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
c4edd0
                       "seat-id", "seat0",
c4edd0
                       "allow-timed-login", FALSE,
c4edd0
                       NULL);
c4edd0
 
c4edd0
         store_display (factory, display);
c4edd0
 
c4edd0
         if (! gdm_display_manage (display)) {
c4edd0
                 display = NULL;
c4edd0
                 goto out;
c4edd0
         }
c4edd0
 
c4edd0
         if (! gdm_display_get_id (display, id, NULL)) {
c4edd0
                 display = NULL;
c4edd0
                 goto out;
c4edd0
         }
c4edd0
 
c4edd0
         ret = TRUE;
c4edd0
  out:
c4edd0
         /* ref either held by store or not at all */
c4edd0
         g_object_unref (display);
c4edd0
 
c4edd0
         return ret;
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 on_display_status_changed (GdmDisplay             *display,
c4edd0
                            GParamSpec             *arg1,
c4edd0
                            GdmLocalDisplayFactory *factory)
c4edd0
 {
c4edd0
         int              status;
c4edd0
-        GdmDisplayStore *store;
c4edd0
         int              num;
c4edd0
         char            *seat_id = NULL;
c4edd0
         char            *session_id = NULL;
c4edd0
         char            *session_type = NULL;
c4edd0
         char            *session_class = NULL;
c4edd0
         gboolean         is_initial = TRUE;
c4edd0
         gboolean         is_local = TRUE;
c4edd0
         int              ret;
c4edd0
 
c4edd0
         num = -1;
c4edd0
         gdm_display_get_x11_display_number (display, &num, NULL);
c4edd0
 
c4edd0
-        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
c4edd0
-
c4edd0
         g_object_get (display,
c4edd0
                       "seat-id", &seat_id,
c4edd0
                       "session-id", &session_id,
c4edd0
                       "is-initial", &is_initial,
c4edd0
                       "is-local", &is_local,
c4edd0
                       "session-type", &session_type,
c4edd0
                       "session-class", &session_class,
c4edd0
                       NULL);
c4edd0
 
c4edd0
         status = gdm_display_get_status (display);
c4edd0
 
c4edd0
         g_debug ("GdmLocalDisplayFactory: display status changed: %d", status);
c4edd0
         switch (status) {
c4edd0
         case GDM_DISPLAY_FINISHED:
c4edd0
                 /* remove the display number from factory->priv->used_display_numbers
c4edd0
                    so that it may be reused */
c4edd0
                 if (num != -1) {
c4edd0
                         g_hash_table_remove (factory->priv->used_display_numbers, GUINT_TO_POINTER (num));
c4edd0
                 }
c4edd0
-                gdm_display_store_remove (store, display);
c4edd0
+                gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
c4edd0
 
c4edd0
                 /* if this is a local display, recreate the display so
c4edd0
                  * a new login screen comes up if one is missing.
c4edd0
                  */
c4edd0
                 if (is_local && g_strcmp0 (session_class, "greeter") != 0) {
c4edd0
                         g_autofree char *active_session = NULL;
c4edd0
 
c4edd0
                         /* reset num failures */
c4edd0
                         factory->priv->num_failures = 0;
c4edd0
 
c4edd0
                         ret = sd_seat_get_active (seat_id, &active_session, NULL);
c4edd0
 
c4edd0
                         if (ret == 0) {
c4edd0
                                 g_autofree char *state = NULL;
c4edd0
                                 ret = sd_session_get_state (active_session, &state);
c4edd0
                                 if (ret != 0 ||
c4edd0
                                     g_strcmp0 (state, "closing") == 0 ||
c4edd0
                                     g_strcmp0 (active_session, session_id) == 0) {
c4edd0
                                         g_clear_pointer (&active_session, free);
c4edd0
                                 }
c4edd0
                         }
c4edd0
 
c4edd0
                         /* If this died in the foreground leaving us on a blank vt,
c4edd0
                            start a new login screen */
c4edd0
                         if (!sd_seat_can_multi_session (seat_id) || active_session == NULL) {
c4edd0
                                 create_display (factory, seat_id, session_type, is_initial);
c4edd0
                         }
c4edd0
                 }
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_FAILED:
c4edd0
                 /* leave the display number in factory->priv->used_display_numbers
c4edd0
                    so that it doesn't get reused */
c4edd0
-                gdm_display_store_remove (store, display);
c4edd0
+                gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
c4edd0
 
c4edd0
                 /* Create a new equivalent display if it was static */
c4edd0
                 if (is_local) {
c4edd0
 
c4edd0
                         factory->priv->num_failures++;
c4edd0
 
c4edd0
                         if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) {
c4edd0
                                 /* oh shit */
c4edd0
                                 g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors");
c4edd0
                         } else {
c4edd0
 #ifdef ENABLE_WAYLAND_SUPPORT
c4edd0
                                 if (g_strcmp0 (session_type, "wayland") == 0) {
c4edd0
                                         g_free (session_type);
c4edd0
                                         session_type = NULL;
c4edd0
                                 }
c4edd0
 
c4edd0
 #endif
c4edd0
                                 create_display (factory, seat_id, session_type, is_initial);
c4edd0
                         }
c4edd0
                 }
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_UNMANAGED:
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_PREPARED:
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_MANAGED:
c4edd0
                 break;
c4edd0
         default:
c4edd0
                 g_assert_not_reached ();
c4edd0
                 break;
c4edd0
diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c
c4edd0
index 46a0d9ffa..5b5786c6f 100644
c4edd0
--- a/daemon/gdm-xdmcp-display-factory.c
c4edd0
+++ b/daemon/gdm-xdmcp-display-factory.c
c4edd0
@@ -2039,93 +2039,90 @@ on_hostname_selected (GdmXdmcpChooserDisplay *display,
c4edd0
                 char *ip;
c4edd0
                 ic->chosen_address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
c4edd0
 
c4edd0
                 ip = NULL;
c4edd0
                 gdm_address_get_numeric_info (ic->chosen_address, &ip, NULL);
c4edd0
                 g_debug ("GdmXdmcpDisplayFactory: hostname resolves to %s",
c4edd0
                         ip ? ip : "(null)");
c4edd0
                 g_free (ip);
c4edd0
         }
c4edd0
 
c4edd0
         freeaddrinfo (ai_list);
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 on_client_disconnected (GdmDisplay *display)
c4edd0
 {
c4edd0
         if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED)
c4edd0
                 return;
c4edd0
 
c4edd0
         gdm_display_stop_greeter_session (display);
c4edd0
         gdm_display_unmanage (display);
c4edd0
         gdm_display_finish (display);
c4edd0
 }
c4edd0
 
c4edd0
 static void
c4edd0
 on_display_status_changed (GdmDisplay             *display,
c4edd0
                            GParamSpec             *arg1,
c4edd0
                            GdmXdmcpDisplayFactory *factory)
c4edd0
 {
c4edd0
         int              status;
c4edd0
-        GdmDisplayStore *store;
c4edd0
         GdmLaunchEnvironment *launch_environment;
c4edd0
         GdmSession *session;
c4edd0
         GdmAddress *address;
c4edd0
         gint32  session_number;
c4edd0
         int display_number;
c4edd0
 
c4edd0
-        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
c4edd0
-
c4edd0
         launch_environment = NULL;
c4edd0
         g_object_get (display, "launch-environment", &launch_environment, NULL);
c4edd0
 
c4edd0
         session = NULL;
c4edd0
         if (launch_environment != NULL) {
c4edd0
                 session = gdm_launch_environment_get_session (launch_environment);
c4edd0
         }
c4edd0
 
c4edd0
         status = gdm_display_get_status (display);
c4edd0
 
c4edd0
         g_debug ("GdmXdmcpDisplayFactory: xdmcp display status changed: %d", status);
c4edd0
         switch (status) {
c4edd0
         case GDM_DISPLAY_FINISHED:
c4edd0
                 g_object_get (display,
c4edd0
                               "remote-address", &address,
c4edd0
                               "x11-display-number", &display_number,
c4edd0
                               "session-number", &session_number,
c4edd0
                               NULL);
c4edd0
                 gdm_xdmcp_send_alive (factory, address, display_number, session_number);
c4edd0
 
c4edd0
-                gdm_display_store_remove (store, display);
c4edd0
+                gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_FAILED:
c4edd0
-                gdm_display_store_remove (store, display);
c4edd0
+                gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_UNMANAGED:
c4edd0
                 if (session != NULL) {
c4edd0
                         g_signal_handlers_disconnect_by_func (G_OBJECT (session),
c4edd0
                                                               G_CALLBACK (on_client_disconnected),
c4edd0
                                                               display);
c4edd0
                 }
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_PREPARED:
c4edd0
                 break;
c4edd0
         case GDM_DISPLAY_MANAGED:
c4edd0
                 if (session != NULL) {
c4edd0
                         g_signal_connect_object (G_OBJECT (session),
c4edd0
                                                  "client-disconnected",
c4edd0
                                                  G_CALLBACK (on_client_disconnected),
c4edd0
                                                  display, G_CONNECT_SWAPPED);
c4edd0
                         g_signal_connect_object (G_OBJECT (session),
c4edd0
                                                  "disconnected",
c4edd0
                                                  G_CALLBACK (on_client_disconnected),
c4edd0
                                                  display, G_CONNECT_SWAPPED);
c4edd0
                 }
c4edd0
                 break;
c4edd0
         default:
c4edd0
                 g_assert_not_reached ();
c4edd0
                 break;
c4edd0
         }
c4edd0
 }
c4edd0
 
c4edd0
 static GdmDisplay *
c4edd0
 gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory,
c4edd0
-- 
c4edd0
2.21.0
c4edd0