#include "config.h"
#include <glib/gvariant-core.h>
+#include "glib-private.h"
#include <glib/gvariant-serialiser.h>
#include <glib/gtestutils.h>
g_free (value->contents.tree.children);
}
+/* < private >
+ * g_variant_lock_in_tree_form:
+ * @value: a #GVariant
+ *
+ * Locks @value if it is in tree form.
+ *
+ * Returns: %TRUE if @value is now in tree form with the lock acquired
+ */
+static gboolean
+g_variant_lock_in_tree_form (GVariant *value)
+{
+ if (g_atomic_int_get (&value->state) & STATE_SERIALISED)
+ return FALSE;
+
+ g_variant_lock (value);
+
+ if (value->state & STATE_SERIALISED)
+ {
+ g_variant_unlock (value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* This begins the main body of the recursive serialiser.
*
* There are 3 functions here that work as a team with the serialiser to
* that size and serialises the instance into the buffer. The
* 'children' array is then released and the instance is set to
* serialised form based on the contents of the buffer.
- *
- * The current thread must hold the lock on @value.
*/
static void
g_variant_ensure_serialised (GVariant *value)
{
- g_assert (value->state & STATE_LOCKED);
-
- if (~value->state & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
{
GBytes *bytes;
gpointer data;
value->contents.serialised.data = g_bytes_get_data (bytes, NULL);
value->contents.serialised.bytes = bytes;
value->state |= STATE_SERIALISED;
+
+ g_variant_unlock (value);
+ }
+}
+
+/* Now we have the code to recursively serialise a GVariant into a
+ * GVariantVectors structure.
+ *
+ * We want to do this in cases where the GVariant contains large chunks
+ * of serialised data in order to avoid having to copy this data.
+ *
+ * This generally works the same as normal serialising (co-recursion
+ * with the serialiser) but instead of using a callback we just hard-code
+ * the callback with the name g_variant_callback_write_to_vectors().
+ *
+ * This is a private API that will be used by GDBus.
+ */
+gsize
+g_variant_callback_write_to_vectors (GVariantVectors *vectors,
+ gpointer data,
+ GVariantTypeInfo **type_info)
+{
+ GVariant *value = data;
+
+ if (g_variant_lock_in_tree_form (value))
+ {
+ g_variant_serialiser_write_to_vectors (vectors, value->type_info, value->size,
+ (gpointer *) value->contents.tree.children,
+ value->contents.tree.n_children);
+
+ g_variant_unlock (value);
}
+ else
+ g_variant_vectors_append_gbytes (vectors, value->contents.serialised.bytes,
+ value->contents.serialised.data, value->size);
+
+ if (type_info)
+ *type_info = value->type_info;
+
+ return value->size;
+}
+
+/* < private >
+ * g_variant_serialise_to_vectors:
+ * @value: a #GVariant
+ * @vectors: (out): the result
+ *
+ * Serialises @value into @vectors.
+ *
+ * The caller must free @vectors.
+ */
+void
+g_variant_to_vectors (GVariant *value,
+ GVariantVectors *vectors)
+{
+ g_variant_vectors_init (vectors);
+
+ g_variant_callback_write_to_vectors (vectors, value, NULL);
}
/* < private >
gconstpointer
g_variant_get_data (GVariant *value)
{
- g_variant_lock (value);
g_variant_ensure_serialised (value);
- g_variant_unlock (value);
return value->contents.serialised.data;
}
gsize bytes_size;
gsize size;
- g_variant_lock (value);
g_variant_ensure_serialised (value);
- g_variant_unlock (value);
bytes_data = g_bytes_get_data (value->contents.serialised.bytes, &bytes_size);
data = value->contents.serialised.data;
{
gsize n_children;
- g_variant_lock (value);
-
- if (value->state & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
+ {
+ n_children = value->contents.tree.n_children;
+ g_variant_unlock (value);
+ }
+ else
{
GVariantSerialised serialised = {
value->type_info,
n_children = g_variant_serialised_n_children (serialised);
}
- else
- n_children = value->contents.tree.n_children;
-
- g_variant_unlock (value);
return n_children;
}
g_variant_get_child_value (GVariant *value,
gsize index_)
{
+ GVariant *child;
+
g_return_val_if_fail (index_ < g_variant_n_children (value), NULL);
- if (~g_atomic_int_get (&value->state) & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
{
- g_variant_lock (value);
-
- if (~value->state & STATE_SERIALISED)
- {
- GVariant *child;
-
- child = g_variant_ref (value->contents.tree.children[index_]);
- g_variant_unlock (value);
-
- return child;
- }
+ child = g_variant_ref (value->contents.tree.children[index_]);
g_variant_unlock (value);
}
+ else
+ {
+ GVariantSerialised serialised = {
+ value->type_info,
+ (gpointer) value->contents.serialised.data,
+ value->size
+ };
+ GVariantSerialised s_child;
- {
- GVariantSerialised serialised = {
- value->type_info,
- (gpointer) value->contents.serialised.data,
- value->size
- };
- GVariantSerialised s_child;
- GVariant *child;
-
- /* get the serialiser to extract the serialised data for the child
- * from the serialised data for the container
- */
- s_child = g_variant_serialised_get_child (serialised, index_);
-
- /* create a new serialised instance out of it */
- child = g_slice_new (GVariant);
- child->type_info = s_child.type_info;
- child->state = (value->state & STATE_TRUSTED) |
- STATE_SERIALISED;
- child->size = s_child.size;
- child->ref_count = 1;
- child->contents.serialised.bytes =
- g_bytes_ref (value->contents.serialised.bytes);
- child->contents.serialised.data = s_child.data;
-
- return child;
- }
+ /* get the serialiser to extract the serialised data for the child
+ * from the serialised data for the container
+ */
+ s_child = g_variant_serialised_get_child (serialised, index_);
+
+ /* create a new serialised instance out of it */
+ child = g_slice_new (GVariant);
+ child->type_info = s_child.type_info;
+ child->state = (value->state & STATE_TRUSTED) |
+ STATE_SERIALISED;
+ child->size = s_child.size;
+ child->ref_count = 1;
+ child->contents.serialised.bytes =
+ g_bytes_ref (value->contents.serialised.bytes);
+ child->contents.serialised.data = s_child.data;
+ }
+
+ return child;
}
/**
g_variant_store (GVariant *value,
gpointer data)
{
- g_variant_lock (value);
-
- if (value->state & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
+ {
+ g_variant_serialise (value, data);
+ g_variant_unlock (value);
+ }
+ else
{
if (value->contents.serialised.data != NULL)
memcpy (data, value->contents.serialised.data, value->size);
else
memset (data, 0, value->size);
}
- else
- g_variant_serialise (value, data);
-
- g_variant_unlock (value);
}
/**
gboolean
g_variant_is_normal_form (GVariant *value)
{
- if (value->state & STATE_TRUSTED)
+ if (g_atomic_int_get (&value->state) & STATE_TRUSTED)
return TRUE;
+ /* We always take the lock here because we expect to find that the
+ * value is in normal form and in that case, we need to update the
+ * state, which requires holding the lock.
+ */
g_variant_lock (value);
if (value->state & STATE_SERIALISED)