+
+/**
+ * gst_mini_object_add_parent:
+ * @object: a #GstMiniObject
+ * @parent: a parent #GstMiniObject
+ *
+ * This adds @parent as a parent for @object. Having one ore more parents affects the
+ * writability of @object: if a @parent is not writable, @object is also not
+ * writable, regardless of its refcount. @object is only writable if all
+ * the parents are writable and its own refcount is exactly 1.
+ *
+ * Note: This function does not take ownership of @parent and also does not
+ * take an additional reference. It is the responsibility of the caller to
+ * remove the parent again at a later time.
+ *
+ * Since: 1.16
+ */
+void
+gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)
+{
+ gint priv_state;
+
+ g_return_if_fail (object != NULL);
+
+ GST_CAT_TRACE (GST_CAT_REFCOUNTING, "adding parent %p to object %p", parent,
+ object);
+
+ priv_state = lock_priv_pointer (object);
+ /* If we already had one parent, we need to allocate the full struct now */
+ if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
+ /* Unlock again */
+ g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
+
+ ensure_priv_data (object);
+ priv_state = PRIV_DATA_STATE_PARENTS_OR_QDATA;
+ }
+
+ /* Now we either have to add the new parent to the full struct, or add
+ * our one and only parent to the pointer field */
+ if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
+ PrivData *priv_data = object->priv_pointer;
+
+ /* Lock parents */
+ while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
+
+ if (priv_data->n_parents >= priv_data->n_parents_len) {
+ priv_data->n_parents_len *= 2;
+ if (priv_data->n_parents_len == 0)
+ priv_data->n_parents_len = 16;
+
+ priv_data->parents =
+ g_realloc (priv_data->parents,
+ priv_data->n_parents_len * sizeof (GstMiniObject *));
+ }
+ priv_data->parents[priv_data->n_parents] = parent;
+ priv_data->n_parents++;
+
+ /* Unlock again */
+ g_atomic_int_set (&priv_data->parent_lock, 0);
+ } else if (priv_state == PRIV_DATA_STATE_NO_PARENT) {
+ object->priv_pointer = parent;
+
+ /* Unlock again */
+ g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_ONE_PARENT);
+ } else {
+ g_assert_not_reached ();
+ }
+}
+
+/**
+ * gst_mini_object_remove_parent:
+ * @object: a #GstMiniObject
+ * @parent: a parent #GstMiniObject
+ *
+ * This removes @parent as a parent for @object. See
+ * gst_mini_object_add_parent().
+ *
+ * Since: 1.16
+ */
+void
+gst_mini_object_remove_parent (GstMiniObject * object, GstMiniObject * parent)
+{
+ gint priv_state;
+
+ g_return_if_fail (object != NULL);
+
+ GST_CAT_TRACE (GST_CAT_REFCOUNTING, "removing parent %p from object %p",
+ parent, object);
+
+ priv_state = lock_priv_pointer (object);
+
+ /* Now we either have to add the new parent to the full struct, or add
+ * our one and only parent to the pointer field */
+ if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
+ PrivData *priv_data = object->priv_pointer;
+ guint i;
+
+ /* Lock parents */
+ while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
+
+ for (i = 0; i < priv_data->n_parents; i++)
+ if (parent == priv_data->parents[i])
+ break;
+
+ if (i != priv_data->n_parents) {
+ priv_data->n_parents--;
+ if (priv_data->n_parents != i)
+ priv_data->parents[i] = priv_data->parents[priv_data->n_parents];
+ } else {
+ g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
+ object, parent);
+ }
+
+ /* Unlock again */
+ g_atomic_int_set (&priv_data->parent_lock, 0);
+ } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
+ if (object->priv_pointer != parent) {
+ g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
+ object, parent);
+ /* Unlock again */
+ g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
+ } else {
+ object->priv_pointer = NULL;
+ /* Unlock again */
+ g_atomic_int_set ((gint *) & object->priv_uint,
+ PRIV_DATA_STATE_NO_PARENT);
+ }
+ } else {
+ /* Unlock again */
+ g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_NO_PARENT);
+ }
+}