tee: Check for the removed pad flag also in the slow pushing path
[platform/upstream/gstreamer.git] / gst / gstminiobject.c
1 /* GStreamer
2  * Copyright (C) 2005 David Schleef <ds@schleef.org>
3  *
4  * gstminiobject.h: Header for GstMiniObject
5  *
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.
10  *
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.
15  *
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.
20  */
21 /**
22  * SECTION:gstminiobject
23  * @title: GstMiniObject
24  * @short_description: Lightweight base class for the GStreamer object hierarchy
25  *
26  * #GstMiniObject is a simple structure that can be used to implement refcounted
27  * types.
28  *
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.
31  *
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.
36  *
37  * A copy can be made with gst_mini_object_copy().
38  *
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.
44  *
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.
49  *
50  * A weak reference can be added and remove with gst_mini_object_weak_ref()
51  * and gst_mini_object_weak_unref() respectively.
52  */
53 #ifdef HAVE_CONFIG_H
54 #include "config.h"
55 #endif
56
57 #include "gst/gst_private.h"
58 #include "gst/gstminiobject.h"
59 #include "gst/gstinfo.h"
60 #include <gobject/gvaluecollector.h>
61
62 /* Mutex used for weak referencing */
63 G_LOCK_DEFINE_STATIC (qdata_mutex);
64 static GQuark weak_ref_quark;
65
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)
74
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.
79  *
80  * The guint is used as an atomic state integer with the following
81  * states:
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)
86  *
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
90  * states again
91  *
92  * FIXME 2.0: We should store this directly inside the struct, possibly
93  * keeping space directly allocated for a couple of parents
94  */
95
96 enum
97 {
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,
102 };
103
104 typedef struct
105 {
106   GQuark quark;
107   GstMiniObjectNotify notify;
108   gpointer data;
109   GDestroyNotify destroy;
110 } GstQData;
111
112 typedef struct
113 {
114   /* Atomic spinlock: 1 if locked, 0 otherwise */
115   gint parent_lock;
116   guint n_parents, n_parents_len;
117   GstMiniObject **parents;
118
119   guint n_qdata, n_qdata_len;
120   GstQData *qdata;
121 } PrivData;
122
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)
128
129 void
130 _priv_gst_mini_object_initialize (void)
131 {
132   weak_ref_quark = g_quark_from_static_string ("GstMiniObjectWeakRefQuark");
133 }
134
135 /**
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
143  *
144  * Initializes a mini-object with the desired type and copy/dispose/free
145  * functions.
146  */
147 void
148 gst_mini_object_init (GstMiniObject * mini_object, guint flags, GType type,
149     GstMiniObjectCopyFunction copy_func,
150     GstMiniObjectDisposeFunction dispose_func,
151     GstMiniObjectFreeFunction free_func)
152 {
153   mini_object->type = type;
154   mini_object->refcount = 1;
155   mini_object->lockstate = 0;
156   mini_object->flags = flags;
157
158   mini_object->copy = copy_func;
159   mini_object->dispose = dispose_func;
160   mini_object->free = free_func;
161
162   g_atomic_int_set ((gint *) & mini_object->priv_uint,
163       PRIV_DATA_STATE_NO_PARENT);
164   mini_object->priv_pointer = NULL;
165
166   GST_TRACER_MINI_OBJECT_CREATED (mini_object);
167 }
168
169 /**
170  * gst_mini_object_copy: (skip)
171  * @mini_object: the mini-object to copy
172  *
173  * Creates a copy of the mini-object.
174  *
175  * MT safe
176  *
177  * Returns: (transfer full) (nullable): the new mini-object if copying is
178  * possible, %NULL otherwise.
179  */
180 GstMiniObject *
181 gst_mini_object_copy (const GstMiniObject * mini_object)
182 {
183   GstMiniObject *copy;
184
185   g_return_val_if_fail (mini_object != NULL, NULL);
186
187   if (mini_object->copy)
188     copy = mini_object->copy (mini_object);
189   else
190     copy = NULL;
191
192   return copy;
193 }
194
195 /**
196  * gst_mini_object_lock:
197  * @object: the mini-object to lock
198  * @flags: #GstLockFlags
199  *
200  * Lock the mini-object with the specified access mode in @flags.
201  *
202  * Returns: %TRUE if @object could be locked.
203  */
204 gboolean
205 gst_mini_object_lock (GstMiniObject * object, GstLockFlags flags)
206 {
207   gint access_mode, state, newstate;
208
209   g_return_val_if_fail (object != NULL, FALSE);
210   g_return_val_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object), FALSE);
211
212   if (G_UNLIKELY (object->flags & GST_MINI_OBJECT_FLAG_LOCK_READONLY &&
213           flags & GST_LOCK_FLAG_WRITE))
214     return FALSE;
215
216   do {
217     access_mode = flags & FLAG_MASK;
218     newstate = state = g_atomic_int_get (&object->lockstate);
219
220     GST_CAT_TRACE (GST_CAT_LOCKING, "lock %p: state %08x, access_mode %d",
221         object, state, access_mode);
222
223     if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
224       /* shared ref */
225       newstate += SHARE_ONE;
226       access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
227     }
228
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))
233       goto lock_failed;
234
235     if (access_mode) {
236       if ((state & LOCK_FLAG_MASK) == 0) {
237         /* nothing mapped, set access_mode */
238         newstate |= access_mode;
239       } else {
240         /* access_mode must match */
241         if ((state & access_mode) != access_mode)
242           goto lock_failed;
243       }
244       /* increase refcount */
245       newstate += LOCK_ONE;
246     }
247   } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
248           newstate));
249
250   return TRUE;
251
252 lock_failed:
253   {
254     GST_CAT_DEBUG (GST_CAT_LOCKING,
255         "lock failed %p: state %08x, access_mode %d", object, state,
256         access_mode);
257     return FALSE;
258   }
259 }
260
261 /**
262  * gst_mini_object_unlock:
263  * @object: the mini-object to unlock
264  * @flags: #GstLockFlags
265  *
266  * Unlock the mini-object with the specified access mode in @flags.
267  */
268 void
269 gst_mini_object_unlock (GstMiniObject * object, GstLockFlags flags)
270 {
271   gint access_mode, state, newstate;
272
273   g_return_if_fail (object != NULL);
274   g_return_if_fail (GST_MINI_OBJECT_IS_LOCKABLE (object));
275
276   do {
277     access_mode = flags & FLAG_MASK;
278     newstate = state = g_atomic_int_get (&object->lockstate);
279
280     GST_CAT_TRACE (GST_CAT_LOCKING, "unlock %p: state %08x, access_mode %d",
281         object, state, access_mode);
282
283     if (access_mode & GST_LOCK_FLAG_EXCLUSIVE) {
284       /* shared counter */
285       g_return_if_fail (state >= SHARE_ONE);
286       newstate -= SHARE_ONE;
287       access_mode &= ~GST_LOCK_FLAG_EXCLUSIVE;
288     }
289
290     if (access_mode) {
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;
297     }
298   } while (!g_atomic_int_compare_and_exchange (&object->lockstate, state,
299           newstate));
300 }
301
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.
304  *
305  * Returns the previous state of the priv uint
306  */
307 static guint
308 lock_priv_pointer (GstMiniObject * object)
309 {
310   gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
311
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);
320
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 */
323   }
324
325   return priv_state;
326 }
327
328 /**
329  * gst_mini_object_is_writable:
330  * @mini_object: the mini-object to check
331  *
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.
335  *
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.
339  *
340  * Modification of a mini-object should only be done after verifying that it
341  * is writable.
342  *
343  * Returns: %TRUE if the object is writable.
344  */
345 gboolean
346 gst_mini_object_is_writable (const GstMiniObject * mini_object)
347 {
348   gboolean result;
349   gint priv_state;
350
351   g_return_val_if_fail (mini_object != NULL, FALSE);
352
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));
357   } else {
358     result = (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
359   }
360   if (!result)
361     return result;
362
363   /* We are writable ourselves, but are there parents and are they all
364    * writable too? */
365   priv_state = lock_priv_pointer (GST_MINI_OBJECT_CAST (mini_object));
366
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;
372
373     /* Lock parents */
374     while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
375
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)
382       result = TRUE;
383     else
384       result = FALSE;
385
386     /* Unlock again */
387     g_atomic_int_set (&priv_data->parent_lock, 0);
388   } else {
389     if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
390       result = gst_mini_object_is_writable (mini_object->priv_pointer);
391     } else {
392       g_assert (priv_state == PRIV_DATA_STATE_NO_PARENT);
393       result = TRUE;
394     }
395
396     /* Unlock again */
397     g_atomic_int_set ((gint *) & mini_object->priv_uint, priv_state);
398   }
399
400   return result;
401 }
402
403 /**
404  * gst_mini_object_make_writable: (skip)
405  * @mini_object: (transfer full): the mini-object to make writable
406  *
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.
410  *
411  * MT safe
412  *
413  * Returns: (transfer full): a mini-object (possibly the same pointer) that
414  *     is writable.
415  */
416 GstMiniObject *
417 gst_mini_object_make_writable (GstMiniObject * mini_object)
418 {
419   GstMiniObject *ret;
420
421   g_return_val_if_fail (mini_object != NULL, NULL);
422
423   if (gst_mini_object_is_writable (mini_object)) {
424     ret = mini_object;
425   } else {
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);
430   }
431
432   return ret;
433 }
434
435 /**
436  * gst_mini_object_ref: (skip)
437  * @mini_object: the mini-object
438  *
439  * Increase the reference count of the mini-object.
440  *
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
446  * is a #GstBuffer.
447  *
448  * Returns: (transfer full): the mini-object.
449  */
450 GstMiniObject *
451 gst_mini_object_ref (GstMiniObject * mini_object)
452 {
453   gint old_refcount, new_refcount;
454
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
458    * the object
459    g_return_val_if_fail (mini_object->refcount > 0, NULL);
460    */
461
462   old_refcount = g_atomic_int_add (&mini_object->refcount, 1);
463   new_refcount = old_refcount + 1;
464
465   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
466       old_refcount, new_refcount);
467
468   GST_TRACER_MINI_OBJECT_REFFED (mini_object, new_refcount);
469
470   return mini_object;
471 }
472
473 /* Called with global qdata lock */
474 static gint
475 find_notify (GstMiniObject * object, GQuark quark, gboolean match_notify,
476     GstMiniObjectNotify notify, gpointer data)
477 {
478   guint i;
479   gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
480   PrivData *priv_data;
481
482   if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA)
483     return -1;
484
485   priv_data = object->priv_pointer;
486
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))
492         return i;
493     }
494   }
495   return -1;
496 }
497
498 static void
499 remove_notify (GstMiniObject * object, gint index)
500 {
501   gint priv_state = g_atomic_int_get ((gint *) & object->priv_uint);
502   PrivData *priv_data;
503
504   g_assert (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA);
505   priv_data = object->priv_pointer;
506
507   /* remove item */
508   priv_data->n_qdata--;
509   if (priv_data->n_qdata == 0) {
510     /* we don't shrink but free when everything is gone */
511     g_free (priv_data->qdata);
512     priv_data->qdata = NULL;
513     priv_data->n_qdata_len = 0;
514   } else if (index != priv_data->n_qdata) {
515     QDATA (priv_data, index) = QDATA (priv_data, priv_data->n_qdata);
516   }
517 }
518
519 /* Make sure we allocate the PrivData of this object if not happened yet */
520 static void
521 ensure_priv_data (GstMiniObject * object)
522 {
523   gint priv_state;
524   PrivData *priv_data;
525   GstMiniObject *parent = NULL;
526
527   GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
528       "allocating private data %s miniobject %p",
529       g_type_name (GST_MINI_OBJECT_TYPE (object)), object);
530
531   priv_state = lock_priv_pointer (object);
532   if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA)
533     return;
534
535   /* Now we're either locked, or someone has already allocated the struct
536    * before us and we can just go ahead
537    *
538    * Note: if someone else allocated it in the meantime, we don't have to
539    * unlock as we didn't lock! */
540   if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
541     if (priv_state == PRIV_DATA_STATE_ONE_PARENT)
542       parent = object->priv_pointer;
543
544     object->priv_pointer = priv_data = g_new0 (PrivData, 1);
545
546     if (parent) {
547       priv_data->parents = g_new (GstMiniObject *, 16);
548       priv_data->n_parents_len = 16;
549       priv_data->n_parents = 1;
550       priv_data->parents[0] = parent;
551     }
552
553     /* Unlock */
554     g_atomic_int_set ((gint *) & object->priv_uint,
555         PRIV_DATA_STATE_PARENTS_OR_QDATA);
556   }
557 }
558
559 static void
560 set_notify (GstMiniObject * object, gint index, GQuark quark,
561     GstMiniObjectNotify notify, gpointer data, GDestroyNotify destroy)
562 {
563   PrivData *priv_data;
564
565   ensure_priv_data (object);
566   priv_data = object->priv_pointer;
567
568   if (index == -1) {
569     /* add item */
570     index = priv_data->n_qdata++;
571     if (index >= priv_data->n_qdata_len) {
572       priv_data->n_qdata_len *= 2;
573       if (priv_data->n_qdata_len == 0)
574         priv_data->n_qdata_len = 16;
575
576       priv_data->qdata =
577           g_realloc (priv_data->qdata,
578           sizeof (GstQData) * priv_data->n_qdata_len);
579     }
580   }
581
582   QDATA_QUARK (priv_data, index) = quark;
583   QDATA_NOTIFY (priv_data, index) = notify;
584   QDATA_DATA (priv_data, index) = data;
585   QDATA_DESTROY (priv_data, index) = destroy;
586 }
587
588 static void
589 free_priv_data (GstMiniObject * obj)
590 {
591   guint i;
592   gint priv_state = g_atomic_int_get ((gint *) & obj->priv_uint);
593   PrivData *priv_data;
594
595   if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
596     if (priv_state == PRIV_DATA_STATE_LOCKED) {
597       g_warning
598           ("%s: object finalizing but has locked private data (object:%p)",
599           G_STRFUNC, obj);
600     } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
601       g_warning
602           ("%s: object finalizing but still has parent (object:%p, parent:%p)",
603           G_STRFUNC, obj, obj->priv_pointer);
604     }
605
606     return;
607   }
608
609   priv_data = obj->priv_pointer;
610
611   for (i = 0; i < priv_data->n_qdata; i++) {
612     if (QDATA_QUARK (priv_data, i) == weak_ref_quark)
613       QDATA_NOTIFY (priv_data, i) (QDATA_DATA (priv_data, i), obj);
614     if (QDATA_DESTROY (priv_data, i))
615       QDATA_DESTROY (priv_data, i) (QDATA_DATA (priv_data, i));
616   }
617   g_free (priv_data->qdata);
618
619   if (priv_data->n_parents)
620     g_warning ("%s: object finalizing but still has %d parents (object:%p)",
621         G_STRFUNC, priv_data->n_parents, obj);
622   g_free (priv_data->parents);
623
624   g_free (priv_data);
625 }
626
627 /**
628  * gst_mini_object_unref: (skip)
629  * @mini_object: the mini-object
630  *
631  * Decreases the reference count of the mini-object, possibly freeing
632  * the mini-object.
633  */
634 void
635 gst_mini_object_unref (GstMiniObject * mini_object)
636 {
637   gint old_refcount, new_refcount;
638
639   g_return_if_fail (mini_object != NULL);
640   g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) > 0);
641
642   old_refcount = g_atomic_int_add (&mini_object->refcount, -1);
643   new_refcount = old_refcount - 1;
644
645   g_return_if_fail (old_refcount > 0);
646
647   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
648       mini_object, old_refcount, new_refcount);
649
650   GST_TRACER_MINI_OBJECT_UNREFFED (mini_object, new_refcount);
651
652   if (new_refcount == 0) {
653     gboolean do_free;
654
655     if (mini_object->dispose)
656       do_free = mini_object->dispose (mini_object);
657     else
658       do_free = TRUE;
659
660     /* if the subclass recycled the object (and returned FALSE) we don't
661      * want to free the instance anymore */
662     if (G_LIKELY (do_free)) {
663       /* there should be no outstanding locks */
664       g_return_if_fail ((g_atomic_int_get (&mini_object->lockstate) & LOCK_MASK)
665           < 4);
666
667       free_priv_data (mini_object);
668
669       GST_TRACER_MINI_OBJECT_DESTROYED (mini_object);
670       if (mini_object->free)
671         mini_object->free (mini_object);
672     }
673   }
674 }
675
676 /**
677  * gst_clear_mini_object: (skip)
678  * @object_ptr: a pointer to a #GstMiniObject reference
679  *
680  * Clears a reference to a #GstMiniObject.
681  *
682  * @object_ptr must not be %NULL.
683  *
684  * If the reference is %NULL then this function does nothing.
685  * Otherwise, the reference count of the object is decreased using
686  * gst_mini_object_unref() and the pointer is set to %NULL.
687  *
688  * A macro is also included that allows this function to be used without
689  * pointer casts.
690  *
691  * Since: 1.16
692  **/
693 #undef gst_clear_mini_object
694 void
695 gst_clear_mini_object (GstMiniObject ** object_ptr)
696 {
697   g_clear_pointer (object_ptr, gst_mini_object_unref);
698 }
699
700 /**
701  * gst_mini_object_replace:
702  * @olddata: (inout) (transfer full) (nullable): pointer to a pointer to a
703  *     mini-object to be replaced
704  * @newdata: (allow-none): pointer to new mini-object
705  *
706  * Atomically modifies a pointer to point to a new mini-object.
707  * The reference count of @olddata is decreased and the reference count of
708  * @newdata is increased.
709  *
710  * Either @newdata and the value pointed to by @olddata may be %NULL.
711  *
712  * Returns: %TRUE if @newdata was different from @olddata
713  */
714 gboolean
715 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
716 {
717   GstMiniObject *olddata_val;
718
719   g_return_val_if_fail (olddata != NULL, FALSE);
720
721   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
722       *olddata, *olddata ? (*olddata)->refcount : 0,
723       newdata, newdata ? newdata->refcount : 0);
724
725   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
726
727   if (G_UNLIKELY (olddata_val == newdata))
728     return FALSE;
729
730   if (newdata)
731     gst_mini_object_ref (newdata);
732
733   while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
734               olddata, olddata_val, newdata))) {
735     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
736     if (G_UNLIKELY (olddata_val == newdata))
737       break;
738   }
739
740   if (olddata_val)
741     gst_mini_object_unref (olddata_val);
742
743   return olddata_val != newdata;
744 }
745
746 /**
747  * gst_mini_object_steal: (skip)
748  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
749  *     be stolen
750  *
751  * Replace the current #GstMiniObject pointer to by @olddata with %NULL and
752  * return the old value.
753  *
754  * Returns: (nullable): the #GstMiniObject at @oldata
755  */
756 GstMiniObject *
757 gst_mini_object_steal (GstMiniObject ** olddata)
758 {
759   GstMiniObject *olddata_val;
760
761   g_return_val_if_fail (olddata != NULL, NULL);
762
763   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
764       *olddata, *olddata ? (*olddata)->refcount : 0);
765
766   do {
767     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
768     if (olddata_val == NULL)
769       break;
770   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
771               olddata, olddata_val, NULL)));
772
773   return olddata_val;
774 }
775
776 /**
777  * gst_mini_object_take:
778  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
779  *     be replaced
780  * @newdata: pointer to new mini-object
781  *
782  * Modifies a pointer to point to a new mini-object. The modification
783  * is done atomically. This version is similar to gst_mini_object_replace()
784  * except that it does not increase the refcount of @newdata and thus
785  * takes ownership of @newdata.
786  *
787  * Either @newdata and the value pointed to by @olddata may be %NULL.
788  *
789  * Returns: %TRUE if @newdata was different from @olddata
790  */
791 gboolean
792 gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
793 {
794   GstMiniObject *olddata_val;
795
796   g_return_val_if_fail (olddata != NULL, FALSE);
797
798   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "take %p (%d) with %p (%d)",
799       *olddata, *olddata ? (*olddata)->refcount : 0,
800       newdata, newdata ? newdata->refcount : 0);
801
802   do {
803     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
804     if (G_UNLIKELY (olddata_val == newdata))
805       break;
806   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
807               olddata, olddata_val, newdata)));
808
809   if (olddata_val)
810     gst_mini_object_unref (olddata_val);
811
812   return olddata_val != newdata;
813 }
814
815 /**
816  * gst_mini_object_weak_ref: (skip)
817  * @object: #GstMiniObject to reference weakly
818  * @notify: callback to invoke before the mini object is freed
819  * @data: extra data to pass to notify
820  *
821  * Adds a weak reference callback to a mini object. Weak references are
822  * used for notification when a mini object is finalized. They are called
823  * "weak references" because they allow you to safely hold a pointer
824  * to the mini object without calling gst_mini_object_ref()
825  * (gst_mini_object_ref() adds a strong reference, that is, forces the object
826  * to stay alive).
827  */
828 void
829 gst_mini_object_weak_ref (GstMiniObject * object,
830     GstMiniObjectNotify notify, gpointer data)
831 {
832   g_return_if_fail (object != NULL);
833   g_return_if_fail (notify != NULL);
834   g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
835
836   G_LOCK (qdata_mutex);
837   set_notify (object, -1, weak_ref_quark, notify, data, NULL);
838   G_UNLOCK (qdata_mutex);
839 }
840
841 /**
842  * gst_mini_object_weak_unref: (skip)
843  * @object: #GstMiniObject to remove a weak reference from
844  * @notify: callback to search for
845  * @data: data to search for
846  *
847  * Removes a weak reference callback from a mini object.
848  */
849 void
850 gst_mini_object_weak_unref (GstMiniObject * object,
851     GstMiniObjectNotify notify, gpointer data)
852 {
853   gint i;
854
855   g_return_if_fail (object != NULL);
856   g_return_if_fail (notify != NULL);
857
858   G_LOCK (qdata_mutex);
859   if ((i = find_notify (object, weak_ref_quark, TRUE, notify, data)) != -1) {
860     remove_notify (object, i);
861   } else {
862     g_warning ("%s: couldn't find weak ref %p (object:%p data:%p)", G_STRFUNC,
863         notify, object, data);
864   }
865   G_UNLOCK (qdata_mutex);
866 }
867
868 /**
869  * gst_mini_object_set_qdata:
870  * @object: a #GstMiniObject
871  * @quark: A #GQuark, naming the user data pointer
872  * @data: An opaque user data pointer
873  * @destroy: Function to invoke with @data as argument, when @data
874  *           needs to be freed
875  *
876  * This sets an opaque, named pointer on a miniobject.
877  * The name is specified through a #GQuark (retrieved e.g. via
878  * g_quark_from_static_string()), and the pointer
879  * can be gotten back from the @object with gst_mini_object_get_qdata()
880  * until the @object is disposed.
881  * Setting a previously set user data pointer, overrides (frees)
882  * the old pointer set, using %NULL as pointer essentially
883  * removes the data stored.
884  *
885  * @destroy may be specified which is called with @data as argument
886  * when the @object is disposed, or the data is being overwritten by
887  * a call to gst_mini_object_set_qdata() with the same @quark.
888  */
889 void
890 gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
891     gpointer data, GDestroyNotify destroy)
892 {
893   gint i;
894   gpointer old_data = NULL;
895   GDestroyNotify old_notify = NULL;
896
897   g_return_if_fail (object != NULL);
898   g_return_if_fail (quark > 0);
899
900   G_LOCK (qdata_mutex);
901   if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
902     PrivData *priv_data = object->priv_pointer;
903
904     old_data = QDATA_DATA (priv_data, i);
905     old_notify = QDATA_DESTROY (priv_data, i);
906
907     if (data == NULL)
908       remove_notify (object, i);
909   }
910   if (data != NULL)
911     set_notify (object, i, quark, NULL, data, destroy);
912   G_UNLOCK (qdata_mutex);
913
914   if (old_notify)
915     old_notify (old_data);
916 }
917
918 /**
919  * gst_mini_object_get_qdata:
920  * @object: The GstMiniObject to get a stored user data pointer from
921  * @quark: A #GQuark, naming the user data pointer
922  *
923  * This function gets back user data pointers stored via
924  * gst_mini_object_set_qdata().
925  *
926  * Returns: (transfer none) (nullable): The user data pointer set, or
927  * %NULL
928  */
929 gpointer
930 gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
931 {
932   guint i;
933   gpointer result;
934
935   g_return_val_if_fail (object != NULL, NULL);
936   g_return_val_if_fail (quark > 0, NULL);
937
938   G_LOCK (qdata_mutex);
939   if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
940     PrivData *priv_data = object->priv_pointer;
941     result = QDATA_DATA (priv_data, i);
942   } else {
943     result = NULL;
944   }
945   G_UNLOCK (qdata_mutex);
946
947   return result;
948 }
949
950 /**
951  * gst_mini_object_steal_qdata:
952  * @object: The GstMiniObject to get a stored user data pointer from
953  * @quark: A #GQuark, naming the user data pointer
954  *
955  * This function gets back user data pointers stored via gst_mini_object_set_qdata()
956  * and removes the data from @object without invoking its destroy() function (if
957  * any was set).
958  *
959  * Returns: (transfer full) (nullable): The user data pointer set, or
960  * %NULL
961  */
962 gpointer
963 gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
964 {
965   guint i;
966   gpointer result;
967
968   g_return_val_if_fail (object != NULL, NULL);
969   g_return_val_if_fail (quark > 0, NULL);
970
971   G_LOCK (qdata_mutex);
972   if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
973     PrivData *priv_data = object->priv_pointer;
974     result = QDATA_DATA (priv_data, i);
975     remove_notify (object, i);
976   } else {
977     result = NULL;
978   }
979   G_UNLOCK (qdata_mutex);
980
981   return result;
982 }
983
984 /**
985  * gst_mini_object_add_parent:
986  * @object: a #GstMiniObject
987  * @parent: a parent #GstMiniObject
988  *
989  * This adds @parent as a parent for @object. Having one ore more parents affects the
990  * writability of @object: if a @parent is not writable, @object is also not
991  * writable, regardless of its refcount. @object is only writable if all
992  * the parents are writable and its own refcount is exactly 1.
993  *
994  * Note: This function does not take ownership of @parent and also does not
995  * take an additional reference. It is the responsibility of the caller to
996  * remove the parent again at a later time.
997  *
998  * Since: 1.16
999  */
1000 void
1001 gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)
1002 {
1003   gint priv_state;
1004
1005   g_return_if_fail (object != NULL);
1006
1007   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "adding parent %p to object %p", parent,
1008       object);
1009
1010   priv_state = lock_priv_pointer (object);
1011   /* If we already had one parent, we need to allocate the full struct now */
1012   if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
1013     /* Unlock again */
1014     g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1015
1016     ensure_priv_data (object);
1017     priv_state = PRIV_DATA_STATE_PARENTS_OR_QDATA;
1018   }
1019
1020   /* Now we either have to add the new parent to the full struct, or add
1021    * our one and only parent to the pointer field */
1022   if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
1023     PrivData *priv_data = object->priv_pointer;
1024
1025     /* Lock parents */
1026     while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1027
1028     if (priv_data->n_parents >= priv_data->n_parents_len) {
1029       priv_data->n_parents_len *= 2;
1030       if (priv_data->n_parents_len == 0)
1031         priv_data->n_parents_len = 16;
1032
1033       priv_data->parents =
1034           g_realloc (priv_data->parents,
1035           priv_data->n_parents_len * sizeof (GstMiniObject *));
1036     }
1037     priv_data->parents[priv_data->n_parents] = parent;
1038     priv_data->n_parents++;
1039
1040     /* Unlock again */
1041     g_atomic_int_set (&priv_data->parent_lock, 0);
1042   } else if (priv_state == PRIV_DATA_STATE_NO_PARENT) {
1043     object->priv_pointer = parent;
1044
1045     /* Unlock again */
1046     g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_ONE_PARENT);
1047   } else {
1048     g_assert_not_reached ();
1049   }
1050 }
1051
1052 /**
1053  * gst_mini_object_remove_parent:
1054  * @object: a #GstMiniObject
1055  * @parent: a parent #GstMiniObject
1056  *
1057  * This removes @parent as a parent for @object. See
1058  * gst_mini_object_add_parent().
1059  *
1060  * Since: 1.16
1061  */
1062 void
1063 gst_mini_object_remove_parent (GstMiniObject * object, GstMiniObject * parent)
1064 {
1065   gint priv_state;
1066
1067   g_return_if_fail (object != NULL);
1068
1069   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "removing parent %p from object %p",
1070       parent, object);
1071
1072   priv_state = lock_priv_pointer (object);
1073
1074   /* Now we either have to add the new parent to the full struct, or add
1075    * our one and only parent to the pointer field */
1076   if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
1077     PrivData *priv_data = object->priv_pointer;
1078     guint i;
1079
1080     /* Lock parents */
1081     while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1082
1083     for (i = 0; i < priv_data->n_parents; i++)
1084       if (parent == priv_data->parents[i])
1085         break;
1086
1087     if (i != priv_data->n_parents) {
1088       priv_data->n_parents--;
1089       if (priv_data->n_parents != i)
1090         priv_data->parents[i] = priv_data->parents[priv_data->n_parents];
1091     } else {
1092       g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1093           object, parent);
1094     }
1095
1096     /* Unlock again */
1097     g_atomic_int_set (&priv_data->parent_lock, 0);
1098   } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
1099     if (object->priv_pointer != parent) {
1100       g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1101           object, parent);
1102       /* Unlock again */
1103       g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1104     } else {
1105       object->priv_pointer = NULL;
1106       /* Unlock again */
1107       g_atomic_int_set ((gint *) & object->priv_uint,
1108           PRIV_DATA_STATE_NO_PARENT);
1109     }
1110   } else {
1111     /* Unlock again */
1112     g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_NO_PARENT);
1113   }
1114 }