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 /* Mutex used for weak referencing */
63 G_LOCK_DEFINE_STATIC (qdata_mutex);
64 static GQuark weak_ref_quark;
66 #define SHARE_ONE (1 << 16)
67 #define SHARE_TWO (2 << 16)
68 #define SHARE_MASK (~(SHARE_ONE - 1))
69 #define IS_SHARED(state) (state >= SHARE_TWO)
70 #define LOCK_ONE (GST_LOCK_FLAG_LAST)
71 #define FLAG_MASK (GST_LOCK_FLAG_LAST - 1)
72 #define LOCK_MASK ((SHARE_ONE - 1) - FLAG_MASK)
73 #define LOCK_FLAG_MASK (SHARE_ONE - 1)
75 /* For backwards compatibility reasons we use the
76 * guint and gpointer in the GstMiniObject struct in
77 * a rather complicated way to store the parent(s) and qdata.
78 * Originally the were just the number of qdatas and the qdata.
80 * The guint is used as an atomic state integer with the following
82 * - Locked: 0, basically a spinlock
83 * - No parent, no qdata: 1 (pointer is NULL)
84 * - One parent: 2 (pointer contains the parent)
85 * - Multiple parents or qdata: 3 (pointer contains a PrivData struct)
87 * Unless we're in state 3, we always have to move to Locking state
88 * atomically and release that again later to the target state whenever
89 * accessing the pointer. When we're in state 3, we will never move to lower
92 * FIXME 2.0: We should store this directly inside the struct, possibly
93 * keeping space directly allocated for a couple of parents
98 PRIV_DATA_STATE_LOCKED = 0,
99 PRIV_DATA_STATE_NO_PARENT = 1,
100 PRIV_DATA_STATE_ONE_PARENT = 2,
101 PRIV_DATA_STATE_PARENTS_OR_QDATA = 3,
107 GstMiniObjectNotify notify;
109 GDestroyNotify destroy;
114 /* Atomic spinlock: 1 if locked, 0 otherwise */
116 guint n_parents, n_parents_len;
117 GstMiniObject **parents;
119 guint n_qdata, n_qdata_len;
123 #define QDATA(q,i) (q->qdata)[(i)]
124 #define QDATA_QUARK(o,i) (QDATA(o,i).quark)
125 #define QDATA_NOTIFY(o,i) (QDATA(o,i).notify)
126 #define QDATA_DATA(o,i) (QDATA(o,i).data)
127 #define QDATA_DESTROY(o,i) (QDATA(o,i).destroy)
130 _priv_gst_mini_object_initialize (void)
132 weak_ref_quark = g_quark_from_static_string ("GstMiniObjectWeakRefQuark");
136 * gst_mini_object_init: (skip)
137 * @mini_object: a #GstMiniObject
138 * @flags: initial #GstMiniObjectFlags
139 * @type: the #GType of the mini-object to create
140 * @copy_func: (allow-none): the copy function, or %NULL
141 * @dispose_func: (allow-none): the dispose function, or %NULL
142 * @free_func: (allow-none): the free function or %NULL
144 * Initializes a mini-object with the desired type and copy/dispose/free
148 gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
149 GstMiniObjectCopyFunction copy_func,
150 GstMiniObjectDisposeFunction dispose_func,
151 GstMiniObjectFreeFunction free_func)
153 mini_object->type = type;
154 mini_object->refcount = 1;
155 mini_object->lockstate = 0;
156 mini_object->flags = flags;
158 mini_object->copy = copy_func;
159 mini_object->dispose = dispose_func;
160 mini_object->free = free_func;
162 g_atomic_int_set ((gint *) & mini_object->priv_uint,
163 PRIV_DATA_STATE_NO_PARENT);
164 mini_object->priv_pointer = NULL;
166 GST_TRACER_MINI_OBJECT_CREATED (mini_object);
170 * gst_mini_object_copy: (skip)
171 * @mini_object: the mini-object to copy
173 * Creates a copy of the mini-object.
177 * Returns: (transfer full) (nullable): the new mini-object if copying is
178 * possible, %NULL otherwise.
181 gst_mini_object_copy (const GstMiniObject * mini_object)
185 g_return_val_if_fail (mini_object != NULL, NULL);
187 if (mini_object->copy)
188 copy = mini_object->copy (mini_object);
196 * gst_mini_object_lock:
197 * @object: the mini-object to lock
198 * @flags: #GstLockFlags
200 * Lock the mini-object with the specified access mode in @flags.
202 * Returns: %TRUE if @object could be locked.
205 gst_mini_object_lock (GstMiniObject * object, GstLockFlags flags)
207 gint access_mode, state, newstate;
209 g_return_val_if_fail (object != NULL, FALSE);
210 g_return_val_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object), FALSE);
212 if (G_UNLIKELY (object->flags & GST_MINI_OBJECT_FLAG_LOCK_READONLY &&
213 flags & GST_LOCK_FLAG_WRITE))
217 access_mode = flags & FLAG_MASK;
218 newstate = state = g_atomic_int_get (&object->lockstate);
220 GST_CAT_TRACE (GST_CAT_LOCKING, "lock %p: state %08x, access_mode %d",
221 object, state, access_mode);
223 if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
225 newstate += SHARE_ONE;
226 access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
229 /* shared counter > 1 and write access is not allowed */
230 if (((state & GST_LOCK_FLAG_WRITE) != 0
231 || (access_mode & GST_LOCK_FLAG_WRITE) != 0)
232 && IS_SHARED (newstate))
236 if ((state & LOCK_FLAG_MASK) == 0) {
237 /* nothing mapped, set access_mode */
238 newstate |= access_mode;
240 /* access_mode must match */
241 if ((state & access_mode) != access_mode)
244 /* increase refcount */
245 newstate += LOCK_ONE;
247 } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
254 GST_CAT_DEBUG (GST_CAT_LOCKING,
255 "lock failed %p: state %08x, access_mode %d", object, state,
262 * gst_mini_object_unlock:
263 * @object: the mini-object to unlock
264 * @flags: #GstLockFlags
266 * Unlock the mini-object with the specified access mode in @flags.
269 gst_mini_object_unlock (GstMiniObject * object, GstLockFlags flags)
271 gint access_mode, state, newstate;
273 g_return_if_fail (object != NULL);
274 g_return_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object));
277 access_mode = flags & FLAG_MASK;
278 newstate = state = g_atomic_int_get (&object->lockstate);
280 GST_CAT_TRACE (GST_CAT_LOCKING, "unlock %p: state %08x, access_mode %d",
281 object, state, access_mode);
283 if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
285 g_return_if_fail (state >= SHARE_ONE);
286 newstate -= SHARE_ONE;
287 access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
291 g_return_if_fail ((state & access_mode) == access_mode);
292 /* decrease the refcount */
293 newstate -= LOCK_ONE;
294 /* last refcount, unset access_mode */
295 if ((newstate & LOCK_FLAG_MASK) == access_mode)
296 newstate &= ~LOCK_FLAG_MASK;
298 } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
302 /* Locks the priv pointer and sets the priv uint to PRIV_DATA_STATE_LOCKED,
303 * unless the full struct was already stored in the priv pointer.
305 * Returns the previous state of the priv uint
308 lock_priv_pointer (GstMiniObject * object)
310 gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
312 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
313 /* As long as the struct was not allocated yet and either someone else
314 * locked it or our priv_state is out of date, try to lock it */
315 while (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA &&
316 (priv_state == PRIV_DATA_STATE_LOCKED ||
317 !g_atomic_int_compare_and_exchange ((gint *) & object->priv_uint,
318 priv_state, PRIV_DATA_STATE_LOCKED)))
319 priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
321 /* Note that if we got the full struct, we did not store
322 * PRIV_DATA_STATE_LOCKED and did not actually lock the priv pointer */
329 * gst_mini_object_is_writable:
330 * @mini_object: the mini-object to check
332 * If @mini_object has the LOCKABLE flag set, check if the current EXCLUSIVE
333 * lock on @object is the only one, this means that changes to the object will
334 * not be visible to any other object.
336 * If the LOCKABLE flag is not set, check if the refcount of @mini_object is
337 * exactly 1, meaning that no other reference exists to the object and that the
338 * object is therefore writable.
340 * Modification of a mini-object should only be done after verifying that it
343 * Returns: %TRUE if the object is writable.
346 gst_mini_object_is_writable (const GstMiniObject * mini_object)
351 g_return_val_if_fail (mini_object != NULL, FALSE);
353 /* Let's first check our own writability. If this already fails there's
354 * no point in checking anything else */
355 if (GST_MINI_OBJECT_IS_LOCKABLE (mini_object)) {
356 result = !IS_SHARED (g_atomic_int_get (&mini_object->lockstate));
358 result = (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
363 /* We are writable ourselves, but are there parents and are they all
365 priv_state = lock_priv_pointer (GST_MINI_OBJECT_CAST (mini_object));
367 /* Now we either have to check the full struct and all the
368 * parents in there, or if there is exactly one parent we
369 * can check that one */
370 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
371 PrivData *priv_data = mini_object->priv_pointer;
374 while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
376 /* If we have one parent, we're only writable if that parent is writable.
377 * Otherwise if we have multiple parents we are not writable, and if
378 * we have no parent, we are writable */
379 if (priv_data->n_parents == 1)
380 result = gst_mini_object_is_writable (priv_data->parents[0]);
381 else if (priv_data->n_parents == 0)
387 g_atomic_int_set (&priv_data->parent_lock, 0);
389 if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
390 result = gst_mini_object_is_writable (mini_object->priv_pointer);
392 g_assert (priv_state == PRIV_DATA_STATE_NO_PARENT);
397 g_atomic_int_set ((gint *) & mini_object->priv_uint, priv_state);
404 * gst_mini_object_make_writable: (skip)
405 * @mini_object: (transfer full): the mini-object to make writable
407 * Checks if a mini-object is writable. If not, a writable copy is made and
408 * returned. This gives away the reference to the original mini object,
409 * and returns a reference to the new object.
413 * Returns: (transfer full): a mini-object (possibly the same pointer) that
417 gst_mini_object_make_writable (GstMiniObject * mini_object)
421 g_return_val_if_fail (mini_object != NULL, NULL);
423 if (gst_mini_object_is_writable (mini_object)) {
426 ret = gst_mini_object_copy (mini_object);
427 GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject %p -> %p",
428 g_type_name (GST_MINI_OBJECT_TYPE (mini_object)), mini_object, ret);
429 gst_mini_object_unref (mini_object);
436 * gst_mini_object_ref: (skip)
437 * @mini_object: the mini-object
439 * Increase the reference count of the mini-object.
441 * Note that the refcount affects the writability
442 * of @mini-object, see gst_mini_object_is_writable(). It is
443 * important to note that keeping additional references to
444 * GstMiniObject instances can potentially increase the number
445 * of memcpy operations in a pipeline, especially if the miniobject
448 * Returns: (transfer full): the mini-object.
451 gst_mini_object_ref (GstMiniObject * mini_object)
453 gint old_refcount, new_refcount;
455 g_return_val_if_fail (mini_object != NULL, NULL);
456 /* we can't assert that the refcount > 0 since the _free functions
457 * increments the refcount from 0 to 1 again to allow resurrecting
459 g_return_val_if_fail (mini_object->refcount > 0, NULL);
462 old_refcount = g_atomic_int_add (&mini_object->refcount, 1);
463 new_refcount = old_refcount + 1;
465 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
466 old_refcount, new_refcount);
468 GST_TRACER_MINI_OBJECT_REFFED (mini_object, new_refcount);
473 /* Called with global qdata lock */
475 find_notify (GstMiniObject * object, GQuark quark, gboolean match_notify,
476 GstMiniObjectNotify notify, gpointer data)
479 gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
482 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA)
485 priv_data = object->priv_pointer;
487 for (i = 0; i < priv_data->n_qdata; i++) {
488 if (QDATA_QUARK (priv_data, i) == quark) {
489 /* check if we need to match the callback too */
490 if (!match_notify || (QDATA_NOTIFY (priv_data, i) == notify &&
491 QDATA_DATA (priv_data, i) == data))
499 remove_notify (GstMiniObject * object, gint index)
501 gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
504 g_assert (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA);
505 priv_data = object->priv_pointer;
508 priv_data->n_qdata--;
509 if (index != priv_data->n_qdata) {
510 QDATA (priv_data, index) = QDATA (priv_data, priv_data->n_qdata);
514 /* Make sure we allocate the PrivData of this object if not happened yet */
516 ensure_priv_data (GstMiniObject * object)
520 GstMiniObject *parent = NULL;
522 GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
523 "allocating private data %s miniobject %p",
524 g_type_name (GST_MINI_OBJECT_TYPE (object)), object);
526 priv_state = lock_priv_pointer (object);
527 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA)
530 /* Now we're either locked, or someone has already allocated the struct
531 * before us and we can just go ahead
533 * Note: if someone else allocated it in the meantime, we don't have to
534 * unlock as we didn't lock! */
535 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
536 if (priv_state == PRIV_DATA_STATE_ONE_PARENT)
537 parent = object->priv_pointer;
539 object->priv_pointer = priv_data = g_new0 (PrivData, 1);
542 priv_data->parents = g_new (GstMiniObject *, 16);
543 priv_data->n_parents_len = 16;
544 priv_data->n_parents = 1;
545 priv_data->parents[0] = parent;
549 g_atomic_int_set ((gint *) & object->priv_uint,
550 PRIV_DATA_STATE_PARENTS_OR_QDATA);
555 set_notify (GstMiniObject * object, gint index, GQuark quark,
556 GstMiniObjectNotify notify, gpointer data, GDestroyNotify destroy)
560 ensure_priv_data (object);
561 priv_data = object->priv_pointer;
565 index = priv_data->n_qdata++;
566 if (index >= priv_data->n_qdata_len) {
567 priv_data->n_qdata_len *= 2;
568 if (priv_data->n_qdata_len == 0)
569 priv_data->n_qdata_len = 16;
572 g_realloc (priv_data->qdata,
573 sizeof (GstQData) * priv_data->n_qdata_len);
577 QDATA_QUARK (priv_data, index) = quark;
578 QDATA_NOTIFY (priv_data, index) = notify;
579 QDATA_DATA (priv_data, index) = data;
580 QDATA_DESTROY (priv_data, index) = destroy;
584 free_priv_data (GstMiniObject * obj)
587 gint priv_state = g_atomic_int_get ((gint *) & obj->priv_uint);
590 if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
591 if (priv_state == PRIV_DATA_STATE_LOCKED) {
593 ("%s: object finalizing but has locked private data (object:%p)",
595 } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
597 ("%s: object finalizing but still has parent (object:%p, parent:%p)",
598 G_STRFUNC, obj, obj->priv_pointer);
604 priv_data = obj->priv_pointer;
606 for (i = 0; i < priv_data->n_qdata; i++) {
607 if (QDATA_QUARK (priv_data, i) == weak_ref_quark)
608 QDATA_NOTIFY (priv_data, i) (QDATA_DATA (priv_data, i), obj);
609 if (QDATA_DESTROY (priv_data, i))
610 QDATA_DESTROY (priv_data, i) (QDATA_DATA (priv_data, i));
612 g_free (priv_data->qdata);
614 if (priv_data->n_parents)
615 g_warning ("%s: object finalizing but still has %d parents (object:%p)",
616 G_STRFUNC, priv_data->n_parents, obj);
617 g_free (priv_data->parents);
623 * gst_mini_object_unref: (skip)
624 * @mini_object: the mini-object
626 * Decreases the reference count of the mini-object, possibly freeing
630 gst_mini_object_unref (GstMiniObject * mini_object)
632 gint old_refcount, new_refcount;
634 g_return_if_fail (mini_object != NULL);
635 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) > 0);
637 old_refcount = g_atomic_int_add (&mini_object->refcount, -1);
638 new_refcount = old_refcount - 1;
640 g_return_if_fail (old_refcount > 0);
642 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
643 mini_object, old_refcount, new_refcount);
645 GST_TRACER_MINI_OBJECT_UNREFFED (mini_object, new_refcount);
647 if (new_refcount == 0) {
650 if (mini_object->dispose)
651 do_free = mini_object->dispose (mini_object);
655 /* if the subclass recycled the object (and returned FALSE) we don't
656 * want to free the instance anymore */
657 if (G_LIKELY (do_free)) {
658 /* there should be no outstanding locks */
659 g_return_if_fail ((g_atomic_int_get (&mini_object->lockstate) & LOCK_MASK)
662 free_priv_data (mini_object);
664 GST_TRACER_MINI_OBJECT_DESTROYED (mini_object);
665 if (mini_object->free)
666 mini_object->free (mini_object);
672 * gst_clear_mini_object: (skip)
673 * @object_ptr: a pointer to a #GstMiniObject reference
675 * Clears a reference to a #GstMiniObject.
677 * @object_ptr must not be %NULL.
679 * If the reference is %NULL then this function does nothing.
680 * Otherwise, the reference count of the object is decreased using
681 * gst_mini_object_unref() and the pointer is set to %NULL.
683 * A macro is also included that allows this function to be used without
688 #undef gst_clear_mini_object
690 gst_clear_mini_object (GstMiniObject ** object_ptr)
692 g_clear_pointer (object_ptr, gst_mini_object_unref);
696 * gst_mini_object_replace:
697 * @olddata: (inout) (transfer full) (nullable): pointer to a pointer to a
698 * mini-object to be replaced
699 * @newdata: (allow-none): pointer to new mini-object
701 * Atomically modifies a pointer to point to a new mini-object.
702 * The reference count of @olddata is decreased and the reference count of
703 * @newdata is increased.
705 * Either @newdata and the value pointed to by @olddata may be %NULL.
707 * Returns: %TRUE if @newdata was different from @olddata
710 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
712 GstMiniObject *olddata_val;
714 g_return_val_if_fail (olddata != NULL, FALSE);
716 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
717 *olddata, *olddata ? (*olddata)->refcount : 0,
718 newdata, newdata ? newdata->refcount : 0);
720 olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
722 if (G_UNLIKELY (olddata_val == newdata))
726 gst_mini_object_ref (newdata);
728 while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
729 olddata, olddata_val, newdata))) {
730 olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
731 if (G_UNLIKELY (olddata_val == newdata))
736 gst_mini_object_unref (olddata_val);
738 return olddata_val != newdata;
742 * gst_mini_object_steal: (skip)
743 * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
746 * Replace the current #GstMiniObject pointer to by @olddata with %NULL and
747 * return the old value.
749 * Returns: (nullable): the #GstMiniObject at @oldata
752 gst_mini_object_steal (GstMiniObject ** olddata)
754 GstMiniObject *olddata_val;
756 g_return_val_if_fail (olddata != NULL, NULL);
758 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
759 *olddata, *olddata ? (*olddata)->refcount : 0);
762 olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
763 if (olddata_val == NULL)
765 } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
766 olddata, olddata_val, NULL)));
772 * gst_mini_object_take:
773 * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
775 * @newdata: pointer to new mini-object
777 * Modifies a pointer to point to a new mini-object. The modification
778 * is done atomically. This version is similar to gst_mini_object_replace()
779 * except that it does not increase the refcount of @newdata and thus
780 * takes ownership of @newdata.
782 * Either @newdata and the value pointed to by @olddata may be %NULL.
784 * Returns: %TRUE if @newdata was different from @olddata
787 gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
789 GstMiniObject *olddata_val;
791 g_return_val_if_fail (olddata != NULL, FALSE);
793 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "take %p (%d) with %p (%d)",
794 *olddata, *olddata ? (*olddata)->refcount : 0,
795 newdata, newdata ? newdata->refcount : 0);
798 olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
799 if (G_UNLIKELY (olddata_val == newdata))
801 } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
802 olddata, olddata_val, newdata)));
805 gst_mini_object_unref (olddata_val);
807 return olddata_val != newdata;
811 * gst_mini_object_weak_ref: (skip)
812 * @object: #GstMiniObject to reference weakly
813 * @notify: callback to invoke before the mini object is freed
814 * @data: extra data to pass to notify
816 * Adds a weak reference callback to a mini object. Weak references are
817 * used for notification when a mini object is finalized. They are called
818 * "weak references" because they allow you to safely hold a pointer
819 * to the mini object without calling gst_mini_object_ref()
820 * (gst_mini_object_ref() adds a strong reference, that is, forces the object
824 gst_mini_object_weak_ref (GstMiniObject * object,
825 GstMiniObjectNotify notify, gpointer data)
827 g_return_if_fail (object != NULL);
828 g_return_if_fail (notify != NULL);
829 g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
831 G_LOCK (qdata_mutex);
832 set_notify (object, -1, weak_ref_quark, notify, data, NULL);
833 G_UNLOCK (qdata_mutex);
837 * gst_mini_object_weak_unref: (skip)
838 * @object: #GstMiniObject to remove a weak reference from
839 * @notify: callback to search for
840 * @data: data to search for
842 * Removes a weak reference callback from a mini object.
845 gst_mini_object_weak_unref (GstMiniObject * object,
846 GstMiniObjectNotify notify, gpointer data)
850 g_return_if_fail (object != NULL);
851 g_return_if_fail (notify != NULL);
853 G_LOCK (qdata_mutex);
854 if ((i = find_notify (object, weak_ref_quark, TRUE, notify, data)) != -1) {
855 remove_notify (object, i);
857 g_warning ("%s: couldn't find weak ref %p (object:%p data:%p)", G_STRFUNC,
858 notify, object, data);
860 G_UNLOCK (qdata_mutex);
864 * gst_mini_object_set_qdata:
865 * @object: a #GstMiniObject
866 * @quark: A #GQuark, naming the user data pointer
867 * @data: An opaque user data pointer
868 * @destroy: Function to invoke with @data as argument, when @data
871 * This sets an opaque, named pointer on a miniobject.
872 * The name is specified through a #GQuark (retrieved e.g. via
873 * g_quark_from_static_string()), and the pointer
874 * can be gotten back from the @object with gst_mini_object_get_qdata()
875 * until the @object is disposed.
876 * Setting a previously set user data pointer, overrides (frees)
877 * the old pointer set, using %NULL as pointer essentially
878 * removes the data stored.
880 * @destroy may be specified which is called with @data as argument
881 * when the @object is disposed, or the data is being overwritten by
882 * a call to gst_mini_object_set_qdata() with the same @quark.
885 gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
886 gpointer data, GDestroyNotify destroy)
889 gpointer old_data = NULL;
890 GDestroyNotify old_notify = NULL;
892 g_return_if_fail (object != NULL);
893 g_return_if_fail (quark > 0);
895 G_LOCK (qdata_mutex);
896 if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
897 PrivData *priv_data = object->priv_pointer;
899 old_data = QDATA_DATA (priv_data, i);
900 old_notify = QDATA_DESTROY (priv_data, i);
903 remove_notify (object, i);
906 set_notify (object, i, quark, NULL, data, destroy);
907 G_UNLOCK (qdata_mutex);
910 old_notify (old_data);
914 * gst_mini_object_get_qdata:
915 * @object: The GstMiniObject to get a stored user data pointer from
916 * @quark: A #GQuark, naming the user data pointer
918 * This function gets back user data pointers stored via
919 * gst_mini_object_set_qdata().
921 * Returns: (transfer none) (nullable): The user data pointer set, or
925 gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
930 g_return_val_if_fail (object != NULL, NULL);
931 g_return_val_if_fail (quark > 0, NULL);
933 G_LOCK (qdata_mutex);
934 if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
935 PrivData *priv_data = object->priv_pointer;
936 result = QDATA_DATA (priv_data, i);
940 G_UNLOCK (qdata_mutex);
946 * gst_mini_object_steal_qdata:
947 * @object: The GstMiniObject to get a stored user data pointer from
948 * @quark: A #GQuark, naming the user data pointer
950 * This function gets back user data pointers stored via gst_mini_object_set_qdata()
951 * and removes the data from @object without invoking its destroy() function (if
954 * Returns: (transfer full) (nullable): The user data pointer set, or
958 gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
963 g_return_val_if_fail (object != NULL, NULL);
964 g_return_val_if_fail (quark > 0, NULL);
966 G_LOCK (qdata_mutex);
967 if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
968 PrivData *priv_data = object->priv_pointer;
969 result = QDATA_DATA (priv_data, i);
970 remove_notify (object, i);
974 G_UNLOCK (qdata_mutex);
980 * gst_mini_object_add_parent:
981 * @object: a #GstMiniObject
982 * @parent: a parent #GstMiniObject
984 * This adds @parent as a parent for @object. Having one ore more parents affects the
985 * writability of @object: if a @parent is not writable, @object is also not
986 * writable, regardless of its refcount. @object is only writable if all
987 * the parents are writable and its own refcount is exactly 1.
989 * Note: This function does not take ownership of @parent and also does not
990 * take an additional reference. It is the responsibility of the caller to
991 * remove the parent again at a later time.
996 gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)
1000 g_return_if_fail (object != NULL);
1002 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "adding parent %p to object %p", parent,
1005 priv_state = lock_priv_pointer (object);
1006 /* If we already had one parent, we need to allocate the full struct now */
1007 if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
1009 g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1011 ensure_priv_data (object);
1012 priv_state = PRIV_DATA_STATE_PARENTS_OR_QDATA;
1015 /* Now we either have to add the new parent to the full struct, or add
1016 * our one and only parent to the pointer field */
1017 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
1018 PrivData *priv_data = object->priv_pointer;
1021 while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1023 if (priv_data->n_parents >= priv_data->n_parents_len) {
1024 priv_data->n_parents_len *= 2;
1025 if (priv_data->n_parents_len == 0)
1026 priv_data->n_parents_len = 16;
1028 priv_data->parents =
1029 g_realloc (priv_data->parents,
1030 priv_data->n_parents_len * sizeof (GstMiniObject *));
1032 priv_data->parents[priv_data->n_parents] = parent;
1033 priv_data->n_parents++;
1036 g_atomic_int_set (&priv_data->parent_lock, 0);
1037 } else if (priv_state == PRIV_DATA_STATE_NO_PARENT) {
1038 object->priv_pointer = parent;
1041 g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_ONE_PARENT);
1043 g_assert_not_reached ();
1048 * gst_mini_object_remove_parent:
1049 * @object: a #GstMiniObject
1050 * @parent: a parent #GstMiniObject
1052 * This removes @parent as a parent for @object. See
1053 * gst_mini_object_add_parent().
1058 gst_mini_object_remove_parent (GstMiniObject * object, GstMiniObject * parent)
1062 g_return_if_fail (object != NULL);
1064 GST_CAT_TRACE (GST_CAT_REFCOUNTING, "removing parent %p from object %p",
1067 priv_state = lock_priv_pointer (object);
1069 /* Now we either have to add the new parent to the full struct, or add
1070 * our one and only parent to the pointer field */
1071 if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
1072 PrivData *priv_data = object->priv_pointer;
1076 while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1078 for (i = 0; i < priv_data->n_parents; i++)
1079 if (parent == priv_data->parents[i])
1082 if (i != priv_data->n_parents) {
1083 priv_data->n_parents--;
1084 if (priv_data->n_parents != i)
1085 priv_data->parents[i] = priv_data->parents[priv_data->n_parents];
1087 g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1092 g_atomic_int_set (&priv_data->parent_lock, 0);
1093 } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
1094 if (object->priv_pointer != parent) {
1095 g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1098 g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1100 object->priv_pointer = NULL;
1102 g_atomic_int_set ((gint *) & object->priv_uint,
1103 PRIV_DATA_STATE_NO_PARENT);
1107 g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_NO_PARENT);