[mutter] util: fix a reentrancy problem with meta_later
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] util: fix a reentrancy problem with meta_later
- Date: Wed, 13 Jul 2011 14:40:41 +0000 (UTC)
commit cd7a9680932868d1d2ef5447c77712cef9a443dd
Author: Dan Winship <danw gnome org>
Date: Tue Mar 29 15:18:57 2011 -0400
util: fix a reentrancy problem with meta_later
Calling meta_later_add() or meta_later_remove() from within a
META_LATER_BEFORE_REDRAW callback ended up being a no-op, because of
how run_repaint_laters() was fiddling with the laters list. (This
resulted in a crash in window.c:idle_calc_repaint(), which assumed it
would only be called when a certain queue was non-empty, but was
getting called anyway because of a failed meta_later_remove() call.)
Fix this by having run_repaint_laters() work on a copy of the laters
list instead, and add refcounting to MetaLater so that removing a
later that run_repaint_laters() hasn't gotten to yet won't cause
problems.
https://bugzilla.gnome.org/show_bug.cgi?id=642957
src/core/util.c | 63 +++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 43 insertions(+), 20 deletions(-)
---
diff --git a/src/core/util.c b/src/core/util.c
index aea1210..2ce5f79 100644
--- a/src/core/util.c
+++ b/src/core/util.c
@@ -708,6 +708,7 @@ static guint last_later_id = 0;
typedef struct
{
guint id;
+ guint ref_count;
MetaLaterType when;
GSourceFunc func;
gpointer data;
@@ -724,13 +725,29 @@ static guint later_repaint_func = 0;
static void ensure_later_repaint_func (void);
static void
+unref_later (MetaLater *later)
+{
+ if (--later->ref_count == 0)
+ {
+ if (later->notify)
+ {
+ later->notify (later->data);
+ later->notify = NULL;
+ }
+ g_slice_free (MetaLater, later);
+ }
+}
+
+static void
destroy_later (MetaLater *later)
{
if (later->source)
- g_source_remove (later->source);
- if (later->notify)
- later->notify (later->data);
- g_slice_free (MetaLater, later);
+ {
+ g_source_remove (later->source);
+ later->source = 0;
+ }
+ later->func = NULL;
+ unref_later (later);
}
/* Used to sort the list of laters with the highest priority
@@ -746,34 +763,41 @@ compare_laters (gconstpointer a,
static gboolean
run_repaint_laters (gpointer data)
{
- GSList *old_laters = laters;
+ GSList *laters_copy;
GSList *l;
gboolean keep_timeline_running = FALSE;
- laters = NULL;
- for (l = old_laters; l; l = l->next)
+ laters_copy = NULL;
+ for (l = laters; l; l = l->next)
{
MetaLater *later = l->data;
if (later->source == 0 ||
(later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
{
- if (later->func (later->data))
- {
- if (later->source == 0)
- keep_timeline_running = TRUE;
- laters = g_slist_insert_sorted (laters, later, compare_laters);
- }
- else
- destroy_later (later);
+ later->ref_count++;
+ laters_copy = g_slist_prepend (laters_copy, later);
+ }
+ }
+ laters_copy = g_slist_reverse (laters_copy);
+
+ for (l = laters_copy; l; l = l->next)
+ {
+ MetaLater *later = l->data;
+
+ if (later->func && later->func (later->data))
+ {
+ if (later->source == 0)
+ keep_timeline_running = TRUE;
}
else
- laters = g_slist_insert_sorted (laters, later, compare_laters);
+ meta_later_remove (later->id);
+ unref_later (later);
}
if (!keep_timeline_running)
clutter_timeline_stop (later_timeline);
- g_slist_free (old_laters);
+ g_slist_free (laters_copy);
/* Just keep the repaint func around - it's cheap if the list is empty */
return TRUE;
@@ -800,9 +824,7 @@ call_idle_later (gpointer data)
if (!later->func (later->data))
{
- laters = g_slist_remove (laters, later);
- later->source = 0;
- destroy_later (later);
+ meta_later_remove (later->id);
return FALSE;
}
else
@@ -838,6 +860,7 @@ meta_later_add (MetaLaterType when,
MetaLater *later = g_slice_new0 (MetaLater);
later->id = ++last_later_id;
+ later->ref_count = 1;
later->when = when;
later->func = func;
later->data = data;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]