kms: Inhibit real time scheduling until initial mode set
We're already inhibiting real time scheduling when reading new KMS state
after hot plugs, as well as when during mode sets, due to the kernel not
being able to reliably handle these within the 250 ms limit. However, we
didn't do this during initial probing, which meant that occasionally
we'd run into these kind of issues during startup.
Handle this by always inhibiting real time scheduling up front, and
don't uninhibit until all initially discovered device have finished
processing their initial mode set.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3628
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3960>
(cherry picked from commit d2be0b6950
)
This commit is contained in:
parent
e8d7640316
commit
abd2c95864
9 changed files with 106 additions and 9 deletions
|
@ -609,6 +609,7 @@ init_gpus (MetaBackendNative *native,
|
|||
{
|
||||
MetaBackend *backend = META_BACKEND (native);
|
||||
MetaUdev *udev = meta_backend_native_get_udev (native);
|
||||
MetaKms *kms = meta_backend_native_get_kms (native);
|
||||
g_autoptr (GError) local_error = NULL;
|
||||
MetaUdevDeviceType device_type = 0;
|
||||
GList *devices;
|
||||
|
@ -669,6 +670,8 @@ init_gpus (MetaBackendNative *native,
|
|||
|
||||
g_list_free_full (devices, g_object_unref);
|
||||
|
||||
meta_kms_notify_probed (kms);
|
||||
|
||||
if (!meta_backend_is_headless (backend) &&
|
||||
g_list_length (meta_backend_get_gpus (backend)) == 0)
|
||||
{
|
||||
|
|
|
@ -108,6 +108,8 @@ typedef struct _MetaKmsImplDevicePrivate
|
|||
|
||||
GHashTable *crtc_frames;
|
||||
|
||||
gboolean realtime_inhibited_pending_mode_set;
|
||||
|
||||
MetaDeadlineTimerState deadline_timer_state;
|
||||
|
||||
gboolean sync_file_retrieved;
|
||||
|
@ -1741,6 +1743,12 @@ process_mode_set_update (MetaKmsImplDevice *impl_device,
|
|||
feedback = do_process (impl_device, NULL, update, flags);
|
||||
meta_thread_uninhibit_realtime_in_impl (thread);
|
||||
|
||||
if (priv->realtime_inhibited_pending_mode_set)
|
||||
{
|
||||
priv->realtime_inhibited_pending_mode_set = FALSE;
|
||||
meta_thread_uninhibit_realtime_in_impl (thread);
|
||||
}
|
||||
|
||||
return feedback;
|
||||
}
|
||||
|
||||
|
@ -1931,6 +1939,15 @@ meta_kms_impl_device_finalize (GObject *object)
|
|||
MetaKmsImplDevicePrivate *priv =
|
||||
meta_kms_impl_device_get_instance_private (impl_device);
|
||||
|
||||
if (priv->realtime_inhibited_pending_mode_set)
|
||||
{
|
||||
MetaThreadImpl *thread_impl = META_THREAD_IMPL (priv->impl);
|
||||
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
|
||||
|
||||
priv->realtime_inhibited_pending_mode_set = FALSE;
|
||||
meta_thread_uninhibit_realtime_in_impl (thread);
|
||||
}
|
||||
|
||||
meta_kms_impl_remove_impl_device (priv->impl, impl_device);
|
||||
|
||||
g_list_free_full (priv->planes, g_object_unref);
|
||||
|
@ -1980,6 +1997,16 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device,
|
|||
|
||||
update_connectors (impl_device, drm_resources, 0);
|
||||
|
||||
if (!priv->crtcs)
|
||||
{
|
||||
MetaThreadImpl *thread_impl = META_THREAD_IMPL (priv->impl);
|
||||
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
|
||||
|
||||
g_warn_if_fail (priv->realtime_inhibited_pending_mode_set);
|
||||
meta_thread_uninhibit_realtime_in_impl (thread);
|
||||
priv->realtime_inhibited_pending_mode_set = FALSE;
|
||||
}
|
||||
|
||||
drmModeFreeResources (drm_resources);
|
||||
|
||||
return TRUE;
|
||||
|
@ -2057,6 +2084,8 @@ meta_kms_impl_device_initable_init (GInitable *initable,
|
|||
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable);
|
||||
MetaKmsImplDevicePrivate *priv =
|
||||
meta_kms_impl_device_get_instance_private (impl_device);
|
||||
MetaThreadImpl *thread_impl = META_THREAD_IMPL (priv->impl);
|
||||
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
|
||||
int fd;
|
||||
|
||||
if (!ensure_device_file (impl_device, error))
|
||||
|
@ -2082,6 +2111,9 @@ meta_kms_impl_device_initable_init (GInitable *initable,
|
|||
|
||||
priv->sync_file = -1;
|
||||
|
||||
meta_thread_inhibit_realtime_in_impl (thread);
|
||||
priv->realtime_inhibited_pending_mode_set = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -172,12 +172,32 @@ meta_kms_impl_finalize (GObject *object)
|
|||
G_OBJECT_CLASS (meta_kms_impl_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_impl_setup (MetaThreadImpl *thread_impl)
|
||||
{
|
||||
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
|
||||
|
||||
meta_thread_inhibit_realtime_in_impl (thread);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_impl_notify_probed (MetaKmsImpl *impl)
|
||||
{
|
||||
MetaThreadImpl *thread_impl = META_THREAD_IMPL (impl);
|
||||
MetaThread *thread = meta_thread_impl_get_thread (thread_impl);
|
||||
|
||||
meta_thread_uninhibit_realtime_in_impl (thread);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_impl_class_init (MetaKmsImplClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MetaThreadImplClass *thread_impl_class = META_THREAD_IMPL_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_kms_impl_finalize;
|
||||
|
||||
thread_impl_class->setup = meta_kms_impl_setup;
|
||||
}
|
||||
|
||||
MetaKmsUpdateFilter *
|
||||
|
|
|
@ -53,6 +53,8 @@ void meta_kms_impl_notify_modes_set (MetaKmsImpl *impl);
|
|||
|
||||
MetaKmsImpl * meta_kms_impl_new (MetaKms *kms);
|
||||
|
||||
void meta_kms_impl_notify_probed (MetaKmsImpl *impl);
|
||||
|
||||
MetaKmsUpdateFilter * meta_kms_impl_add_update_filter (MetaKmsImpl *impl,
|
||||
MetaKmsUpdateFilterFunc func,
|
||||
gpointer user_data);
|
||||
|
|
|
@ -413,6 +413,23 @@ meta_kms_new (MetaBackend *backend,
|
|||
return kms;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
notify_probed_in_impl (MetaThreadImpl *thread_impl,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
meta_kms_impl_notify_probed (META_KMS_IMPL (thread_impl));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_notify_probed (MetaKms *kms)
|
||||
{
|
||||
meta_thread_post_impl_task (META_THREAD (kms),
|
||||
notify_probed_in_impl,
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_finalize (GObject *object)
|
||||
{
|
||||
|
|
|
@ -64,6 +64,8 @@ MetaKms * meta_kms_new (MetaBackend *backend,
|
|||
MetaKmsFlags flags,
|
||||
GError **error);
|
||||
|
||||
void meta_kms_notify_probed (MetaKms *kms);
|
||||
|
||||
META_EXPORT_TEST
|
||||
void meta_kms_inhibit_kernel_thread (MetaKms *kms);
|
||||
|
||||
|
|
|
@ -568,6 +568,15 @@ meta_thread_impl_dispatch (MetaThreadImpl *thread_impl)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
meta_thread_impl_setup (MetaThreadImpl *thread_impl)
|
||||
{
|
||||
MetaThreadImplClass *klass = META_THREAD_IMPL_GET_CLASS (thread_impl);
|
||||
|
||||
if (klass->setup)
|
||||
klass->setup (thread_impl);
|
||||
}
|
||||
|
||||
void
|
||||
meta_thread_impl_run (MetaThreadImpl *thread_impl,
|
||||
MetaThreadImplRunFlags flags)
|
||||
|
|
|
@ -38,6 +38,8 @@ G_DECLARE_DERIVABLE_TYPE (MetaThreadImpl, meta_thread_impl,
|
|||
struct _MetaThreadImplClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* setup) (MetaThreadImpl *thread_impl);
|
||||
};
|
||||
|
||||
typedef enum _MetaThreadTaskFeedbackType
|
||||
|
@ -70,6 +72,8 @@ void meta_thread_impl_queue_task (MetaThreadImpl *thread_impl,
|
|||
|
||||
void meta_thread_impl_terminate (MetaThreadImpl *thread_impl);
|
||||
|
||||
void meta_thread_impl_setup (MetaThreadImpl *thread_impl);
|
||||
|
||||
void meta_thread_impl_run (MetaThreadImpl *thread_impl,
|
||||
MetaThreadImplRunFlags flags);
|
||||
|
||||
|
|
|
@ -333,22 +333,28 @@ request_normal_scheduling (MetaThread *thread,
|
|||
}
|
||||
|
||||
static gboolean
|
||||
should_use_realtime_scheduling_in_impl (MetaThread *thread)
|
||||
can_use_realtime_scheduling_in_impl (MetaThread *thread)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
gboolean should_use_realtime_scheduling = FALSE;
|
||||
|
||||
switch (priv->thread_type)
|
||||
{
|
||||
case META_THREAD_TYPE_USER:
|
||||
break;
|
||||
return FALSE;
|
||||
case META_THREAD_TYPE_KERNEL:
|
||||
if (priv->wants_realtime && priv->kernel.realtime_inhibit_count == 0)
|
||||
should_use_realtime_scheduling = TRUE;
|
||||
break;
|
||||
return priv->wants_realtime;
|
||||
}
|
||||
|
||||
return should_use_realtime_scheduling;
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_use_realtime_scheduling_in_impl (MetaThread *thread)
|
||||
{
|
||||
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
|
||||
|
||||
return (can_use_realtime_scheduling_in_impl (thread) &&
|
||||
priv->kernel.realtime_inhibit_count == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -417,11 +423,13 @@ thread_impl_func (gpointer user_data)
|
|||
priv->kernel.realtime_inhibit_count = 0;
|
||||
priv->kernel.is_realtime = FALSE;
|
||||
|
||||
meta_thread_impl_setup (impl);
|
||||
|
||||
sync_realtime_scheduling_in_impl (thread);
|
||||
|
||||
if (priv->kernel.is_realtime)
|
||||
if (can_use_realtime_scheduling_in_impl (thread))
|
||||
{
|
||||
g_message ("Made thread '%s' realtime scheduled", priv->name);
|
||||
g_message ("Thread '%s' will be using real time scheduling", priv->name);
|
||||
run_flags |= META_THREAD_IMPL_RUN_FLAG_REALTIME;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue