1
0
Fork 0

Lock the main context when modifying the repaint functions list

The repaint functions list can (and should) be manipulated from
different threads, but it currently doesn't prevent multiple threads
from accessing it concurrently. We should have a simple lock and take it
when adding and removing elements from the list; the invocation is still
performed under the Big Clutter Lock™, so it doesn't require special
handling.
This commit is contained in:
Emmanuele Bassi 2011-09-01 17:12:46 +01:00
parent 2557370445
commit 63a05fca9d
2 changed files with 66 additions and 19 deletions

View file

@ -116,6 +116,7 @@
/* main context */
static ClutterMainContext *ClutterCntx = NULL;
G_LOCK_DEFINE_STATIC (ClutterCntx);
/* main lock and locking/unlocking functions */
static GMutex *clutter_threads_mutex = NULL;
@ -1068,6 +1069,18 @@ clutter_get_debug_enabled (void)
#endif
}
void
_clutter_context_lock (void)
{
G_LOCK (ClutterCntx);
}
void
_clutter_context_unlock (void)
{
G_UNLOCK (ClutterCntx);
}
gboolean
_clutter_context_is_initialized (void)
{
@ -1077,8 +1090,8 @@ _clutter_context_is_initialized (void)
return ClutterCntx->is_initialized;
}
ClutterMainContext *
_clutter_context_get_default (void)
static inline ClutterMainContext *
clutter_context_get_default_unlocked (void)
{
if (G_UNLIKELY (ClutterCntx == NULL))
{
@ -1096,11 +1109,27 @@ _clutter_context_get_default (void)
ctx->timer = g_timer_new ();
g_timer_start (ctx->timer);
#endif
ctx->last_repaint_id = 1;
}
return ClutterCntx;
}
ClutterMainContext *
_clutter_context_get_default (void)
{
ClutterMainContext *retval;
_clutter_context_lock ();
retval = clutter_context_get_default_unlocked ();
_clutter_context_unlock ();
return retval;
}
/**
* clutter_get_timestamp:
*
@ -1116,11 +1145,15 @@ clutter_get_timestamp (void)
ClutterMainContext *ctx;
gdouble seconds;
ctx = _clutter_context_get_default ();
_clutter_context_lock ();
ctx = clutter_context_get_default_unlocked ();
/* FIXME: may need a custom timer for embedded setups */
seconds = g_timer_elapsed (ctx->timer, NULL);
_clutter_context_unlock ();
return (gulong)(seconds / 1.0e-6);
#else
return 0;
@ -2817,7 +2850,9 @@ clutter_threads_remove_repaint_func (guint handle_id)
g_return_if_fail (handle_id > 0);
context = _clutter_context_get_default ();
_clutter_context_lock ();
context = clutter_context_get_default_unlocked ();
l = context->repaint_funcs;
while (l != NULL)
{
@ -2835,11 +2870,13 @@ clutter_threads_remove_repaint_func (guint handle_id)
g_slice_free (ClutterRepaintFunction, repaint_func);
return;
break;
}
l = l->next;
}
_clutter_context_unlock ();
}
/**
@ -2875,19 +2912,18 @@ clutter_threads_add_repaint_func (GSourceFunc func,
gpointer data,
GDestroyNotify notify)
{
static guint repaint_id = 1;
ClutterMainContext *context;
ClutterRepaintFunction *repaint_func;
g_return_val_if_fail (func != NULL, 0);
context = _clutter_context_get_default ();
_clutter_context_lock ();
/* XXX lock the context */
context = clutter_context_get_default_unlocked ();
repaint_func = g_slice_new (ClutterRepaintFunction);
repaint_func->id = repaint_id++;
repaint_func->id = context->last_repaint_id++;
repaint_func->func = func;
repaint_func->data = data;
repaint_func->notify = notify;
@ -2895,7 +2931,7 @@ clutter_threads_add_repaint_func (GSourceFunc func,
context->repaint_funcs = g_list_prepend (context->repaint_funcs,
repaint_func);
/* XXX unlock the context */
_clutter_context_unlock ();
return repaint_func->id;
}
@ -2914,23 +2950,26 @@ _clutter_run_repaint_functions (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterRepaintFunction *repaint_func;
GList *reinvoke_list, *l;
GList *invoke_list, *reinvoke_list, *l;
if (context->repaint_funcs == NULL)
return;
/* steal the list */
invoke_list = context->repaint_funcs;
context->repaint_funcs = NULL;
reinvoke_list = NULL;
/* consume the whole list while we execute the functions */
while (context->repaint_funcs)
while (invoke_list != NULL)
{
gboolean res = FALSE;
repaint_func = context->repaint_funcs->data;
repaint_func = invoke_list->data;
l = context->repaint_funcs;
context->repaint_funcs =
g_list_remove_link (context->repaint_funcs, context->repaint_funcs);
l = invoke_list;
invoke_list = g_list_remove_link (invoke_list, invoke_list);
g_list_free (l);
@ -2940,15 +2979,20 @@ _clutter_run_repaint_functions (void)
reinvoke_list = g_list_prepend (reinvoke_list, repaint_func);
else
{
if (repaint_func->notify)
if (repaint_func->notify != NULL)
repaint_func->notify (repaint_func->data);
g_slice_free (ClutterRepaintFunction, repaint_func);
}
}
if (reinvoke_list)
context->repaint_funcs = reinvoke_list;
if (context->repaint_funcs != NULL)
{
context->repaint_funcs = g_list_concat (context->repaint_funcs,
g_list_reverse (reinvoke_list));
}
else
context->repaint_funcs = g_list_reverse (reinvoke_list);
}
/**

View file

@ -163,6 +163,7 @@ struct _ClutterMainContext
* clutter_threads_add_repaint_func()
*/
GList *repaint_funcs;
guint last_repaint_id;
/* main settings singleton */
ClutterSettings *settings;
@ -186,6 +187,8 @@ gboolean _clutter_threads_dispatch (gpointer data);
void _clutter_threads_dispatch_free (gpointer data);
ClutterMainContext * _clutter_context_get_default (void);
void _clutter_context_lock (void);
void _clutter_context_unlock (void);
gboolean _clutter_context_is_initialized (void);
PangoContext * _clutter_context_create_pango_context (void);
PangoContext * _clutter_context_get_pango_context (void);