GVariant: refactor locking a bit more
[platform/upstream/glib.git] / glib / gvariant-core.c
index e3597e4..4ab4238 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "config.h"
+
 #include <glib/gvariant-core.h>
 
 #include <glib/gvariant-serialiser.h>
 #include <glib/gtestutils.h>
 #include <glib/gbitlock.h>
 #include <glib/gatomic.h>
-#include <glib/gbuffer.h>
+#include <glib/gbytes.h>
 #include <glib/gslice.h>
 #include <glib/gmem.h>
 #include <string.h>
 
-#include "galias.h"
 
 /*
  * This file includes the structure definition for GVariant and a small
@@ -62,7 +61,7 @@ struct _GVariant
   {
     struct
     {
-      GBuffer *buffer;
+      GBytes *bytes;
       gconstpointer data;
     } serialised;
 
@@ -107,21 +106,11 @@ struct _GVariant
  *            The type_info field never changes during the life of the
  *            instance, so it can be accessed without a lock.
  *
- * size: this is the size of the serialised form for the instance, if it
- *       is known.  If the instance is in serialised form then it is, by
- *       definition, known.  If the instance is in tree form then it may
- *       be unknown (in which case it is -1).  It is possible for the
- *       size to be known when in tree form if, for example, the user
- *       has called g_variant_get_size() without calling
- *       g_variant_get_data().  Additionally, even when the user calls
- *       g_variant_get_data() the size of the data must first be
- *       determined so that a large enough buffer can be allocated for
- *       the data.
- *
- *       Once the size is known, it can never become unknown again.
- *       g_variant_ensure_size() is used to ensure that the size is in
- *       the known state -- it calculates the size if needed.  After
- *       that, the size field can be accessed without a lock.
+ * size: this is the size of the serialised form for the instance.  It
+ *       is known for serialised instances and also tree-form instances
+ *       (for which it is calculated at construction time, from the
+ *       known sizes of the children used).  After construction, it
+ *       never changes and therefore can be accessed without a lock.
  *
  * contents: a union containing either the information associated with
  *           holding a value in serialised form or holding a value in
@@ -134,16 +123,16 @@ struct _GVariant
  *                never be changed.  It is therefore valid to access
  *                them without holding a lock.
  *
- *     .buffer: the #GBuffer that contains the memory pointed to by
+ *     .bytes:  the #GBytes that contains the memory pointed to by
  *              .data, or %NULL if .data is %NULL.  In the event that
  *              the instance was deserialised from another instance,
- *              then the buffer will be shared by both of them.  When
+ *              then the bytes will be shared by both of them.  When
  *              the instance is freed, this reference must be released
- *              with g_buffer_unref().
+ *              with g_bytes_unref().
  *
  *     .data: the serialised data (of size 'size') of the instance.
  *            This pointer should not be freed or modified in any way.
- *            #GBuffer is responsible for memory management.
+ *            #GBytes is responsible for memory management.
  *
  *            This pointer may be %NULL in two cases:
  *
@@ -260,6 +249,31 @@ g_variant_release_children (GVariant *value)
   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
@@ -277,31 +291,19 @@ g_variant_release_children (GVariant *value)
  * instances are always in serialised form.  For these instances,
  * storing their serialised form merely involves a memcpy().
  *
- * Serialisation is a two-step process.  First, the size of the
- * serialised data must be calculated so that an appropriately-sized
- * buffer can be allocated.  Second, the data is written into the
- * buffer.
- *
- * Determining the size:
- *   The process of determining the size is triggered by a call to
- *   g_variant_ensure_size() on a container.  This invokes the
- *   serialiser code to determine the size.  The serialiser is passed
- *   g_variant_fill_gvs() as a callback.
+ * Converting to serialised form:
  *
- *   g_variant_fill_gvs() is called by the serialiser on each child of
- *   the container which, in turn, calls g_variant_ensure_size() on
- *   itself and fills in the result of its own size calculation.
+ *   The first step in the process of converting a GVariant to
+ *   serialised form is to allocate a buffer.  The size of the buffer is
+ *   always known because we computed at construction time of the
+ *   GVariant.
  *
- *   The serialiser uses the size information from the children to
- *   calculate the size needed for the entire container.
- *
- * Writing the data:
  *   After the buffer has been allocated, g_variant_serialise() is
  *   called on the container.  This invokes the serialiser code to write
- *   the bytes to the container.  The serialiser is, again, passed
+ *   the bytes to the container.  The serialiser is passed
  *   g_variant_fill_gvs() as a callback.
  *
- *   This time, when g_variant_fill_gvs() is called for each child, the
+ *   At the time that g_variant_fill_gvs() is called for each child, the
  *   child is given a pointer to a sub-region of the allocated buffer
  *   where it should write its data.  This is done by calling
  *   g_variant_store().  In the event that the instance is in serialised
@@ -315,34 +317,6 @@ g_variant_release_children (GVariant *value)
 static void g_variant_fill_gvs (GVariantSerialised *, gpointer);
 
 /* < private >
- * g_variant_ensure_size:
- * @value: a #GVariant
- *
- * Ensures that the ->size field of @value is filled in properly.  This
- * must be done as a precursor to any serialisation of the value in
- * order to know how large of a buffer is needed to store the data.
- *
- * The current thread must hold the lock on @value.
- */
-static void
-g_variant_ensure_size (GVariant *value)
-{
-  g_assert (value->state & STATE_LOCKED);
-
-  if (value->size == (gssize) -1)
-    {
-      gpointer *children;
-      gsize n_children;
-
-      children = (gpointer *) value->contents.tree.children;
-      n_children = value->contents.tree.n_children;
-      value->size = g_variant_serialiser_needed_size (value->type_info,
-                                                      g_variant_fill_gvs,
-                                                      children, n_children);
-    }
-}
-
-/* < private >
  * g_variant_serialise:
  * @value: a #GVariant
  * @data: an appropriately-sized buffer
@@ -387,9 +361,12 @@ g_variant_serialise (GVariant *value,
  *
  *  - reporting its type
  *
- *  - reporting its serialised size (requires knowing the size first)
+ *  - reporting its serialised size
  *
  *  - possibly storing its serialised form into the provided buffer
+ *
+ * This callback is also used during g_variant_new_from_children() in
+ * order to discover the size and type of each child.
  */
 static void
 g_variant_fill_gvs (GVariantSerialised *serialised,
@@ -397,10 +374,6 @@ g_variant_fill_gvs (GVariantSerialised *serialised,
 {
   GVariant *value = data;
 
-  g_variant_lock (value);
-  g_variant_ensure_size (value);
-  g_variant_unlock (value);
-
   if (serialised->type_info == NULL)
     serialised->type_info = value->type_info;
   g_assert (serialised->type_info == value->type_info);
@@ -424,34 +397,30 @@ g_variant_fill_gvs (GVariantSerialised *serialised,
  *
  * Ensures that @value is in serialised form.
  *
- * If @value is in tree form then this function ensures that the
- * serialised size is known and then allocates a buffer of 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.
+ * If @value is in tree form then this function allocates a buffer of
+ * 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.
  */
 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))
     {
-      GBuffer *buffer;
+      GBytes *bytes;
       gpointer data;
 
-      g_variant_ensure_size (value);
       data = g_malloc (value->size);
       g_variant_serialise (value, data);
 
       g_variant_release_children (value);
 
-      buffer = g_buffer_new_take_data (data, value->size);
-      value->contents.serialised.data = buffer->data;
-      value->contents.serialised.buffer = buffer;
+      bytes = g_bytes_new_take (data, value->size);
+      value->contents.serialised.data = g_bytes_get_data (bytes, NULL);
+      value->contents.serialised.bytes = bytes;
       value->state |= STATE_SERIALISED;
+
+      g_variant_unlock (value);
     }
 }
 
@@ -460,11 +429,12 @@ g_variant_ensure_serialised (GVariant *value)
  * @type: the type of the new instance
  * @serialised: if the instance will be in serialised form
  * @trusted: if the instance will be trusted
- * @returns: a new #GVariant with a floating reference
  *
  * Allocates a #GVariant instance and does some common work (such as
  * looking up and filling in the type info), setting the state field,
  * and setting the ref_count to 1.
