1
0
Fork 0

thread: Make callback handling thread safe

This is in preparation for introducing kernel threads, where proper
synchronization becomes necessary.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2777>
This commit is contained in:
Jonas Ådahl 2021-06-11 10:27:36 +02:00
parent 915bceb5a0
commit 4c317eae07

View file

@ -54,6 +54,7 @@ typedef struct _MetaThreadPrivate
MetaThreadImpl *impl; MetaThreadImpl *impl;
gboolean waiting_for_impl_task; gboolean waiting_for_impl_task;
GMutex callbacks_mutex;
GList *pending_callbacks; GList *pending_callbacks;
guint callbacks_source_id; guint callbacks_source_id;
} MetaThreadPrivate; } MetaThreadPrivate;
@ -166,11 +167,12 @@ meta_thread_finalize (GObject *object)
while (meta_thread_impl_dispatch (priv->impl) > 0); while (meta_thread_impl_dispatch (priv->impl) > 0);
meta_thread_flush_callbacks (thread); meta_thread_flush_callbacks (thread);
g_clear_handle_id (&priv->callbacks_source_id, g_source_remove);
g_clear_object (&priv->impl); g_clear_object (&priv->impl);
g_clear_pointer (&priv->name, g_free); g_clear_pointer (&priv->name, g_free);
g_mutex_clear (&priv->callbacks_mutex);
G_OBJECT_CLASS (meta_thread_parent_class)->finalize (object); G_OBJECT_CLASS (meta_thread_parent_class)->finalize (object);
} }
@ -207,6 +209,9 @@ meta_thread_class_init (MetaThreadClass *klass)
static void static void
meta_thread_init (MetaThread *thread) meta_thread_init (MetaThread *thread)
{ {
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
g_mutex_init (&priv->callbacks_mutex);
} }
void void
@ -221,16 +226,14 @@ meta_thread_class_register_impl_type (MetaThreadClass *thread_class,
class_priv->impl_type = impl_type; class_priv->impl_type = impl_type;
} }
int static int
meta_thread_flush_callbacks (MetaThread *thread) dispatch_callbacks (MetaThread *thread,
GList *pending_callbacks)
{ {
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
GList *l;
int callback_count = 0; int callback_count = 0;
GList *l;
meta_assert_not_in_thread_impl (thread); for (l = pending_callbacks; l; l = l->next)
for (l = priv->pending_callbacks; l; l = l->next)
{ {
MetaThreadCallbackData *callback_data = l->data; MetaThreadCallbackData *callback_data = l->data;
@ -239,21 +242,41 @@ meta_thread_flush_callbacks (MetaThread *thread)
callback_count++; callback_count++;
} }
g_list_free (priv->pending_callbacks);
priv->pending_callbacks = NULL;
return callback_count; return callback_count;
} }
int
meta_thread_flush_callbacks (MetaThread *thread)
{
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
g_autoptr (GList) pending_callbacks = NULL;
meta_assert_not_in_thread_impl (thread);
g_mutex_lock (&priv->callbacks_mutex);
pending_callbacks = g_steal_pointer (&priv->pending_callbacks);
g_clear_handle_id (&priv->callbacks_source_id, g_source_remove);
g_mutex_unlock (&priv->callbacks_mutex);
return dispatch_callbacks (thread, pending_callbacks);
}
static gboolean static gboolean
callback_idle (gpointer user_data) callback_idle (gpointer user_data)
{ {
MetaThread *thread = user_data; MetaThread *thread = user_data;
MetaThreadPrivate *priv = meta_thread_get_instance_private (thread); MetaThreadPrivate *priv = meta_thread_get_instance_private (thread);
g_autoptr (GList) pending_callbacks = NULL;
meta_thread_flush_callbacks (thread); meta_assert_not_in_thread_impl (thread);
g_mutex_lock (&priv->callbacks_mutex);
pending_callbacks = g_steal_pointer (&priv->pending_callbacks);
priv->callbacks_source_id = 0; priv->callbacks_source_id = 0;
g_mutex_unlock (&priv->callbacks_mutex);
dispatch_callbacks (thread, pending_callbacks);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@ -272,6 +295,8 @@ meta_thread_queue_callback (MetaThread *thread,
.user_data = user_data, .user_data = user_data,
.user_data_destroy = user_data_destroy, .user_data_destroy = user_data_destroy,
}; };
g_mutex_lock (&priv->callbacks_mutex);
priv->pending_callbacks = g_list_append (priv->pending_callbacks, priv->pending_callbacks = g_list_append (priv->pending_callbacks,
callback_data); callback_data);
if (!priv->callbacks_source_id) if (!priv->callbacks_source_id)
@ -284,6 +309,7 @@ meta_thread_queue_callback (MetaThread *thread,
priv->main_context); priv->main_context);
g_source_unref (idle_source); g_source_unref (idle_source);
} }
g_mutex_unlock (&priv->callbacks_mutex);
} }
typedef struct _MetaSyncTaskData typedef struct _MetaSyncTaskData