gstpad: Probes that return HANDLED can reset the data info field
[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 (index != priv_data->n_qdata) {
510     QDATA (priv_data, index) = QDATA (priv_data, priv_data->n_qdata);
511   }
512 }
513
514 /* Make sure we allocate the PrivData of this object if not happened yet */
515 static void
516 ensure_priv_data (GstMiniObject * object)
517 {
518   gint priv_state;
519   PrivData *priv_data;
520   GstMiniObject *parent = NULL;
521
522   GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
523       "allocating private data %s miniobject %p",
524       g_type_name (GST_MINI_OBJECT_TYPE (object)), object);
525
526   priv_state = lock_priv_pointer (object);
527   if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA)
528     return;
529
530   /* Now we're either locked, or someone has already allocated the struct
531    * before us and we can just go ahead
532    *
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;
538
539     object->priv_pointer = priv_data = g_new0 (PrivData, 1);
540
541     if (parent) {
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;
546     }
547
548     /* Unlock */
549     g_atomic_int_set ((gint *) & object->priv_uint,
550         PRIV_DATA_STATE_PARENTS_OR_QDATA);
551   }
552 }
553
554 static void
555 set_notify (GstMiniObject * object, gint index, GQuark quark,
556     GstMiniObjectNotify notify, gpointer data, GDestroyNotify destroy)
557 {
558   PrivData *priv_data;
559
560   ensure_priv_data (object);
561   priv_data = object->priv_pointer;
562
563   if (index == -1) {
564     /* add item */
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;
570
571       priv_data->qdata =
572           g_realloc (priv_data->qdata,
573           sizeof (GstQData) * priv_data->n_qdata_len);
574     }
575   }
576
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;
581 }
582
583 static void
584 free_priv_data (GstMiniObject * obj)
585 {
586   guint i;
587   gint priv_state = g_atomic_int_get ((gint *) & obj->priv_uint);
588   PrivData *priv_data;
589
590   if (priv_state != PRIV_DATA_STATE_PARENTS_OR_QDATA) {
591     if (priv_state == PRIV_DATA_STATE_LOCKED) {
592       g_warning
593           ("%s: object finalizing but has locked private data (object:%p)",
594           G_STRFUNC, obj);
595     } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
596       g_warning
597           ("%s: object finalizing but still has parent (object:%p, parent:%p)",
598           G_STRFUNC, obj, obj->priv_pointer);
599     }
600
601     return;
602   }
603
604   priv_data = obj->priv_pointer;
605
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));
611   }
612   g_free (priv_data->qdata);
613
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);
618
619   g_free (priv_data);
620 }
621
622 /**
623  * gst_mini_object_unref: (skip)
624  * @mini_object: the mini-object
625  *
626  * Decreases the reference count of the mini-object, possibly freeing
627  * the mini-object.
628  */
629 void
630 gst_mini_object_unref (GstMiniObject * mini_object)
631 {
632   gint old_refcount, new_refcount;
633
634   g_return_if_fail (mini_object != NULL);
635   g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) > 0);
636
637   old_refcount = g_atomic_int_add (&mini_object->refcount, -1);
638   new_refcount = old_refcount - 1;
639
640   g_return_if_fail (old_refcount > 0);
641
642   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
643       mini_object, old_refcount, new_refcount);
644
645   GST_TRACER_MINI_OBJECT_UNREFFED (mini_object, new_refcount);
646
647   if (new_refcount == 0) {
648     gboolean do_free;
649
650     if (mini_object->dispose)
651       do_free = mini_object->dispose (mini_object);
652     else
653       do_free = TRUE;
654
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)
660           < 4);
661
662       free_priv_data (mini_object);
663
664       GST_TRACER_MINI_OBJECT_DESTROYED (mini_object);
665       if (mini_object->free)
666         mini_object->free (mini_object);
667     }
668   }
669 }
670
671 /**
672  * gst_clear_mini_object: (skip)
673  * @object_ptr: a pointer to a #GstMiniObject reference
674  *
675  * Clears a reference to a #GstMiniObject.
676  *
677  * @object_ptr must not be %NULL.
678  *
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.
682  *
683  * A macro is also included that allows this function to be used without
684  * pointer casts.
685  *
686  * Since: 1.16
687  **/
688 #undef gst_clear_mini_object
689 void
690 gst_clear_mini_object (GstMiniObject ** object_ptr)
691 {
692   g_clear_pointer (object_ptr, gst_mini_object_unref);
693 }
694
695 /**
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
700  *
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.
704  *
705  * Either @newdata and the value pointed to by @olddata may be %NULL.
706  *
707  * Returns: %TRUE if @newdata was different from @olddata
708  */
709 gboolean
710 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
711 {
712   GstMiniObject *olddata_val;
713
714   g_return_val_if_fail (olddata != NULL, FALSE);
715
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);
719
720   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
721
722   if (G_UNLIKELY (olddata_val == newdata))
723     return FALSE;
724
725   if (newdata)
726     gst_mini_object_ref (newdata);
727
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))
732       break;
733   }
734
735   if (olddata_val)
736     gst_mini_object_unref (olddata_val);
737
738   return olddata_val != newdata;
739 }
740
741 /**
742  * gst_mini_object_steal: (skip)
743  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
744  *     be stolen
745  *
746  * Replace the current #GstMiniObject pointer to by @olddata with %NULL and
747  * return the old value.
748  *
749  * Returns: (nullable): the #GstMiniObject at @oldata
750  */
751 GstMiniObject *
752 gst_mini_object_steal (GstMiniObject ** olddata)
753 {
754   GstMiniObject *olddata_val;
755
756   g_return_val_if_fail (olddata != NULL, NULL);
757
758   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
759       *olddata, *olddata ? (*olddata)->refcount : 0);
760
761   do {
762     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
763     if (olddata_val == NULL)
764       break;
765   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
766               olddata, olddata_val, NULL)));
767
768   return olddata_val;
769 }
770
771 /**
772  * gst_mini_object_take:
773  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
774  *     be replaced
775  * @newdata: pointer to new mini-object
776  *
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.
781  *
782  * Either @newdata and the value pointed to by @olddata may be %NULL.
783  *
784  * Returns: %TRUE if @newdata was different from @olddata
785  */
786 gboolean
787 gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
788 {
789   GstMiniObject *olddata_val;
790
791   g_return_val_if_fail (olddata != NULL, FALSE);
792
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);
796
797   do {
798     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
799     if (G_UNLIKELY (olddata_val == newdata))
800       break;
801   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
802               olddata, olddata_val, newdata)));
803
804   if (olddata_val)
805     gst_mini_object_unref (olddata_val);
806
807   return olddata_val != newdata;
808 }
809
810 /**
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
815  *
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
821  * to stay alive).
822  */
823 void
824 gst_mini_object_weak_ref (GstMiniObject * object,
825     GstMiniObjectNotify notify, gpointer data)
826 {
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);
830
831   G_LOCK (qdata_mutex);
832   set_notify (object, -1, weak_ref_quark, notify, data, NULL);
833   G_UNLOCK (qdata_mutex);
834 }
835
836 /**
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
841  *
842  * Removes a weak reference callback from a mini object.
843  */
844 void
845 gst_mini_object_weak_unref (GstMiniObject * object,
846     GstMiniObjectNotify notify, gpointer data)
847 {
848   gint i;
849
850   g_return_if_fail (object != NULL);
851   g_return_if_fail (notify != NULL);
852
853   G_LOCK (qdata_mutex);
854   if ((i = find_notify (object, weak_ref_quark, TRUE, notify, data)) != -1) {
855     remove_notify (object, i);
856   } else {
857     g_warning ("%s: couldn't find weak ref %p (object:%p data:%p)", G_STRFUNC,
858         notify, object, data);
859   }
860   G_UNLOCK (qdata_mutex);
861 }
862
863 /**
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
869  *           needs to be freed
870  *
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.
879  *
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.
883  */
884 void
885 gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
886     gpointer data, GDestroyNotify destroy)
887 {
888   gint i;
889   gpointer old_data = NULL;
890   GDestroyNotify old_notify = NULL;
891
892   g_return_if_fail (object != NULL);
893   g_return_if_fail (quark > 0);
894
895   G_LOCK (qdata_mutex);
896   if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
897     PrivData *priv_data = object->priv_pointer;
898
899     old_data = QDATA_DATA (priv_data, i);
900     old_notify = QDATA_DESTROY (priv_data, i);
901
902     if (data == NULL)
903       remove_notify (object, i);
904   }
905   if (data != NULL)
906     set_notify (object, i, quark, NULL, data, destroy);
907   G_UNLOCK (qdata_mutex);
908
909   if (old_notify)
910     old_notify (old_data);
911 }
912
913 /**
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
917  *
918  * This function gets back user data pointers stored via
919  * gst_mini_object_set_qdata().
920  *
921  * Returns: (transfer none) (nullable): The user data pointer set, or
922  * %NULL
923  */
924 gpointer
925 gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
926 {
927   guint i;
928   gpointer result;
929
930   g_return_val_if_fail (object != NULL, NULL);
931   g_return_val_if_fail (quark > 0, NULL);
932
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);
937   } else {
938     result = NULL;
939   }
940   G_UNLOCK (qdata_mutex);
941
942   return result;
943 }
944
945 /**
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
949  *
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
952  * any was set).
953  *
954  * Returns: (transfer full) (nullable): The user data pointer set, or
955  * %NULL
956  */
957 gpointer
958 gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
959 {
960   guint i;
961   gpointer result;
962
963   g_return_val_if_fail (object != NULL, NULL);
964   g_return_val_if_fail (quark > 0, NULL);
965
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);
971   } else {
972     result = NULL;
973   }
974   G_UNLOCK (qdata_mutex);
975
976   return result;
977 }
978
979 /**
980  * gst_mini_object_add_parent:
981  * @object: a #GstMiniObject
982  * @parent: a parent #GstMiniObject
983  *
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.
988  *
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.
992  *
993  * Since: 1.16
994  */
995 void
996 gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)
997 {
998   gint priv_state;
999
1000   g_return_if_fail (object != NULL);
1001
1002   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "adding parent %p to object %p", parent,
1003       object);
1004
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) {
1008     /* Unlock again */
1009     g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1010
1011     ensure_priv_data (object);
1012     priv_state = PRIV_DATA_STATE_PARENTS_OR_QDATA;
1013   }
1014
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;
1019
1020     /* Lock parents */
1021     while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1022
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;
1027
1028       priv_data->parents =
1029           g_realloc (priv_data->parents,
1030           priv_data->n_parents_len * sizeof (GstMiniObject *));
1031     }
1032     priv_data->parents[priv_data->n_parents] = parent;
1033     priv_data->n_parents++;
1034
1035     /* Unlock again */
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;
1039
1040     /* Unlock again */
1041     g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_ONE_PARENT);
1042   } else {
1043     g_assert_not_reached ();
1044   }
1045 }
1046
1047 /**
1048  * gst_mini_object_remove_parent:
1049  * @object: a #GstMiniObject
1050  * @parent: a parent #GstMiniObject
1051  *
1052  * This removes @parent as a parent for @object. See
1053  * gst_mini_object_add_parent().
1054  *
1055  * Since: 1.16
1056  */
1057 void
1058 gst_mini_object_remove_parent (GstMiniObject * object, GstMiniObject * parent)
1059 {
1060   gint priv_state;
1061
1062   g_return_if_fail (object != NULL);
1063
1064   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "removing parent %p from object %p",
1065       parent, object);
1066
1067   priv_state = lock_priv_pointer (object);
1068
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;
1073     guint i;
1074
1075     /* Lock parents */
1076     while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1077
1078     for (i = 0; i < priv_data->n_parents; i++)
1079       if (parent == priv_data->parents[i])
1080         break;
1081
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];
1086     } else {
1087       g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1088           object, parent);
1089     }
1090
1091     /* Unlock again */
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,
1096           object, parent);
1097       /* Unlock again */
1098       g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1099     } else {
1100       object->priv_pointer = NULL;
1101       /* Unlock again */
1102       g_atomic_int_set ((gint *) & object->priv_uint,
1103           PRIV_DATA_STATE_NO_PARENT);
1104     }
1105   } else {
1106     /* Unlock again */
1107     g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_NO_PARENT);
1108   }
1109 }