+ *
+ * Returns: a new #GVariant with a floating reference
  */
 static GVariant *
 g_variant_alloc (const GVariantType *type,
@@ -478,48 +448,71 @@ g_variant_alloc (const GVariantType *type,
   value->state = (serialised ? STATE_SERIALISED : 0) |
                  (trusted ? STATE_TRUSTED : 0) |
                  STATE_FLOATING;
-  value->size = (gssize) -1;
   value->ref_count = 1;
 
   return value;
 }
 
-/* -- internal -- */
-/* < internal >
- * g_variant_new_from_buffer:
+/**
+ * g_variant_new_from_bytes:
  * @type: a #GVariantType
- * @buffer: a #GBuffer
- * @trusted: if the contents of @buffer are trusted
- * @returns: a new #GVariant with a floating reference
+ * @bytes: a #GBytes
+ * @trusted: if the contents of @bytes are trusted
  *
  * Constructs a new serialised-mode #GVariant instance.  This is the
  * inner interface for creation of new serialised values that gets
  * called from various functions in gvariant.c.
  *
- * A reference is taken on @buffer.
+ * A reference is taken on @bytes.
+ *
+ * Returns: (transfer none): a new #GVariant with a floating reference
+ *
+ * Since: 2.36
  */
 GVariant *
-g_variant_new_from_buffer (const GVariantType *type,
-                           GBuffer            *buffer,
-                           gboolean            trusted)
+g_variant_new_from_bytes (const GVariantType *type,
+                          GBytes             *bytes,
+                          gboolean            trusted)
 {
   GVariant *value;
+  guint alignment;
+  gsize size;
 
   value = g_variant_alloc (type, TRUE, trusted);
-  value->contents.serialised.buffer = g_buffer_ref (buffer);
-  value->contents.serialised.data = buffer->data;
-  value->size = buffer->size;
+
+  value->contents.serialised.bytes = g_bytes_ref (bytes);
+
+  g_variant_type_info_query (value->type_info,
+                             &alignment, &size);
+
+  if (size && g_bytes_get_size (bytes) != size)
+    {
+      /* Creating a fixed-sized GVariant with a bytes of the wrong
+       * size.
+       *
+       * We should do the equivalent of pulling a fixed-sized child out
+       * of a brozen container (ie: data is NULL size is equal to the correct
+       * fixed size).
+       */
+      value->contents.serialised.data = NULL;
+      value->size = size;
+    }
+  else
+    {
+      value->contents.serialised.data = g_bytes_get_data (bytes, &value->size);
+    }
 
   return value;
 }
 
+/* -- internal -- */
+
 /* < internal >
  * g_variant_new_from_children:
  * @type: a #GVariantType
  * @children: an array of #GVariant pointers.  Consumed.
  * @n_children: the length of @children
  * @trusted: %TRUE if every child in @children in trusted
- * @returns: a new #GVariant with a floating reference
  *
  * Constructs a new tree-mode #GVariant instance.  This is the inner
  * interface for creation of new serialised values that gets called from
@@ -527,6 +520,8 @@ g_variant_new_from_buffer (const GVariantType *type,
  *
  * @children is consumed by this function.  g_free() will be called on
  * it some time later.
+ *
+ * Returns: a new #GVariant with a floating reference
  */
 GVariant *
 g_variant_new_from_children (const GVariantType  *type,
@@ -539,6 +534,8 @@ g_variant_new_from_children (const GVariantType  *type,
   value = g_variant_alloc (type, FALSE, trusted);
   value->contents.tree.children = children;
   value->contents.tree.n_children = n_children;
+  value->size = g_variant_serialiser_needed_size (value->type_info, g_variant_fill_gvs,
+                                                  (gpointer *) children, n_children);
 
   return value;
 }
@@ -546,11 +543,12 @@ g_variant_new_from_children (const GVariantType  *type,
 /* < internal >
  * g_variant_get_type_info:
  * @value: a #GVariant
- * @returns: the #GVariantTypeInfo for @value
  *
  * Returns the #GVariantTypeInfo corresponding to the type of @value.  A
  * reference is not added, so the return value is only good for the
  * duration of the life of @value.
+ *
+ * Returns: the #GVariantTypeInfo for @value
  */
 GVariantTypeInfo *
 g_variant_get_type_info (GVariant *value)
@@ -561,7 +559,6 @@ g_variant_get_type_info (GVariant *value)
 /* < internal >
  * g_variant_is_trusted:
  * @value: a #GVariant
- * @returns: if @value is trusted
  *
  * Determines if @value is trusted by #GVariant to contain only
  * fully-valid data.  All values constructed solely via #GVariant APIs
@@ -572,6 +569,8 @@ g_variant_get_type_info (GVariant *value)
  * skipped.  For example, we don't need to check that a string is
  * properly nul-terminated or that an object path is actually a
  * properly-formatted object path.
+ *
+ * Returns: if @value is trusted
  */
 gboolean
 g_variant_is_trusted (GVariant *value)
@@ -593,6 +592,9 @@ g_variant_is_trusted (GVariant *value)
 void
 g_variant_unref (GVariant *value)
 {
+  g_return_if_fail (value != NULL);
+  g_return_if_fail (value->ref_count > 0);
+
   if (g_atomic_int_dec_and_test (&value->ref_count))
     {
       if G_UNLIKELY (value->state & STATE_LOCKED)
@@ -604,10 +606,11 @@ g_variant_unref (GVariant *value)
       g_variant_type_info_unref (value->type_info);
 
       if (value->state & STATE_SERIALISED)
-        g_buffer_unref (value->contents.serialised.buffer);
+        g_bytes_unref (value->contents.serialised.bytes);
       else
         g_variant_release_children (value);
 
+      memset (value, 0, sizeof (GVariant));
       g_slice_free (GVariant, value);
     }
 }
@@ -615,15 +618,19 @@ g_variant_unref (GVariant *value)
 /**
  * g_variant_ref:
  * @value: a #GVariant
- * @returns: the same @value
  *
  * Increases the reference count of @value.
  *
+ * Returns: the same @value
+ *
  * Since: 2.24
  **/
 GVariant *
 g_variant_ref (GVariant *value)
 {
+  g_return_val_if_fail (value != NULL, NULL);
+  g_return_val_if_fail (value->ref_count > 0, NULL);
+
   g_atomic_int_inc (&value->ref_count);
 
   return value;
@@ -632,10 +639,9 @@ g_variant_ref (GVariant *value)
 /**
  * g_variant_ref_sink:
  * @value: a #GVariant
- * @returns: the same @value
  *
  * #GVariant uses a floating reference count system.  All functions with
- * names starting with <literal>g_variant_new_</literal> return floating
+ * names starting with `g_variant_new_` return floating
  * references.
  *
  * Calling g_variant_ref_sink() on a #GVariant with a floating reference
@@ -657,11 +663,16 @@ g_variant_ref (GVariant *value)
  * maintaining normal refcounting semantics in situations where values
  * are not floating.
  *
+ * Returns: the same @value
+ *
  * Since: 2.24
  **/
 GVariant *
 g_variant_ref_sink (GVariant *value)
 {
+  g_return_val_if_fail (value != NULL, NULL);
+  g_return_val_if_fail (value->ref_count > 0, NULL);
+
   g_variant_lock (value);
 
   if (~value->state & STATE_FLOATING)
@@ -675,9 +686,84 @@ g_variant_ref_sink (GVariant *value)
 }
 
 /**
+ * g_variant_take_ref:
+ * @value: a #GVariant
+ *
+ * If @value is floating, sink it.  Otherwise, do nothing.
+ *
+ * Typically you want to use g_variant_ref_sink() in order to
+ * automatically do the correct thing with respect to floating or
+ * non-floating references, but there is one specific scenario where
+ * this function is helpful.
+ *
+ * The situation where this function is helpful is when creating an API
+ * that allows the user to provide a callback function that returns a
+ * #GVariant.  We certainly want to allow the user the flexibility to
+ * return a non-floating reference from this callback (for the case
+ * where the value that is being returned already exists).
+ *
+ * At the same time, the style of the #GVariant API makes it likely that
+ * for newly-created #GVariant instances, the user can be saved some
+ * typing if they are allowed to return a #GVariant with a floating
+ * reference.
+ *
+ * Using this function on the return value of the user's callback allows
+ * the user to do whichever is more convenient for them.  The caller
+ * will alway receives exactly one full reference to the value: either
+ * the one that was returned in the first place, or a floating reference
+ * that has been converted to a full reference.
+ *
+ * This function has an odd interaction when combined with
+ * g_variant_ref_sink() running at the same time in another thread on
+ * the same #GVariant instance.  If g_variant_ref_sink() runs first then
+ * the result will be that the floating reference is converted to a hard
+ * reference.  If g_variant_take_ref() runs first then the result will
+ * be that the floating reference is converted to a hard reference and
+ * an additional reference on top of that one is added.  It is best to
+ * avoid this situation.
+ *
+ * Returns: the same @value
+ **/
+GVariant *
+g_variant_take_ref (GVariant *value)
+{
+  g_return_val_if_fail (value != NULL, NULL);
+  g_return_val_if_fail (value->ref_count > 0, NULL);
+
+  g_atomic_int_and (&value->state, ~STATE_FLOATING);
+
+  return value;
+}
+
+/**
+ * g_variant_is_floating:
+ * @value: a #GVariant
+ *
+ * Checks whether @value has a floating reference count.
+ *
+ * This function should only ever be used to assert that a given variant
+ * is or is not floating, or for debug purposes. To acquire a reference
+ * to a variant that might be floating, always use g_variant_ref_sink()
+ * or g_variant_take_ref().
+ *
+ * See g_variant_ref_sink() for more information about floating reference
+ * counts.
+ *
+ * Returns: whether @value is floating
+ *
+ * Since: 2.26
+ **/
+gboolean
+g_variant_is_floating (GVariant *value)
+{
+  g_return_val_if_fail (value != NULL, FALSE);
+
+  return (value->state & STATE_FLOATING) != 0;
+}
+
+/**
  * g_variant_get_size:
  * @value: a #GVariant instance
- * @returns: the serialised size of @value
  *
  * Determines the number of bytes that would be required to store @value
  * with g_variant_store().
@@ -691,22 +777,19 @@ g_variant_ref_sink (GVariant *value)
  * operation which is approximately O(n) in the number of values
  * involved.
  *
+ * Returns: the serialised size of @value
+ *
  * Since: 2.24
  **/
 gsize
 g_variant_get_size (GVariant *value)
 {
-  g_variant_lock (value);
-  g_variant_ensure_size (value);
-  g_variant_unlock (value);
-
   return value->size;
 }
 
 /**
  * g_variant_get_data:
  * @value: a #GVariant instance
- * @returns: the serialised form of @value, or %NULL
  *
  * Returns a pointer to the serialised form of a #GVariant instance.
  * The returned data may not be in fully-normalised form if read from an
@@ -724,22 +807,66 @@ g_variant_get_size (GVariant *value)
  * serialisation occurs implicitly and is approximately O(n) in the size
  * of the result.
  *
+ * To deserialise the data returned by this function, in addition to the
+ * serialised data, you must know the type of the #GVariant, and (if the
+ * machine might be different) the endianness of the machine that stored
+ * it. As a result, file formats or network messages that incorporate
+ * serialised #GVariants must include this information either
+ * implicitly (for instance "the file always contains a
+ * %G_VARIANT_TYPE_VARIANT and it is always in little-endian order") or
+ * explicitly (by storing the type and/or endianness in addition to the
+ * serialised data).
+ *
+ * Returns: (transfer none): the serialised form of @value, or %NULL
+ *
  * Since: 2.24
  **/
 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;
 }
 
 /**
+ * g_variant_get_data_as_bytes:
+ * @value: a #GVariant
+ *
+ * Returns a pointer to the serialised form of a #GVariant instance.
+ * The semantics of this function are exactly the same as
+ * g_variant_get_data(), except that the returned #GBytes holds
+ * a reference to the variant data.
+ *
+ * Returns: (transfer full): A new #GBytes representing the variant data
+ *
+ * Since: 2.36
+ */ 
+GBytes *
+g_variant_get_data_as_bytes (GVariant *value)
+{
+  const gchar *bytes_data;
+  const gchar *data;
+  gsize bytes_size;
+  gsize size;
+
+  g_variant_ensure_serialised (value);
+
+  bytes_data = g_bytes_get_data (value->contents.serialised.bytes, &bytes_size);
+  data = value->contents.serialised.data;
+  size = value->size;
+
+  if (data == bytes_data && size == bytes_size)
+    return g_bytes_ref (value->contents.serialised.bytes);
+  else
+    return g_bytes_new_from_bytes (value->contents.serialised.bytes,
+                                   data - bytes_data, size);
+}
+
+
+/**
  * g_variant_n_children:
  * @value: a container #GVariant
- * @returns: the number of children in the container
  *
  * Determines the number of children in a container #GVariant instance.
  * This includes variants, maybes, arrays, tuples and dictionary
@@ -753,6 +880,8 @@ g_variant_get_data (GVariant *value)
  *
  * This function is O(1).
  *
+ * Returns: the number of children in the container
+ *
  * Since: 2.24
  **/
 gsize
@@ -760,9 +889,12 @@ g_variant_n_children (GVariant *value)
 {
   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,
@@ -772,10 +904,6 @@ g_variant_n_children (GVariant *value)
 
       n_children = g_variant_serialised_n_children (serialised);
     }
-  else
-    n_children = value->contents.tree.n_children;
-
-  g_variant_unlock (value);
 
   return n_children;
 }
@@ -784,7 +912,6 @@ g_variant_n_children (GVariant *value)
  * g_variant_get_child_value:
  * @value: a container #GVariant
  * @index_: the index of the child to fetch
- * @returns: the child at the specified index
  *
  * Reads a child item out of a container #GVariant instance.  This
  * includes variants, maybes, arrays, tuples and dictionary
@@ -794,19 +921,30 @@ g_variant_n_children (GVariant *value)
  * It is an error if @index_ is greater than the number of child items
  * in the container.  See g_variant_n_children().
  *
+ * The returned value is never floating.  You should free it with
+ * g_variant_unref() when you're done with it.
+ *
  * This function is O(1).
  *
+ * Returns: (transfer full): the child at the specified index
+ *
  * Since: 2.24
  **/
 GVariant *
 g_variant_get_child_value (GVariant *value,
                            gsize     index_)
 {
-  GVariant *child = NULL;
+  GVariant *child;
 
-  g_variant_lock (value);
+  g_return_val_if_fail (index_ < g_variant_n_children (value), NULL);
 
-  if (value->state & STATE_SERIALISED)
+  if (g_variant_lock_in_tree_form (value))
+    {
+
+      child = g_variant_ref (value->contents.tree.children[index_]);
+      g_variant_unlock (value);
+    }
+  else
     {
       GVariantSerialised serialised = {
         value->type_info,
@@ -827,14 +965,10 @@ g_variant_get_child_value (GVariant *value,
                      STATE_SERIALISED;
       child->size = s_child.size;
       child->ref_count = 1;
-      child->contents.serialised.buffer =
-        g_buffer_ref (value->contents.serialised.buffer);
+      child->contents.serialised.bytes =
+        g_bytes_ref (value->contents.serialised.bytes);
       child->contents.serialised.data = s_child.data;
-     }
-  else
-    child = g_variant_ref (value->contents.tree.children[index_]);
-
-  g_variant_unlock (value);
+    }
 
   return child;
 }
@@ -849,7 +983,11 @@ g_variant_get_child_value (GVariant *value,
  *
  * The stored data is in machine native byte order but may not be in
  * fully-normalised form if read from an untrusted source.  See
- * g_variant_normalise() for a solution.
+ * g_variant_get_normal_form() for a solution.
+ *
+ * As with g_variant_get_data(), to be able to deserialise the
+ * serialised variant successfully, its type and (if the destination
+ * machine might be different) its endianness must also be available.
  *
  * This function is approximately O(n) in the size of @data.
  *
@@ -859,45 +997,49 @@ void
 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);
 }
 
 /**
  * g_variant_is_normal_form:
  * @value: a #GVariant instance
- * @returns: %TRUE if @value is in normal form
  *
  * Checks if @value is in normal form.
  *
  * The main reason to do this is to detect if a given chunk of
  * serialised data is in normal form: load the data into a #GVariant
- * using g_variant_create_from_data() and then use this function to
+ * using g_variant_new_from_data() and then use this function to
  * check.
  *
  * If @value is found to be in normal form then it will be marked as
  * being trusted.  If the value was already marked as being trusted then
  * this function will immediately return %TRUE.
  *
+ * Returns: %TRUE if @value is in normal form
+ *
  * Since: 2.24
  **/
 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)
@@ -927,6 +1069,3 @@ g_variant_is_normal_form (GVariant *value)
 
   return (value->state & STATE_TRUSTED) != 0;
 }
-
-#define __G_VARIANT_CORE_C__
-#include "galiasdef.c"