+ if (data == NULL)
+ remove_notify (object, i);
+ }
+ if (data != NULL)
+ set_notify (object, i, quark, NULL, data, destroy);
+ G_UNLOCK (qdata_mutex);
+
+ if (old_notify)
+ old_notify (old_data);
+}
+
+/**
+ * gst_mini_object_get_qdata:
+ * @object: The GstMiniObject to get a stored user data pointer from
+ * @quark: A #GQuark, naming the user data pointer
+ *
+ * This function gets back user data pointers stored via
+ * gst_mini_object_set_qdata().
+ *
+ * Returns: (transfer none) (nullable): The user data pointer set, or
+ * %NULL
+ */
+gpointer
+gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
+{
+ guint i;
+ gpointer result;
+
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (quark > 0, NULL);
+
+ G_LOCK (qdata_mutex);
+ if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
+ PrivData *priv_data = object->priv_pointer;
+ result = QDATA_DATA (priv_data, i);
+ } else {
+ result = NULL;
+ }
+ G_UNLOCK (qdata_mutex);
+
+ return result;
+}
+
+/**
+ * gst_mini_object_steal_qdata:
+ * @object: The GstMiniObject to get a stored user data pointer from
+ * @quark: A #GQuark, naming the user data pointer
+ *
+ * This function gets back user data pointers stored via gst_mini_object_set_qdata()
+ * and removes the data from @object without invoking its destroy() function (if
+ * any was set).
+ *
+ * Returns: (transfer full) (nullable): The user data pointer set, or
+ * %NULL
+ */
+gpointer
+gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
+{
+ guint i;
+ gpointer result;
+
+ g_return_val_if_fail (object != NULL, NULL);
+ g_return_val_if_fail (quark > 0, NULL);
+
+ G_LOCK (qdata_mutex);
+ if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
+ PrivData *priv_data = object->priv_pointer;
+ result = QDATA_DATA (priv_data, i);
+ remove_notify (object, i);
+ } else {
+ result = NULL;
+ }
+ G_UNLOCK (qdata_mutex);
+
+ return result;
+}
+
+/**
+ * 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;