mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-06 01:16:17 +01:00
gclosure: Split out invalidation to a helper function
This avoids the need to ref/unref the closure while invalidating it in the `closure->ref_count == 1` path in `g_closure_unref()`. scan-build gets very confused about the ref count here, and ends up assuming it’s possible for the `g_closure_unref()` call in `g_closure_invalidate()` to finalise the closure when the latter is called from `g_closure_unref()`. There was an existing assertion in `g_closure_invalidate()` which hinted that this wasn’t possible, but scan-build doesn’t seem to be able to propagate assumptions about refcounts between function contexts. So, introduce an internal variant of `g_closure_invalidate()` which can skip modifying the closure’s refcount. It’s safe to invalidate the closure without adding a ref when doing so from `g_closure_unref()` with `closure->ref_count == 1` because at that point `g_closure_unref()` holds the only remaining ref to the closure. So none of the invalidation callbacks are allowed to unref it further. Signed-off-by: Philip Withnall <pwithnall@gnome.org> Helps: #1767
This commit is contained in:
parent
4894168631
commit
e41b4b1acb
@ -567,6 +567,17 @@ g_closure_ref (GClosure *closure)
|
||||
return closure;
|
||||
}
|
||||
|
||||
static void
|
||||
closure_invalidate_internal (GClosure *closure)
|
||||
{
|
||||
gboolean was_invalid;
|
||||
|
||||
SWAP (closure, is_invalid, TRUE, &was_invalid);
|
||||
/* invalidate only once */
|
||||
if (!was_invalid)
|
||||
closure_invoke_notifiers (closure, INOTIFY);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_closure_invalidate:
|
||||
* @closure: #GClosure to invalidate
|
||||
@ -594,12 +605,8 @@ g_closure_invalidate (GClosure *closure)
|
||||
|
||||
if (!closure->is_invalid)
|
||||
{
|
||||
gboolean was_invalid;
|
||||
g_closure_ref (closure); /* preserve floating flag */
|
||||
SWAP (closure, is_invalid, TRUE, &was_invalid);
|
||||
/* invalidate only once */
|
||||
if (!was_invalid)
|
||||
closure_invoke_notifiers (closure, INOTIFY);
|
||||
closure_invalidate_internal (closure);
|
||||
g_closure_unref (closure);
|
||||
}
|
||||
}
|
||||
@ -622,8 +629,9 @@ g_closure_unref (GClosure *closure)
|
||||
g_return_if_fail (closure != NULL);
|
||||
g_return_if_fail (closure->ref_count > 0);
|
||||
|
||||
if (closure->ref_count == 1) /* last unref, invalidate first */
|
||||
g_closure_invalidate (closure);
|
||||
/* last unref, invalidate first */
|
||||
if (closure->ref_count == 1 && !closure->is_invalid)
|
||||
closure_invalidate_internal (closure);
|
||||
|
||||
DEC_ASSIGN (closure, ref_count, &new_ref_count);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user