gobject: preserve order of weak notifications in g_object_weak_unref()

g_object_weak_unref() would have done a fast-removal of the entry, which
messes up the order of the weak notifications.

During destruction of the object we emit the weak notifications. They
are emitted in the order in which they were registered (FIFO). Except,
when a g_object_weak_unref() messes up the order. Avoid that and
preserve the order.

Now, do a memmove(), which is O(n). But note that we already track weak
references in a flat array that requires a O(n) linear search. Thus,
g_object_weak_unref() was already O(n) and that didn't change. More
importantly, users are well advised to limit themselves to a reasonably
small number of weak notifications. And for small n, the linear search
and the memmove() is an efficient solution.
This commit is contained in:
Thomas Haller
2025-04-09 07:52:34 +02:00
committed by Michael Catanzaro
parent 7743c7aaa2
commit d2e08b7dfe
2 changed files with 11 additions and 19 deletions

View File

@@ -3827,7 +3827,11 @@ g_object_weak_unref_cb (gpointer *data,
*data = NULL;
}
else if (i != wstack->n_weak_refs)
wstack->weak_refs[i] = wstack->weak_refs[wstack->n_weak_refs];
{
memmove (&wstack->weak_refs[i],
&wstack->weak_refs[i + 1],
sizeof (wstack->weak_refs[i]) * (wstack->n_weak_refs - i));
}
found_one = TRUE;
break;

View File

@@ -285,7 +285,6 @@ test_references (void)
/*****************************************************************************/
static guint weak_ref4_notified;
static guint weak_ref4_has_stable_order;
static void
weak_ref4 (gpointer data,
@@ -294,12 +293,9 @@ weak_ref4 (gpointer data,
static gint last = -1;
gint idx;
if (weak_ref4_has_stable_order)
{
idx = (gint) GPOINTER_TO_UINT (data);
g_assert_cmpint (last, <, idx);
last = idx;
}
idx = (gint) GPOINTER_TO_UINT (data);
g_assert_cmpint (last, <, idx);
last = idx;
weak_ref4_notified++;
}
@@ -331,17 +327,9 @@ test_references_many (void)
indexes[i] = indexes[j];
indexes[j] = tmp;
}
if (g_random_boolean ())
{
m = 0;
}
else
{
m = g_random_int () % (n + 1u);
for (i = 0; i < m; i++)
g_object_weak_unref (object, weak_ref4, GUINT_TO_POINTER (indexes[i]));
}
weak_ref4_has_stable_order = (m == 0);
m = g_random_int () % (n + 1u);
for (i = 0; i < m; i++)
g_object_weak_unref (object, weak_ref4, GUINT_TO_POINTER (indexes[i]));
g_object_unref (object);
g_assert_cmpint (weak_ref4_notified, ==, n - m);
g_free (indexes);