2 * Copyright (C) 2005 David Schleef <ds@schleef.org>
4 * gstminiobject.h: Header for GstMiniObject
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 * SECTION:gstminiobject
23 * @title: GstMiniObject
24 * @short_description: Lightweight base class for the GStreamer object hierarchy
26 * #GstMiniObject is a simple structure that can be used to implement refcounted
29 * Subclasses will include #GstMiniObject as the first member in their structure
30 * and then call gst_mini_object_init() to initialize the #GstMiniObject fields.
32 * gst_mini_object_ref() and gst_mini_object_unref() increment and decrement the
33 * refcount respectively. When the refcount of a mini-object reaches 0, the
34 * dispose function is called first and when this returns %TRUE, the free
35 * function of the miniobject is called.
37 * A copy can be made with gst_mini_object_copy().
39 * gst_mini_object_is_writable() will return %TRUE when the refcount of the
40 * object is exactly 1 and there is no parent or a single parent exists and is
41 * writable itself, meaning the current caller has the only reference to the
42 * object. gst_mini_object_make_writable() will return a writable version of
43 * the object, which might be a new copy when the refcount was not 1.
45 * Opaque data can be associated with a #GstMiniObject with
46 * gst_mini_object_set_qdata() and gst_mini_object_get_qdata(). The data is
47 * meant to be specific to the particular object and is not automatically copied
48 * with gst_mini_object_copy() or similar methods.
50 * A weak reference can be added and remove with gst_mini_object_weak_ref()
51 * and gst_mini_object_weak_unref() respectively.
57 #include "gst/gst_private.h"
58 #include "gst/gstminiobject.h"
59 #include "gst/gstinfo.h"
60 #include <gobject/gvaluecollector.h>
62 GType _gst_mini_object_type = 0;
64 /* Mutex used for weak referencing */
65 G_LOCK_DEFINE_STATIC (qdata_mutex);
66 static GQuark weak_ref_quark;
68 #define SHARE_ONE (1 << 16)
69 #define SHARE_TWO (2 << 16)
70 #define SHARE_MASK (~(SHARE_ONE - 1))
71 #define IS_SHARED(state) (state >= SHARE_TWO)
72 #define LOCK_ONE (GST_LOCK_FLAG_LAST)
73 #define FLAG_MASK (GST_LOCK_FLAG_LAST - 1)
74 #define LOCK_MASK ((SHARE_ONE - 1) - FLAG_MASK)
75 #define LOCK_FLAG_MASK (SHARE_ONE - 1)
78 * GST_TYPE_MINI_OBJECT:
80 * The #GType associated with #GstMiniObject.
85 /* For backwards compatibility reasons we use the
86 * guint and gpointer in the GstMiniObject struct in
87 * a rather complicated way to store the parent(s) and qdata.
88 * Originally the were just the number of qdatas and the qdata.
90 * The guint is used as an atomic state integer with the following
92 * - Locked: 0, basically a spinlock
93 * - No parent, no qdata: 1 (pointer is NULL)
94 * - One parent: 2 (pointer contains the parent)
95 * - Multiple parents or qdata: 3 (pointer contains a PrivData struct)
97 * Unless we're in state 3, we always have to move to Locking state
98 * atomically and release that again later to the target state whenever
99 * accessing the pointer. When we're in state 3, we will never move to lower
102 * FIXME 2.0: We should store this directly inside the struct, possibly
103 * keeping space directly allocated for a couple of parents
108 PRIV_DATA_STATE_LOCKED = 0,
109 PRIV_DATA_STATE_NO_PARENT = 1,
110 PRIV_DATA_STATE_ONE_PARENT = 2,
111 PRIV_DATA_STATE_PARENTS_OR_QDATA = 3,
117 GstMiniObjectNotify notify;
119 GDestroyNotify destroy;
124 /* Atomic spinlock: 1 if locked, 0 otherwise */
126 guint n_parents, n_parents_len;
127 GstMiniObject **parents;
129 guint n_qdata, n_qdata_len;
133 #define QDATA(q,i) (q->qdata)[(i)]
134 #define QDATA_QUARK(o,i) (QDATA(o,i).quark)
135 #define QDATA_NOTIFY(o,i) (QDATA(o,i).notify)
136 #define QDATA_DATA(o,i) (QDATA(o,i).data)
137 #define QDATA_DESTROY(o,i) (QDATA(o,i).destroy)
139 GST_DEFINE_MINI_OBJECT_TYPE (GstMiniObject, gst_mini_object);
142 _priv_gst_mini_object_initialize (void)
144 _gst_mini_object_type = gst_mini_object_get_type ();
145 weak_ref_quark = g_quark_from_static_string ("GstMiniObjectWeakRefQuark");
149 * gst_mini_object_init: (skip)
150 * @mini_object: a #GstMiniObject
151 * @flags: initial #GstMiniObjectFlags
152 * @type: the #GType of the mini-object to create
153 * @copy_func: (allow-none): the copy function, or %NULL
154 * @dispose_func: (allow-none): the dispose function, or %NULL
155 * @free_func: (allow-none): the free function or %NULL
157 * Initializes a mini-object with the desired type and copy/dispose/free
161 gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
162 GstMiniObjectCopyFunction copy_func,
163 GstMiniObjectDisposeFunction dispose_func,
164 GstMiniObjectFreeFunction free_func)
166 mini_object->type = type;
167 mini_object->refcount = 1;
168 mini_object->lockstate = 0;
169 mini_object->flags = flags;
171 mini_object->copy = copy_func;
172 mini_object->dispose = dispose_func;
173 mini_object->free = free_func;
175 g_atomic_int_set ((gint *) & mini_object->priv_uint,
176 PRIV_DATA_STATE_NO_PARENT);
177 mini_object->priv_pointer = NULL;
179 GST_TRACER_MINI_OBJECT_CREATED (mini_object);
183 * gst_mini_object_copy: (skip)
184 * @mini_object: the mini-object to copy
186 * Creates a copy of the mini-object.
190 * Returns: (transfer full) (nullable): the new mini-object if copying is
191 * possible, %NULL otherwise.
194 gst_mini_object_copy (const GstMiniObject * mini_object)
198 g_return_val_if_fail (mini_object != NULL, NULL);
200 if (mini_object->copy)
201 copy = mini_object->copy (mini_object);
209 * gst_mini_object_lock:
210 * @object: the mini-object to lock
211 * @flags: #GstLockFlags
213 * Lock the mini-object with the specified access mode in @flags.
215 * Returns: %TRUE if @object could be locked.
218 gst_mini_object_lock (GstMiniObject * object, GstLockFlags flags)
220 gint access_mode, state, newstate;
222 g_return_val_if_fail (object != NULL, FALSE);
223 g_return_val_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object), FALSE);
225 if (G_UNLIKELY (object->flags & GST_MINI_OBJECT_FLAG_LOCK_READONLY &&
226 flags & GST_LOCK_FLAG_WRITE))
230 access_mode = flags & FLAG_MASK;
231 newstate = state = g_atomic_int_get (&object->lockstate);
233 GST_CAT_TRACE (GST_CAT_LOCKING, "lock %p: state %08x, access_mode %d",
234 object, state, access_mode);
236 if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
238 newstate += SHARE_ONE;
239 access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
242 /* shared counter > 1 and write access is not allowed */
243 if (((state & GST_LOCK_FLAG_WRITE) != 0
244 || (access_mode & GST_LOCK_FLAG_WRITE) != 0)
245 && IS_SHARED (newstate))
249 if ((state & LOCK_FLAG_MASK) == 0) {
250 /* nothing mapped, set access_mode */
251 newstate |= access_mode;
253 /* access_mode must match */
254 if ((state & access_mode) != access_mode)
257 /* increase refcount */
258 newstate += LOCK_ONE;
260 } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
267 GST_CAT_DEBUG (GST_CAT_LOCKING,
268 "lock failed %p: state %08x, access_mode %d", object, state,
275 * gst_mini_object_unlock:
276 * @object: the mini-object to unlock
277 * @flags: #GstLockFlags
279 * Unlock the mini-object with the specified access mode in @flags.
282 gst_mini_object_unlock (GstMiniObject * object, GstLockFlags flags)
284 gint access_mode, state, newstate;
286 g_return_if_fail (object != NULL);
287 g_return_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object));
290 access_mode = flags & FLAG_MASK;
291 newstate = state = g_atomic_int_get (&object->lockstate);
293 GST_CAT_TRACE (GST_CAT_LOCKING, "unlock %p: state %08x, access_mode %d",
294 object, state, access_mode);
296 if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
298 g_return_if_fail (state >= SHARE_ONE);
299 newstate -= SHARE_ONE;
300 access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
304 g_return_if_fail ((state & access_mode) == access_mode);
305 /* decrease the refcount */
306 newstate -= LOCK_ONE;
307 /* last refcount, unset access_mode */
308 if ((newstate & LOCK_FLAG_MASK) == access_mode)
309 newstate &= ~LOCK_FLAG_MASK;
311 } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
315 /* Locks the priv pointer and sets the priv uint to PRIV_DATA_STATE_LOCKED,
316 * unless the full struct was already stored in the priv pointer.
318 * Returns the previous state of the priv uint
321 lock_priv_pointer (GstMiniObject * object)
323 gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
325 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
326 /* As long as the struct was not allocated yet and either someone else
327 * locked it or our priv_state is out of date, try to lock it */
328 while (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA &&
329 (priv_state == PRIV_DATA_STATE_LOCKED ||
330 !g_atomic_int_compare_and_exchange ((gint *) & object->priv_uint,
331 priv_state, PRIV_DATA_STATE_LOCKED)))
332 priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
334 /* Note that if we got the full struct, we did not store
335 * PRIV_DATA_STATE_LOCKED and did not actually lock the priv pointer */
342 * gst_mini_object_is_writable:
343 * @mini_object: the mini-object to check
345 * If @mini_object has the LOCKABLE flag set, check if the current EXCLUSIVE
346 * lock on @object is the only one, this means that changes to the object will
347 * not be visible to any other object.
349 * If the LOCKABLE flag is not set, check if the refcount of @mini_object is
350 * exactly 1, meaning that no other reference exists to the object and that the
351 * object is therefore writable.
353 * Modification of a mini-object should only be done after verifying that it
356 * Returns: %TRUE if the object is writable.
359 gst_mini_object_is_writable (const GstMiniObject * mini_object)
364 g_return_val_if_fail (mini_object != NULL, FALSE);
366 /* Let's first check our own writability. If this already fails there's
367 * no point in checking anything else */
368 if (GST_MINI_OBJECT_IS_LOCKABLE (mini_object)) {
369 result = !IS_SHARED (g_atomic_int_get (&mini_object->lockstate));
371 result = (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
376 /* We are writable ourselves, but are there parents and are they all
378 priv_state = lock_priv_pointer (GST_MINI_OBJECT_CAST (mini_object));
380 /* Now we either have to check the full struct and all the
381 * parents in there, or if there is exactly one parent we
382 * can check that one */
383 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
384 PrivData *priv_data = mini_object->priv_pointer;
387 while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
389 /* If we have one parent, we're only writable if that parent is writable.
390 * Otherwise if we have multiple parents we are not writable, and if
391 * we have no parent, we are writable */
392 if (priv_data->n_parents == 1)
393 result = gst_mini_object_is_writable (priv_data->parents[0]);
394 else if (priv_data->n_parents == 0)
400 g_atomic_int_set (&priv_data->parent_lock, 0);
402 if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
403 result = gst_mini_object_is_writable (mini_object->priv_pointer);
405 g_assert (priv_state == PRIV_DATA_STATE_NO_PARENT);
410 g_atomic_int_set ((gint *) & mini_object->priv_uint, priv_state);
417 * gst_mini_object_make_writable: (skip)
418 * @mini_object: (transfer full): the mini-object to make writable
420 * Checks if a mini-object is writable. If not, a writable copy is made and
421 * returned. This gives away the reference to the original mini object,
422 * and returns a reference to the new object.
426 * Returns: (transfer full): a mini-object (possibly the same pointer) that
430 gst_mini_object_make_writable (GstMiniObject * mini_object)
434 g_return_val_if_fail (mini_object != NULL, NULL);
436 if (gst_mini_object_is_writable (mini_object)) {
439 ret = gst_mini_object_copy (mini_object);
440 GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject %p -> %p",
441 g_type_name (GST_MINI_OBJECT_TYPE (mini_object)), mini_object, ret);
442 gst_mini_object_unref (mini_object);
449 * gst_mini_object_ref: (skip)
450 * @mini_object: the mini-object
452 * Increase the reference count of the mini-object.
454 * Note that the refcount affects the writability
455 * of @mini-object, see gst_mini_object_is_writable(). It is
456 * important to note that keeping additional references to
457 * GstMiniObject instances can potentially increase the number
458 * of memcpy operations in a pipeline, especially if the miniobject
461 * Returns: (transfer full): the mini-object.
464 gst_mini_object_ref (GstMiniObject * mini_object)
466 gint old_refcount, new_refcount;
468 g_return_val_if_fail (mini_object != NULL, NULL);
469 /* we can't assert that the refcount > 0 since the _free functions
470 * increments the refcount from 0 to 1 again to allow resurrecting
472 g_return_val_if_fail (mini_object->refcount > 0, NULL);
475 old_refcount = g_atomic_int_add (&mini_object->refcount, 1);
476 new_refcount = old_refcount + 1;
478 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
479 old_refcount, new_refcount);
481 GST_TRACER_MINI_OBJECT_REFFED (mini_object, new_refcount);
486 /* Called with global qdata lock */
488 find_notify (GstMiniObject * object, GQuark quark, gboolean match_notify,
489 GstMiniObjectNotify notify, gpointer data)
492 gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
495 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA)
498 priv_data = object->priv_pointer;
500 for (i = 0; i < priv_data->n_qdata; i++) {
501 if (QDATA_QUARK (priv_data, i) == quark) {
502 /* check if we need to match the callback too */
503 if (!match_notify || (QDATA_NOTIFY (priv_data, i) == notify &&
504 QDATA_DATA (priv_data, i) == data))
512 remove_notify (GstMiniObject * object, gint index)
514 gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
517 g_assert (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA);
518 priv_data = object->priv_pointer;
521 priv_data->n_qdata--;
522 if (priv_data->n_qdata == 0) {
523 /* we don't shrink but free when everything is gone */
524 g_free (priv_data->qdata);
525 priv_data->qdata = NULL;
526 priv_data->n_qdata_len = 0;
527 } else if (index != priv_data->n_qdata) {
528 QDATA (priv_data, index) = QDATA (priv_data, priv_data->n_qdata);
532 /* Make sure we allocate the PrivData of this object if not happened yet */
534 ensure_priv_data (GstMiniObject * object)
538 GstMiniObject *parent = NULL;
540 GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
541 "allocating private data %s miniobject %p",
542 g_type_name (GST_MINI_OBJECT_TYPE (object)), object);
544 priv_state = lock_priv_pointer (object);
545 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA)
548 /* Now we're either locked, or someone has already allocated the struct
549 * before us and we can just go ahead
551 * Note: if someone else allocated it in the meantime, we don't have to
552 * unlock as we didn't lock! */
553 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
554 if (priv_state == PRIV_DATA_STATE_ONE_PARENT)
555 parent = object->priv_pointer;
557 object->priv_pointer = priv_data = g_new0 (PrivData, 1);
560 priv_data->parents = g_new (GstMiniObject *, 16);
561 priv_data->n_parents_len = 16;
562 priv_data->n_parents = 1;
563 priv_data->parents[0] = parent;
567 g_atomic_int_set ((gint *) & object->priv_uint,
568 PRIV_DATA_STATE_PARENTS_OR_QDATA);
573 set_notify (GstMiniObject * object, gint index, GQuark quark,
574 GstMiniObjectNotify notify, gpointer data, GDestroyNotify destroy)
578 ensure_priv_data (object);
579 priv_data = object->priv_pointer;
583 index = priv_data->n_qdata++;
584 if (index >= priv_data->n_qdata_len) {
585 priv_data->n_qdata_len *= 2;
586 if (priv_data->n_qdata_len == 0)
587 priv_data->n_qdata_len = 16;
590 g_realloc (priv_data->qdata,
591 sizeof (GstQData) * priv_data->n_qdata_len);
595 QDATA_QUARK (priv_data, index) = quark;
596 QDATA_NOTIFY (priv_data, index) = notify;
597 QDATA_DATA (priv_data, index) = data;
598 QDATA_DESTROY (priv_data, index) = destroy;
602 free_priv_data (GstMiniObject * obj)
605 gint priv_state = g_atomic_int_get ((gint *) & obj->priv_uint);
608 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
609 if (priv_state == PRIV_DATA_STATE_LOCKED) {
611 ("%s: object finalizing but has locked private data (object:%p)",
613 } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
615 ("%s: object finalizing but still has parent (object:%p, parent:%p)",
616 G_STRFUNC, obj, obj->priv_pointer);
622 priv_data = obj->priv_pointer;
624 for (i = 0; i < priv_data->n_qdata; i++) {
625 if (QDATA_QUARK (priv_data, i) == weak_ref_quark)
626 QDATA_NOTIFY (priv_data, i) (QDATA_DATA (priv_data, i), obj);
627 if (QDATA_DESTROY (priv_data, i))
628 QDATA_DESTROY (priv_data, i) (QDATA_DATA (priv_data, i));
630 g_free (priv_data->qdata);
632 if (priv_data->n_parents)
633 g_warning ("%s: object finalizing but still has %d parents (object:%p)",
634 G_STRFUNC, priv_data->n_parents, obj);
635 g_free (priv_data->parents);
641 * gst_mini_object_unref: (skip)
642 * @mini_object: the mini-object
644 * Decreases the reference count of the mini-object, possibly freeing
648 gst_mini_object_unref (GstMiniObject * mini_object)
650 gint old_refcount, new_refcount;
652 g_return_if_fail (mini_object != NULL);
653 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) > 0);
655 old_refcount = g_atomic_int_add (&mini_object->refcount, -1);
656 new_refcount = old_refcount - 1;
658 g_return_if_fail (old_refcount > 0);
660 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
661 mini_object, old_refcount, new_refcount);
663 GST_TRACER_MINI_OBJECT_UNREFFED (mini_object, new_refcount);
665 if (new_refcount == 0) {
668 if (mini_object->dispose)
669 do_free = mini_object->dispose (mini_object);
673 /* if the subclass recycled the object (and returned FALSE) we don't
674 * want to free the instance anymore */
675 if (G_LIKELY (do_free)) {
676 /* there should be no outstanding locks */
677 g_return_if_fail ((g_atomic_int_get (&mini_object->lockstate) & LOCK_MASK)
680 free_priv_data (mini_object);
682 GST_TRACER_MINI_OBJECT_DESTROYED (mini_object);
683 if (mini_object->free)
684 mini_object->free (mini_object);
690 * gst_clear_mini_object: (skip)
691 * @object_ptr: a pointer to a #GstMiniObject reference
693 * Clears a reference to a #GstMiniObject.
695 * @object_ptr must not be %NULL.
697 * If the reference is %NULL then this function does nothing.
698 * Otherwise, the reference count of the object is decreased using
699 * gst_mini_object_unref() and the pointer is set to %NULL.
701 * A macro is also included that allows this function to be used without
706 #undef gst_clear_mini_object
708 gst_clear_mini_object (GstMiniObject ** object_ptr)
710 g_clear_pointer (object_ptr, gst_mini_object_unref);
714 * gst_mini_object_replace:
715 * @olddata: (inout) (transfer full) (nullable): pointer to a pointer to a
716 * mini-object to be replaced
717 * @newdata: (allow-none): pointer to new mini-object
719 * Atomically modifies a pointer to point to a new mini-object.
720 * The reference count of @olddata is decreased and the reference count of
721 * @newdata is increased.
723 * Either @newdata and the value pointed to by @olddata may be %NULL.
725 * Returns: %TRUE if @newdata was different from @olddata
728 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
730 GstMiniObject *olddata_val;
732 g_return_val_if_fail (olddata != NULL, FALSE);
734 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
735 *olddata, *olddata ? (*olddata)->refcount : 0,
736 newdata, newdata ? newdata->refcount : 0);
738 olddata_val = (GstMiniObject *) g_atomic_pointer_get ((gpointer *) olddata);
740 if (G_UNLIKELY (olddata_val == newdata))
744 gst_mini_object_ref (newdata);
746 while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
747 olddata, (gpointer) olddata_val, newdata))) {
748 olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
749 if (G_UNLIKELY (olddata_val == newdata))
754 gst_mini_object_unref (olddata_val);
756 return olddata_val != newdata;
760 * gst_mini_object_steal: (skip)
761 * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
764 * Replace the current #GstMiniObject pointer to by @olddata with %NULL and
765 * return the old value.
767 * Returns: (nullable): the #GstMiniObject at @oldata
770 gst_mini_object_steal (GstMiniObject ** olddata)
772 GstMiniObject *olddata_val;
774 g_return_val_if_fail (olddata != NULL, NULL);
776 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
777 *olddata, *olddata ? (*olddata)->refcount : 0);
780 olddata_val = (GstMiniObject *) g_atomic_pointer_get ((gpointer *) olddata);
781 if (olddata_val == NULL)
783 } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
784 olddata, (gpointer) olddata_val, NULL)));
790 * gst_mini_object_take:
791 * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
793 * @newdata: pointer to new mini-object
795 * Modifies a pointer to point to a new mini-object. The modification
796 * is done atomically. This version is similar to gst_mini_object_replace()
797 * except that it does not increase the refcount of @newdata and thus
798 * takes ownership of @newdata.
800 * Either @newdata and the value pointed to by @olddata may be %NULL.
802 * Returns: %TRUE if @newdata was different from @olddata
805 gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
807 GstMiniObject *olddata_val;
809 g_return_val_if_fail (olddata != NULL, FALSE);
811 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "take %p (%d) with %p (%d)",
812 *olddata, *olddata ? (*olddata)->refcount : 0,
813 newdata, newdata ? newdata->refcount : 0);
816 olddata_val = (GstMiniObject *) g_atomic_pointer_get ((gpointer *) olddata);
817 if (G_UNLIKELY (olddata_val == newdata))
819 } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
820 olddata, (gpointer) olddata_val, newdata)));
823 gst_mini_object_unref (olddata_val);
825 return olddata_val != newdata;
829 * gst_mini_object_weak_ref: (skip)
830 * @object: #GstMiniObject to reference weakly
831 * @notify: callback to invoke before the mini object is freed
832 * @data: extra data to pass to notify
834 * Adds a weak reference callback to a mini object. Weak references are
835 * used for notification when a mini object is finalized. They are called
836 * "weak references" because they allow you to safely hold a pointer
837 * to the mini object without calling gst_mini_object_ref()
838 * (gst_mini_object_ref() adds a strong reference, that is, forces the object
842 gst_mini_object_weak_ref (GstMiniObject * object,
843 GstMiniObjectNotify notify, gpointer data)
845 g_return_if_fail (object != NULL);
846 g_return_if_fail (notify != NULL);
847 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
849 G_LOCK (qdata_mutex);
850 set_notify (object, -1, weak_ref_quark, notify, data, NULL);
851 G_UNLOCK (qdata_mutex);
855 * gst_mini_object_weak_unref: (skip)
856 * @object: #GstMiniObject to remove a weak reference from
857 * @notify: callback to search for
858 * @data: data to search for
860 * Removes a weak reference callback from a mini object.
863 gst_mini_object_weak_unref (GstMiniObject * object,
864 GstMiniObjectNotify notify, gpointer data)
868 g_return_if_fail (object != NULL);
869 g_return_if_fail (notify != NULL);
871 G_LOCK (qdata_mutex);
872 if ((i = find_notify (object, weak_ref_quark, TRUE, notify, data)) != -1) {
873 remove_notify (object, i);
875 g_warning ("%s: couldn't find weak ref %p (object:%p data:%p)", G_STRFUNC,
876 notify, object, data);
878 G_UNLOCK (qdata_mutex);
882 * gst_mini_object_set_qdata:
883 * @object: a #GstMiniObject
884 * @quark: A #GQuark, naming the user data pointer
885 * @data: An opaque user data pointer
886 * @destroy: Function to invoke with @data as argument, when @data
889 * This sets an opaque, named pointer on a miniobject.
890 * The name is specified through a #GQuark (retrieved e.g. via
891 * g_quark_from_static_string()), and the pointer
892 * can be gotten back from the @object with gst_mini_object_get_qdata()
893 * until the @object is disposed.
894 * Setting a previously set user data pointer, overrides (frees)
895 * the old pointer set, using %NULL as pointer essentially
896 * removes the data stored.
898 * @destroy may be specified which is called with @data as argument
899 * when the @object is disposed, or the data is being overwritten by
900 * a call to gst_mini_object_set_qdata() with the same @quark.
903 gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
904 gpointer data, GDestroyNotify destroy)
907 gpointer old_data = NULL;
908 GDestroyNotify old_notify = NULL;
910 g_return_if_fail (object != NULL);
911 g_return_if_fail (quark > 0);
913 G_LOCK (qdata_mutex);
914 if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
915 PrivData *priv_data = object->priv_pointer;
917 old_data = QDATA_DATA (priv_data, i);
918 old_notify = QDATA_DESTROY (priv_data, i);
921 remove_notify (object, i);
924 set_notify (object, i, quark, NULL, data, destroy);
925 G_UNLOCK (qdata_mutex);
928 old_notify (old_data);
932 * gst_mini_object_get_qdata:
933 * @object: The GstMiniObject to get a stored user data pointer from
934 * @quark: A #GQuark, naming the user data pointer
936 * This function gets back user data pointers stored via
937 * gst_mini_object_set_qdata().
939 * Returns: (transfer none) (nullable): The user data pointer set, or
943 gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
948 g_return_val_if_fail (object != NULL, NULL);
949 g_return_val_if_fail (quark > 0, NULL);
951 G_LOCK (qdata_mutex);
952 if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
953 PrivData *priv_data = object->priv_pointer;
954 result = QDATA_DATA (priv_data, i);
958 G_UNLOCK (qdata_mutex);
964 * gst_mini_object_steal_qdata:
965 * @object: The GstMiniObject to get a stored user data pointer from
966 * @quark: A #GQuark, naming the user data pointer
968 * This function gets back user data pointers stored via gst_mini_object_set_qdata()
969 * and removes the data from @object without invoking its `destroy()` function (if
972 * Returns: (transfer full) (nullable): The user data pointer set, or
976 gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
981 g_return_val_if_fail (object != NULL, NULL);
982 g_return_val_if_fail (quark > 0, NULL);
984 G_LOCK (qdata_mutex);
985 if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
986 PrivData *priv_data = object->priv_pointer;
987 result = QDATA_DATA (priv_data, i);
988 remove_notify (object, i);
992 G_UNLOCK (qdata_mutex);
998 * gst_mini_object_add_parent:
999 * @object: a #GstMiniObject
1000 * @parent: a parent #GstMiniObject
1002 * This adds @parent as a parent for @object. Having one ore more parents affects the
1003 * writability of @object: if a @parent is not writable, @object is also not
1004 * writable, regardless of its refcount. @object is only writable if all
1005 * the parents are writable and its own refcount is exactly 1.
1007 * Note: This function does not take ownership of @parent and also does not
1008 * take an additional reference. It is the responsibility of the caller to
1009 * remove the parent again at a later time.
1014 gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)
1018 g_return_if_fail (object != NULL);
1020 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "adding parent %p to object %p", parent,
1023 priv_state = lock_priv_pointer (object);
1024 /* If we already had one parent, we need to allocate the full struct now */
1025 if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
1027 g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1029 ensure_priv_data (object);
1030 priv_state = PRIV_DATA_STATE_PARENTS_OR_QDATA;
1033 /* Now we either have to add the new parent to the full struct, or add
1034 * our one and only parent to the pointer field */
1035 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
1036 PrivData *priv_data = object->priv_pointer;
1039 while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1041 if (priv_data->n_parents >= priv_data->n_parents_len) {
1042 priv_data->n_parents_len *= 2;
1043 if (priv_data->n_parents_len == 0)
1044 priv_data->n_parents_len = 16;
1046 priv_data->parents =
1047 g_realloc (priv_data->parents,
1048 priv_data->n_parents_len * sizeof (GstMiniObject *));
1050 priv_data->parents[priv_data->n_parents] = parent;
1051 priv_data->n_parents++;
1054 g_atomic_int_set (&priv_data->parent_lock, 0);
1055 } else if (priv_state == PRIV_DATA_STATE_NO_PARENT) {
1056 object->priv_pointer = parent;
1059 g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_ONE_PARENT);
1061 g_assert_not_reached ();
1066 * gst_mini_object_remove_parent:
1067 * @object: a #GstMiniObject
1068 * @parent: a parent #GstMiniObject
1070 * This removes @parent as a parent for @object. See
1071 * gst_mini_object_add_parent().
1076 gst_mini_object_remove_parent (GstMiniObject * object, GstMiniObject * parent)
1080 g_return_if_fail (object != NULL);
1082 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "removing parent %p from object %p",
1085 priv_state = lock_priv_pointer (object);
1087 /* Now we either have to add the new parent to the full struct, or add
1088 * our one and only parent to the pointer field */
1089 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
1090 PrivData *priv_data = object->priv_pointer;
1094 while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1096 for (i = 0; i < priv_data->n_parents; i++)
1097 if (parent == priv_data->parents[i])
1100 if (i != priv_data->n_parents) {
1101 priv_data->n_parents--;
1102 if (priv_data->n_parents != i)
1103 priv_data->parents[i] = priv_data->parents[priv_data->n_parents];
1105 g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1110 g_atomic_int_set (&priv_data->parent_lock, 0);
1111 } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
1112 if (object->priv_pointer != parent) {
1113 g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1116 g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1118 object->priv_pointer = NULL;
1120 g_atomic_int_set ((gint *) & object->priv_uint,
1121 PRIV_DATA_STATE_NO_PARENT);
1125 g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_NO_PARENT);