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

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