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

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