mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-22 10:12:10 +01:00
glib: add internal g_datalist_id_update_atomic() function
This commit is contained in:
parent
dcd6c000ed
commit
d101913026
101
glib/gdataset.c
101
glib/gdataset.c
@ -827,6 +827,107 @@ g_datalist_id_remove_no_notify (GData **datalist,
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_datalist_id_update_atomic:
|
||||
* @datalist: the data list
|
||||
* @key_id: they key to add.
|
||||
* @callback: callback to update (set, remove, steal, update) the
|
||||
* data.
|
||||
* @user_data: the user data for @callback.
|
||||
*
|
||||
* Will call @callback while holding the lock on @datalist. Be careful, to not
|
||||
* end up calling into another data-list function, because the lock is not reentrant
|
||||
* and deadlock will happen.
|
||||
*
|
||||
* The callback receives the current data and destroy function. If the key
|
||||
* is currently not in @datalist, they will be %NULL.
|
||||
* The callback can update those pointers, and @datalist will be updated.
|
||||
* Note that if callback modifies a received data, then it MUST steal it
|
||||
* and take ownership on it. Possibly freeing it with the provided destroy function.
|
||||
*
|
||||
* The point is to atomically update the entry, while holding a lock.
|
||||
*
|
||||
* Returns: the data that @callback returns.
|
||||
*/
|
||||
gpointer
|
||||
g_datalist_id_update_atomic (GData **datalist,
|
||||
GQuark key_id,
|
||||
GDataListUpdateAtomicFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GData *d;
|
||||
GDataElt *data;
|
||||
gpointer new_data;
|
||||
GDestroyNotify new_destroy;
|
||||
guint32 idx;
|
||||
gboolean to_unlock = TRUE;
|
||||
|
||||
d = g_datalist_lock_and_get (datalist);
|
||||
|
||||
data = datalist_find (d, key_id, &idx);
|
||||
|
||||
if (data)
|
||||
{
|
||||
new_data = data->data;
|
||||
new_destroy = data->destroy;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_data = NULL;
|
||||
new_destroy = NULL;
|
||||
}
|
||||
|
||||
callback (key_id, &new_data, &new_destroy, user_data);
|
||||
|
||||
if (data && !new_data)
|
||||
{
|
||||
/* Remove.
|
||||
*
|
||||
* The old data->data was already stolen by callback(). */
|
||||
if (idx != d->len - 1u)
|
||||
*data = d->data[d->len - 1u];
|
||||
d->len--;
|
||||
|
||||
/* We don't bother to shrink, but if all data are now gone
|
||||
* we at least free the memory
|
||||
*/
|
||||
if (d->len == 0)
|
||||
{
|
||||
/* datalist may be situated in dataset, so must not be
|
||||
* unlocked when we free it
|
||||
*/
|
||||
g_datalist_unlock_and_set (datalist, NULL);
|
||||
g_free (d);
|
||||
to_unlock = FALSE;
|
||||
}
|
||||
}
|
||||
else if (data)
|
||||
{
|
||||
/* Update.
|
||||
*
|
||||
* The old data was stolen by callback(). We only update the pointers and are done. */
|
||||
data->data = new_data;
|
||||
data->destroy = new_destroy;
|
||||
}
|
||||
else if (!data && !new_data)
|
||||
{
|
||||
/* Absent, no change. We had no data, and nothing to add. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add */
|
||||
if (datalist_append (&d, key_id, new_data, new_destroy))
|
||||
{
|
||||
g_datalist_unlock_and_set (datalist, d);
|
||||
to_unlock = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (to_unlock)
|
||||
g_datalist_unlock (datalist);
|
||||
return new_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_dataset_id_get_data:
|
||||
* @dataset_location: (not nullable): the location identifying the dataset.
|
||||
|
@ -38,6 +38,15 @@ G_BEGIN_DECLS
|
||||
#define G_DATALIST_GET_FLAGS(datalist) \
|
||||
((gsize) g_atomic_pointer_get (datalist) & G_DATALIST_FLAGS_MASK)
|
||||
|
||||
typedef gpointer (*GDataListUpdateAtomicFunc) (GQuark key_id,
|
||||
gpointer *data,
|
||||
GDestroyNotify *destroy_notify,
|
||||
gpointer user_data);
|
||||
|
||||
gpointer g_datalist_id_update_atomic (GData **datalist,
|
||||
GQuark key_id,
|
||||
GDataListUpdateAtomicFunc callback,
|
||||
gpointer user_data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "glib-private.h"
|
||||
#include "glib-init.h"
|
||||
#include "gutilsprivate.h"
|
||||
#include "gdatasetprivate.h"
|
||||
|
||||
#ifdef USE_INVALID_PARAMETER_HANDLER
|
||||
#include <crtdbg.h>
|
||||
@ -74,6 +75,8 @@ glib__private__ (void)
|
||||
g_uri_get_default_scheme_port,
|
||||
|
||||
g_set_prgname_once,
|
||||
|
||||
g_datalist_id_update_atomic,
|
||||
};
|
||||
|
||||
return &table;
|
||||
|
@ -75,6 +75,11 @@ void __lsan_ignore_object (const void *p) __attribute__ ((weak));
|
||||
*/
|
||||
#define G_CONTAINER_OF(ptr, type, field) ((type *) G_STRUCT_MEMBER_P (ptr, -G_STRUCT_OFFSET (type, field)))
|
||||
|
||||
typedef gpointer (*GDataListUpdateAtomicFunc) (GQuark key_id,
|
||||
gpointer *data,
|
||||
GDestroyNotify *destroy_notify,
|
||||
gpointer user_data);
|
||||
|
||||
/*
|
||||
* g_leak_sanitizer_is_supported:
|
||||
*
|
||||
@ -291,6 +296,11 @@ typedef struct {
|
||||
/* See gutils.c */
|
||||
gboolean (* g_set_prgname_once) (const gchar *prgname);
|
||||
|
||||
gpointer (*g_datalist_id_update_atomic) (GData **datalist,
|
||||
GQuark key_id,
|
||||
GDataListUpdateAtomicFunc callback,
|
||||
gpointer user_data);
|
||||
|
||||
/* Add other private functions here, initialize them in glib-private.c */
|
||||
} GLibPrivateVTable;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user