gdataset: add "already_locked" argument to g_datalist_id_update_atomic()

This allows the caller to take the lock on the GData first, and perform
some operations.

This is useful under the assumption, that the caller can find cases
where calling g_datalist_id_update_atomic() is unnecessary, but it's
still necessary to perform that check while holding a lock.

That will yield better performance, if we can avoid calling
g_datalist_id_update_atomic(). That matters for checking the
toggle-notify in g_object_ref()/g_object_unref().

Note that with "already_locked", g_datalist_id_update_atomic() will
still unlock the GData at the end. That is because the API of
g_datalist_id_update_atomic() requires that it might re-allocate the
buffer, and it can do a more efficient unlock in that case, instead of
leaving it to the caller. The usage and purpose of this parameter is
very special, so this asymmetry is taken because the only callers will
be fine with this behavior, and it results in potentially more efficient
unlocking.
This commit is contained in:
Thomas Haller 2024-03-06 09:18:31 +01:00
parent cb5c1cf60a
commit 6fc7abe5c0
4 changed files with 23 additions and 4 deletions

View File

@ -1051,6 +1051,11 @@ g_datalist_id_remove_no_notify (GData **datalist,
* g_datalist_id_update_atomic: * g_datalist_id_update_atomic:
* @datalist: the data list * @datalist: the data list
* @key_id: the key to add. * @key_id: the key to add.
* @already_locked: if TRUE, the caller already called g_datalist_lock(). Note
* that the function will always unlock at the end. That is because the
* function may need to reset the pointer, which is most efficiently done
* with g_datalist_unlock_and_set(). This adds an asymmetry, but the usage
* of this is very peculiar anyway.
* @callback: (scope call): callback to update (set, remove, steal, update) the * @callback: (scope call): callback to update (set, remove, steal, update) the
* data. * data.
* @user_data: the user data for @callback. * @user_data: the user data for @callback.
@ -1080,6 +1085,7 @@ g_datalist_id_remove_no_notify (GData **datalist,
gpointer gpointer
g_datalist_id_update_atomic (GData **datalist, g_datalist_id_update_atomic (GData **datalist,
GQuark key_id, GQuark key_id,
gboolean already_locked,
GDataListUpdateAtomicFunc callback, GDataListUpdateAtomicFunc callback,
gpointer user_data) gpointer user_data)
{ {
@ -1090,7 +1096,14 @@ g_datalist_id_update_atomic (GData **datalist,
GDestroyNotify new_destroy; GDestroyNotify new_destroy;
guint32 idx; guint32 idx;
d = g_datalist_lock_and_get (datalist); if (G_UNLIKELY (already_locked))
{
d = G_DATALIST_GET_POINTER (datalist);
}
else
{
d = g_datalist_lock_and_get (datalist);
}
data = datalist_find (d, key_id, &idx); data = datalist_find (d, key_id, &idx);

View File

@ -78,6 +78,7 @@ typedef gpointer (*GDataListUpdateAtomicFunc) (gpointer *data,
gpointer g_datalist_id_update_atomic (GData **datalist, gpointer g_datalist_id_update_atomic (GData **datalist,
GQuark key_id, GQuark key_id,
gboolean already_locked,
GDataListUpdateAtomicFunc callback, GDataListUpdateAtomicFunc callback,
gpointer user_data); gpointer user_data);

View File

@ -305,6 +305,7 @@ typedef struct {
gpointer (*g_datalist_id_update_atomic) (GData **datalist, gpointer (*g_datalist_id_update_atomic) (GData **datalist,
GQuark key_id, GQuark key_id,
gboolean already_locked,
GDataListUpdateAtomicFunc callback, GDataListUpdateAtomicFunc callback,
gpointer user_data); gpointer user_data);
@ -345,7 +346,10 @@ guint g_uint_hash (gconstpointer v);
#endif #endif
/* Convenience wrapper to call private g_datalist_id_update_atomic() function. */ /* Convenience wrapper to call private g_datalist_id_update_atomic() function. */
#define _g_datalist_id_update_atomic_full(datalist, key_id, already_locked, callback, user_data) \
(GLIB_PRIVATE_CALL (g_datalist_id_update_atomic) ((datalist), (key_id), (already_locked), (callback), (user_data)))
#define _g_datalist_id_update_atomic(datalist, key_id, callback, user_data) \ #define _g_datalist_id_update_atomic(datalist, key_id, callback, user_data) \
(GLIB_PRIVATE_CALL (g_datalist_id_update_atomic) ((datalist), (key_id), (callback), (user_data))) _g_datalist_id_update_atomic_full((datalist), (key_id), FALSE, (callback), (user_data))
#endif /* __GLIB_PRIVATE_H__ */ #endif /* __GLIB_PRIVATE_H__ */

View File

@ -235,10 +235,11 @@ static GQuark quark_weak_locations = 0;
static gpointer (*_local_g_datalist_id_update_atomic) (GData **datalist, static gpointer (*_local_g_datalist_id_update_atomic) (GData **datalist,
GQuark key_id, GQuark key_id,
gboolean already_locked,
GDataListUpdateAtomicFunc callback, GDataListUpdateAtomicFunc callback,
gpointer user_data) = NULL; gpointer user_data) = NULL;
#undef _g_datalist_id_update_atomic #undef _g_datalist_id_update_atomic_full
#define _g_datalist_id_update_atomic(...) ((_local_g_datalist_id_update_atomic) (__VA_ARGS__)) #define _g_datalist_id_update_atomic_full(...) ((_local_g_datalist_id_update_atomic) (__VA_ARGS__))
#if HAVE_PRIVATE #if HAVE_PRIVATE
G_ALWAYS_INLINE static inline GObjectPrivate * G_ALWAYS_INLINE static inline GObjectPrivate *