gdataset: reorder epilogue code path in g_datalist_id_update_atomic()

The most common case is that the callback does not change the
data/destroy pointers. Reorder the "if" checks to favor those cases.

g_datalist_id_update_atomic() makes sense to track some data structure,
and atomically update it. But in that case, we usually update the values
inside the structure, and don't reset the pointer to the structure
itself. That means, if old data was present, then new_data is likley
unchanged.

With this change, we instead check whether the values are unchanged and
avoid resetting the (same) value. The idea is in the common case to
avoid writing the same value to memory to avoid false sharing or
invalidating CPU caches.
This commit is contained in:
Thomas Haller 2024-08-13 21:18:02 +02:00
parent a4a20a101b
commit a1e9284f47

View File

@ -1097,7 +1097,6 @@ g_datalist_id_update_atomic (GData **datalist,
gpointer result;
GDestroyNotify new_destroy;
guint32 idx;
gboolean to_unlock = TRUE;
d = g_datalist_lock_and_get (datalist);
@ -1116,7 +1115,13 @@ g_datalist_id_update_atomic (GData **datalist,
result = callback (&new_data, &new_destroy, user_data);
if (data && !new_data)
if (G_LIKELY (data))
{
if (G_LIKELY (data->data == new_data && data->destroy == new_destroy))
{
/* No change. */
}
else if (!new_data)
{
GData *d_to_free;
@ -1129,10 +1134,10 @@ g_datalist_id_update_atomic (GData **datalist,
g_datalist_unlock_and_set (datalist, d);
if (G_UNLIKELY (d_to_free))
g_free (d_to_free);
to_unlock = FALSE;
goto return_without_unlock;
}
}
else if (data)
else
{
/* Update. The callback may have provided new pointers to an existing
* entry.
@ -1142,9 +1147,12 @@ g_datalist_id_update_atomic (GData **datalist,
data->data = new_data;
data->destroy = new_destroy;
}
else if (!data && !new_data)
}
else
{
/* Absent. No change. The entry didn't exist and still does not. */
if (G_LIKELY (!new_data))
{
/* No change. The entry didn't exist and still does not. */
}
else
{
@ -1152,13 +1160,14 @@ g_datalist_id_update_atomic (GData **datalist,
if (datalist_append (&d, key_id, new_data, new_destroy))
{
g_datalist_unlock_and_set (datalist, d);
to_unlock = FALSE;
goto return_without_unlock;
}
}
}
if (to_unlock)
g_datalist_unlock (datalist);
return_without_unlock:
return result;
}