GVariant: avoid locking in a common case
authorRyan Lortie <desrt@desrt.ca>
Tue, 26 Oct 2010 15:49:32 +0000 (11:49 -0400)
committerRyan Lortie <desrt@desrt.ca>
Tue, 26 Oct 2010 15:49:32 +0000 (11:49 -0400)
Avoid acquiring the lock on the instance on the case of deserialising a
child.  We know that it is safe to do this unlocked because a serialised
child will never become unserialised.

Closes #626320

glib/gvariant-core.c

index 6f01930..d783053 100644 (file)
@@ -847,41 +847,50 @@ GVariant *
 g_variant_get_child_value (GVariant *value,
                            gsize     index_)
 {
-  GVariant *child = NULL;
+  if (~g_atomic_int_get (&value->state) & STATE_SERIALISED)
+    {
+      g_variant_lock (value);
 
-  g_variant_lock (value);
+      if (~value->state & STATE_SERIALISED)
+        {
+          GVariant *child;
 
-  if (value->state & STATE_SERIALISED)
-    {
-      GVariantSerialised serialised = {
-        value->type_info,
-        (gpointer) value->contents.serialised.data,
-        value->size
-      };
-      GVariantSerialised s_child;
+          child = g_variant_ref (value->contents.tree.children[index_]);
+          g_variant_unlock (value);
 
-      /* 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.buffer =
-        g_buffer_ref (value->contents.serialised.buffer);
-      child->contents.serialised.data = s_child.data;
-     }
-  else
-    child = g_variant_ref (value->contents.tree.children[index_]);
+          return child;
+        }
 
-  g_variant_unlock (value);
+      g_variant_unlock (value);
+    }
 
-  return 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.buffer =
+      g_buffer_ref (value->contents.serialised.buffer);
+    child->contents.serialised.data = s_child.data;
+
+    return child;
+  }
 }
 
 /**