[mutter] kms: Process impl idle callbacks before pre dispatch flush



commit 79491df2b8d90af3011d6a3a29b0d63ad52677f8
Author: Pekka Paalanen <pekka paalanen collabora com>
Date:   Fri Nov 29 12:50:30 2019 +0200

    kms: Process impl idle callbacks before pre dispatch flush
    
    mode_set_fallback() schedules a call to mode_set_fallback_feedback_idle(), but
    it is possible for Mutter to repaint before the idle callbacks are dispatched.
    If that happens, mode_set_fallback_feedback_idle() does not get called before
    Mutter enters wait_for_pending_flips(), leading to a deadlock.
    
    Add the needed interfaces so that meta_kms_device_dispatch_sync() can flush all
    the implementation idle callbacks before it checks if any "events" are
    available. This prevents the deadlock by ensuring
    mode_set_fallback_feedback_idle() does get called before potentially waiting
    for actual DRM events.
    
    Presumably this call would not be needed if the implementation was running in
    its own thread, since it would eventually dispatch its idle callbacks before
    going to sleep polling on the DRM fd. This call might even be unnecessary
    overhead in that case, synchronizing with the implementation thread needlessly.
    But the thread does not exist yet, so this is needed for now.
    
    This is part 1 of 2 fixing a complete desktop freeze when drmModePageFlip()
    fails with EINVAL and the fallback to drmModeSetCrtc() succeeds but the success
    is not registered correctly as completed "flip". The freeze occurs under
    wait_for_pending_flips() which calls down into meta_kms_impl_device_dispatch()
    which ends up poll()'ing the DRM fd even though drmModeSetCrtc() will not
    produce a DRM event, hence the poll() never returns. The freeze was observed
    when hotplugging a DisplayLink dock for the first time on Ubuntu 19.10.
    
    CC stable: gnome-3-34
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/953

 src/backends/native/meta-kms-device.c      | 17 +++++++++++++++++
 src/backends/native/meta-kms-impl-simple.c | 11 +++++++++++
 src/backends/native/meta-kms-impl.c        |  7 +++++++
 src/backends/native/meta-kms-impl.h        |  4 ++++
 4 files changed, 39 insertions(+)
---
diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c
index 8ed2de024..c6a05e83c 100644
--- a/src/backends/native/meta-kms-device.c
+++ b/src/backends/native/meta-kms-device.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2019 Red Hat
+ * Copyright (C) 2019 DisplayLink (UK) Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -149,12 +150,28 @@ dispatch_in_impl (MetaKmsImpl  *impl,
   return meta_kms_impl_device_dispatch (impl_device, error);
 }
 
+static gboolean
+dispatch_idle_in_impl (MetaKmsImpl  *impl,
+                       gpointer      user_data,
+                       GError      **error)
+{
+  meta_kms_impl_dispatch_idle (impl);
+
+  return TRUE;
+}
+
 int
 meta_kms_device_dispatch_sync (MetaKmsDevice  *device,
                                GError        **error)
 {
   int callback_count;
 
+  if (!meta_kms_run_impl_task_sync (device->kms,
+                                    dispatch_idle_in_impl,
+                                    device->impl_device,
+                                    error))
+    return -1;
+
   callback_count = meta_kms_flush_callbacks (device->kms);
   if (callback_count > 0)
     return TRUE;
diff --git a/src/backends/native/meta-kms-impl-simple.c b/src/backends/native/meta-kms-impl-simple.c
index 571dccf12..78d5cc445 100644
--- a/src/backends/native/meta-kms-impl-simple.c
+++ b/src/backends/native/meta-kms-impl-simple.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018-2019 Red Hat
+ * Copyright (C) 2019 DisplayLink (UK) Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -806,6 +807,15 @@ meta_kms_impl_simple_discard_pending_page_flips (MetaKmsImpl *impl)
                    g_source_destroy);
 }
 
+static void
+meta_kms_impl_simple_dispatch_idle (MetaKmsImpl *impl)
+{
+  MetaKmsImplSimple *impl_simple = META_KMS_IMPL_SIMPLE (impl);
+
+  if (impl_simple->mode_set_fallback_feedback_source)
+    mode_set_fallback_feedback_idle (impl_simple);
+}
+
 static void
 meta_kms_impl_simple_finalize (GObject *object)
 {
@@ -845,4 +855,5 @@ meta_kms_impl_simple_class_init (MetaKmsImplSimpleClass *klass)
   impl_class->process_update = meta_kms_impl_simple_process_update;
   impl_class->handle_page_flip_callback = meta_kms_impl_simple_handle_page_flip_callback;
   impl_class->discard_pending_page_flips = meta_kms_impl_simple_discard_pending_page_flips;
+  impl_class->dispatch_idle = meta_kms_impl_simple_dispatch_idle;
 }
diff --git a/src/backends/native/meta-kms-impl.c b/src/backends/native/meta-kms-impl.c
index 1934d21ae..731f5970f 100644
--- a/src/backends/native/meta-kms-impl.c
+++ b/src/backends/native/meta-kms-impl.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Red Hat
+ * Copyright (C) 2019 DisplayLink (UK) Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -65,6 +66,12 @@ meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl)
   META_KMS_IMPL_GET_CLASS (impl)->discard_pending_page_flips (impl);
 }
 
+void
+meta_kms_impl_dispatch_idle (MetaKmsImpl *impl)
+{
+  META_KMS_IMPL_GET_CLASS (impl)->dispatch_idle (impl);
+}
+
 static void
 meta_kms_impl_set_property (GObject      *object,
                             guint         prop_id,
diff --git a/src/backends/native/meta-kms-impl.h b/src/backends/native/meta-kms-impl.h
index 7816253d9..7c8dbfc66 100644
--- a/src/backends/native/meta-kms-impl.h
+++ b/src/backends/native/meta-kms-impl.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Red Hat
+ * Copyright (C) 2019 DisplayLink (UK) Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -38,6 +39,7 @@ struct _MetaKmsImplClass
   void (* handle_page_flip_callback) (MetaKmsImpl         *impl,
                                       MetaKmsPageFlipData *page_flip_data);
   void (* discard_pending_page_flips) (MetaKmsImpl *impl);
+  void (* dispatch_idle) (MetaKmsImpl *impl);
 };
 
 MetaKms * meta_kms_impl_get_kms (MetaKmsImpl *impl);
@@ -51,4 +53,6 @@ void meta_kms_impl_handle_page_flip_callback (MetaKmsImpl         *impl,
 
 void meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl);
 
+void meta_kms_impl_dispatch_idle (MetaKmsImpl *impl);
+
 #endif /* META_KMS_IMPL_H */


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