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:
parent
915bceb5a0
commit
4c317eae07
1 changed files with 38 additions and 12 deletions
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue