Blob Blame History Raw
From 99be4ed7c3be19969930ce826f48c444e5e9da41 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Oct 2023 14:48:55 -0400
Subject: [PATCH 4/4] kms/impl-device: Inhibit real-time scheduling when mode
 setting

Certain kernel drivers can take an unreasonably long time to
complete mode setting operations. That excessive CPU time is charged
to the process's rlimits which can lead to the process getting killed
if the thread is a real-time thread.

This commit inhibits real-time scheduling around mode setting
commits, since those commits are the ones currently presenting as
excessively slow.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3037
---
 src/backends/native/meta-kms-impl-device.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
index da372383d..d53552704 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
@@ -1554,141 +1554,154 @@ meta_kms_impl_device_schedule_process (MetaKmsImplDevice *impl_device,
 
   if (crtc_frame->await_flush)
     return;
 
   if (!is_using_deadline_timer (impl_device))
     goto needs_flush;
 
   if (crtc_frame->pending_page_flip)
     return;
 
   if (ensure_deadline_timer_armed (impl_device, crtc_frame, &error))
     return;
 
   if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
     g_warning ("Failed to determine deadline: %s", error->message);
 
   priv = meta_kms_impl_device_get_instance_private (impl_device);
   priv->deadline_timer_inhibited = TRUE;
 
 needs_flush:
   meta_kms_device_set_needs_flush (meta_kms_crtc_get_device (crtc), crtc);
 }
 
 static MetaKmsFeedback *
 process_mode_set_update (MetaKmsImplDevice *impl_device,
                          MetaKmsUpdate     *update,
                          MetaKmsUpdateFlag  flags)
 {
   MetaKmsImplDevicePrivate *priv =
     meta_kms_impl_device_get_instance_private (impl_device);
+  MetaKmsImpl *kms_impl = meta_kms_impl_device_get_impl (impl_device);
+  MetaThreadImpl *thread_impl = META_THREAD_IMPL (kms_impl);
+  MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
+  MetaKmsFeedback *feedback;
   CrtcFrame *crtc_frame;
   GList *l;
   GHashTableIter iter;
 
   for (l = meta_kms_update_get_mode_sets (update); l; l = l->next)
     {
       MetaKmsModeSet *mode_set = l->data;
       MetaKmsCrtc *crtc = mode_set->crtc;
 
       crtc_frame = get_crtc_frame (impl_device, crtc);
       if (!crtc_frame)
         continue;
 
       if (!crtc_frame->pending_update)
         continue;
 
       meta_kms_update_merge_from (update, crtc_frame->pending_update);
       g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
     }
 
   g_hash_table_iter_init (&iter, priv->crtc_frames);
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &crtc_frame))
     {
       crtc_frame->deadline.is_deadline_page_flip = FALSE;
       crtc_frame->await_flush = FALSE;
       crtc_frame->pending_page_flip = FALSE;
       g_clear_pointer (&crtc_frame->pending_update, meta_kms_update_free);
       disarm_crtc_frame_deadline_timer (crtc_frame);
     }
 
-  return do_process (impl_device, NULL, update, flags);
+  meta_thread_inhibit_realtime_in_impl (thread);
+  feedback = do_process (impl_device, NULL, update, flags);
+  meta_thread_uninhibit_realtime_in_impl (thread);
+
+  return feedback;
 }
 
 MetaKmsFeedback *
 meta_kms_impl_device_process_update (MetaKmsImplDevice *impl_device,
                                      MetaKmsUpdate     *update,
                                      MetaKmsUpdateFlag  flags)
 {
   g_autoptr (GError) error = NULL;
 
   if (!ensure_device_file (impl_device, &error))
     {
       MetaKmsFeedback *feedback = NULL;
 
       feedback = meta_kms_feedback_new_failed (NULL, g_steal_pointer (&error));
       queue_result_feedback (impl_device, update, feedback);
 
       meta_kms_update_free (update);
       return feedback;
     }
 
   meta_kms_update_realize (update, impl_device);
 
   if (flags & META_KMS_UPDATE_FLAG_TEST_ONLY)
     {
       return do_process (impl_device,
                          meta_kms_update_get_latch_crtc (update),
                          update, flags);
     }
   else if (flags & META_KMS_UPDATE_FLAG_MODE_SET)
     {
       return process_mode_set_update (impl_device, update, flags);
     }
   else
     {
       g_assert_not_reached ();
     }
 }
 
 void
 meta_kms_impl_device_disable (MetaKmsImplDevice *impl_device)
 {
   MetaKmsImplDevicePrivate *priv =
     meta_kms_impl_device_get_instance_private (impl_device);
+  MetaKmsImpl *kms_impl = meta_kms_impl_device_get_impl (impl_device);
+  MetaThreadImpl *thread_impl = META_THREAD_IMPL (kms_impl);
+  MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
   MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
 
   if (!priv->device_file)
     return;
 
   meta_kms_impl_device_hold_fd (impl_device);
+  meta_thread_inhibit_realtime_in_impl (thread);
   klass->disable (impl_device);
+  meta_thread_uninhibit_realtime_in_impl (thread);
   g_list_foreach (priv->crtcs,
                   (GFunc) meta_kms_crtc_disable_in_impl, NULL);
   g_list_foreach (priv->connectors,
                   (GFunc) meta_kms_connector_disable_in_impl, NULL);
   meta_kms_impl_device_unhold_fd (impl_device);
 }
 
 void
 meta_kms_impl_device_handle_page_flip_callback (MetaKmsImplDevice   *impl_device,
                                                 MetaKmsPageFlipData *page_flip_data)
 {
   MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
 
   klass->handle_page_flip_callback (impl_device, page_flip_data);
 }
 
 void
 meta_kms_impl_device_discard_pending_page_flips (MetaKmsImplDevice *impl_device)
 {
   MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device);
 
   klass->discard_pending_page_flips (impl_device);
 }
 
 void
 meta_kms_impl_device_hold_fd (MetaKmsImplDevice *impl_device)
 {
   MetaKmsImplDevicePrivate *priv =
     meta_kms_impl_device_get_instance_private (impl_device);
   MetaKms *kms = meta_kms_device_get_kms (priv->device);
-- 
2.41.0