mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-22 18:22:11 +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;
|
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:
|
* g_dataset_id_get_data:
|
||||||
* @dataset_location: (not nullable): the location identifying the dataset.
|
* @dataset_location: (not nullable): the location identifying the dataset.
|
||||||
|
@ -38,6 +38,15 @@ G_BEGIN_DECLS
|
|||||||
#define G_DATALIST_GET_FLAGS(datalist) \
|
#define G_DATALIST_GET_FLAGS(datalist) \
|
||||||
((gsize) g_atomic_pointer_get (datalist) & G_DATALIST_FLAGS_MASK)
|
((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
|
G_END_DECLS
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "glib-private.h"
|
#include "glib-private.h"
|
||||||
#include "glib-init.h"
|
#include "glib-init.h"
|
||||||
#include "gutilsprivate.h"
|
#include "gutilsprivate.h"
|
||||||
|
#include "gdatasetprivate.h"
|
||||||
|
|
||||||
#ifdef USE_INVALID_PARAMETER_HANDLER
|
#ifdef USE_INVALID_PARAMETER_HANDLER
|
||||||
#include <crtdbg.h>
|
#include <crtdbg.h>
|
||||||
@ -74,6 +75,8 @@ glib__private__ (void)
|
|||||||
g_uri_get_default_scheme_port,
|
g_uri_get_default_scheme_port,
|
||||||
|
|
||||||
g_set_prgname_once,
|
g_set_prgname_once,
|
||||||
|
|
||||||
|
g_datalist_id_update_atomic,
|
||||||
};
|
};
|
||||||
|
|
||||||
return &table;
|
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)))
|
#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:
|
* g_leak_sanitizer_is_supported:
|
||||||
*
|
*
|
||||||
@ -291,6 +296,11 @@ typedef struct {
|
|||||||
/* See gutils.c */
|
/* See gutils.c */
|
||||||
gboolean (* g_set_prgname_once) (const gchar *prgname);
|
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 */
|
/* Add other private functions here, initialize them in glib-private.c */
|
||||||
} GLibPrivateVTable;
|
} GLibPrivateVTable;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user