miniobject: Add parent pointers to the miniobject to influence writability
[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_mini_object_replace:
673  * @olddata: (inout) (transfer full) (nullable): pointer to a pointer to a
674  *     mini-object to be replaced
675  * @newdata: (allow-none): pointer to new mini-object
676  *
677  * Atomically modifies a pointer to point to a new mini-object.
678  * The reference count of @olddata is decreased and the reference count of
679  * @newdata is increased.
680  *
681  * Either @newdata and the value pointed to by @olddata may be %NULL.
682  *
683  * Returns: %TRUE if @newdata was different from @olddata
684  */
685 gboolean
686 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
687 {
688   GstMiniObject *olddata_val;
689
690   g_return_val_if_fail (olddata != NULL, FALSE);
691
692   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
693       *olddata, *olddata ? (*olddata)->refcount : 0,
694       newdata, newdata ? newdata->refcount : 0);
695
696   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
697
698   if (G_UNLIKELY (olddata_val == newdata))
699     return FALSE;
700
701   if (newdata)
702     gst_mini_object_ref (newdata);
703
704   while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
705               olddata, olddata_val, newdata))) {
706     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
707     if (G_UNLIKELY (olddata_val == newdata))
708       break;
709   }
710
711   if (olddata_val)
712     gst_mini_object_unref (olddata_val);
713
714   return olddata_val != newdata;
715 }
716
717 /**
718  * gst_mini_object_steal: (skip)
719  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
720  *     be stolen
721  *
722  * Replace the current #GstMiniObject pointer to by @olddata with %NULL and
723  * return the old value.
724  *
725  * Returns: (nullable): the #GstMiniObject at @oldata
726  */
727 GstMiniObject *
728 gst_mini_object_steal (GstMiniObject ** olddata)
729 {
730   GstMiniObject *olddata_val;
731
732   g_return_val_if_fail (olddata != NULL, NULL);
733
734   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
735       *olddata, *olddata ? (*olddata)->refcount : 0);
736
737   do {
738     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
739     if (olddata_val == NULL)
740       break;
741   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
742               olddata, olddata_val, NULL)));
743
744   return olddata_val;
745 }
746
747 /**
748  * gst_mini_object_take:
749  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
750  *     be replaced
751  * @newdata: pointer to new mini-object
752  *
753  * Modifies a pointer to point to a new mini-object. The modification
754  * is done atomically. This version is similar to gst_mini_object_replace()
755  * except that it does not increase the refcount of @newdata and thus
756  * takes ownership of @newdata.
757  *
758  * Either @newdata and the value pointed to by @olddata may be %NULL.
759  *
760  * Returns: %TRUE if @newdata was different from @olddata
761  */
762 gboolean
763 gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
764 {
765   GstMiniObject *olddata_val;
766
767   g_return_val_if_fail (olddata != NULL, FALSE);
768
769   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "take %p (%d) with %p (%d)",
770       *olddata, *olddata ? (*olddata)->refcount : 0,
771       newdata, newdata ? newdata->refcount : 0);
772
773   do {
774     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
775     if (G_UNLIKELY (olddata_val == newdata))
776       break;
777   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
778               olddata, olddata_val, newdata)));
779
780   if (olddata_val)
781     gst_mini_object_unref (olddata_val);
782
783   return olddata_val != newdata;
784 }
785
786 /**
787  * gst_mini_object_weak_ref: (skip)
788  * @object: #GstMiniObject to reference weakly
789  * @notify: callback to invoke before the mini object is freed
790  * @data: extra data to pass to notify
791  *
792  * Adds a weak reference callback to a mini object. Weak references are
793  * used for notification when a mini object is finalized. They are called
794  * "weak references" because they allow you to safely hold a pointer
795  * to the mini object without calling gst_mini_object_ref()
796  * (gst_mini_object_ref() adds a strong reference, that is, forces the object
797  * to stay alive).
798  */
799 void
800 gst_mini_object_weak_ref (GstMiniObject * object,
801     GstMiniObjectNotify notify, gpointer data)
802 {
803   g_return_if_fail (object != NULL);
804   g_return_if_fail (notify != NULL);
805   g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
806
807   G_LOCK (qdata_mutex);
808   set_notify (object, -1, weak_ref_quark, notify, data, NULL);
809   G_UNLOCK (qdata_mutex);
810 }
811
812 /**
813  * gst_mini_object_weak_unref: (skip)
814  * @object: #GstMiniObject to remove a weak reference from
815  * @notify: callback to search for
816  * @data: data to search for
817  *
818  * Removes a weak reference callback from a mini object.
819  */
820 void
821 gst_mini_object_weak_unref (GstMiniObject * object,
822     GstMiniObjectNotify notify, gpointer data)
823 {
824   gint i;
825
826   g_return_if_fail (object != NULL);
827   g_return_if_fail (notify != NULL);
828
829   G_LOCK (qdata_mutex);
830   if ((i = find_notify (object, weak_ref_quark, TRUE, notify, data)) != -1) {
831     remove_notify (object, i);
832   } else {
833     g_warning ("%s: couldn't find weak ref %p (object:%p data:%p)", G_STRFUNC,
834         notify, object, data);
835   }
836   G_UNLOCK (qdata_mutex);
837 }
838
839 /**
840  * gst_mini_object_set_qdata:
841  * @object: a #GstMiniObject
842  * @quark: A #GQuark, naming the user data pointer
843  * @data: An opaque user data pointer
844  * @destroy: Function to invoke with @data as argument, when @data
845  *           needs to be freed
846  *
847  * This sets an opaque, named pointer on a miniobject.
848  * The name is specified through a #GQuark (retrieved e.g. via
849  * g_quark_from_static_string()), and the pointer
850  * can be gotten back from the @object with gst_mini_object_get_qdata()
851  * until the @object is disposed.
852  * Setting a previously set user data pointer, overrides (frees)
853  * the old pointer set, using %NULL as pointer essentially
854  * removes the data stored.
855  *
856  * @destroy may be specified which is called with @data as argument
857  * when the @object is disposed, or the data is being overwritten by
858  * a call to gst_mini_object_set_qdata() with the same @quark.
859  */
860 void
861 gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
862     gpointer data, GDestroyNotify destroy)
863 {
864   gint i;
865   gpointer old_data = NULL;
866   GDestroyNotify old_notify = NULL;
867
868   g_return_if_fail (object != NULL);
869   g_return_if_fail (quark > 0);
870
871   G_LOCK (qdata_mutex);
872   if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
873     PrivData *priv_data = object->priv_pointer;
874
875     old_data = QDATA_DATA (priv_data, i);
876     old_notify = QDATA_DESTROY (priv_data, i);
877
878     if (data == NULL)
879       remove_notify (object, i);
880   }
881   if (data != NULL)
882     set_notify (object, i, quark, NULL, data, destroy);
883   G_UNLOCK (qdata_mutex);
884
885   if (old_notify)
886     old_notify (old_data);
887 }
888
889 /**
890  * gst_mini_object_get_qdata:
891  * @object: The GstMiniObject to get a stored user data pointer from
892  * @quark: A #GQuark, naming the user data pointer
893  *
894  * This function gets back user data pointers stored via
895  * gst_mini_object_set_qdata().
896  *
897  * Returns: (transfer none) (nullable): The user data pointer set, or
898  * %NULL
899  */
900 gpointer
901 gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
902 {
903   guint i;
904   gpointer result;
905
906   g_return_val_if_fail (object != NULL, NULL);
907   g_return_val_if_fail (quark > 0, NULL);
908
909   G_LOCK (qdata_mutex);
910   if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
911     PrivData *priv_data = object->priv_pointer;
912     result = QDATA_DATA (priv_data, i);
913   } else {
914     result = NULL;
915   }
916   G_UNLOCK (qdata_mutex);
917
918   return result;
919 }
920
921 /**
922  * gst_mini_object_steal_qdata:
923  * @object: The GstMiniObject to get a stored user data pointer from
924  * @quark: A #GQuark, naming the user data pointer
925  *
926  * This function gets back user data pointers stored via gst_mini_object_set_qdata()
927  * and removes the data from @object without invoking its destroy() function (if
928  * any was set).
929  *
930  * Returns: (transfer full) (nullable): The user data pointer set, or
931  * %NULL
932  */
933 gpointer
934 gst_mini_object_steal_qdata (GstMiniObject * object, GQuark quark)
935 {
936   guint i;
937   gpointer result;
938
939   g_return_val_if_fail (object != NULL, NULL);
940   g_return_val_if_fail (quark > 0, NULL);
941
942   G_LOCK (qdata_mutex);
943   if ((i = find_notify (object, quark, FALSE, NULL, NULL)) != -1) {
944     PrivData *priv_data = object->priv_pointer;
945     result = QDATA_DATA (priv_data, i);
946     remove_notify (object, i);
947   } else {
948     result = NULL;
949   }
950   G_UNLOCK (qdata_mutex);
951
952   return result;
953 }
954
955 /**
956  * gst_mini_object_add_parent:
957  * @object: a #GstMiniObject
958  * @parent: a parent #GstMiniObject
959  *
960  * This adds @parent as a parent for @object. Having one ore more parents affects the
961  * writability of @object: if a @parent is not writable, @object is also not
962  * writable, regardless of its refcount. @object is only writable if all
963  * the parents are writable and its own refcount is exactly 1.
964  *
965  * Note: This function does not take ownership of @parent and also does not
966  * take an additional reference. It is the responsibility of the caller to
967  * remove the parent again at a later time.
968  *
969  * Since: 1.16
970  */
971 void
972 gst_mini_object_add_parent (GstMiniObject * object, GstMiniObject * parent)
973 {
974   gint priv_state;
975
976   g_return_if_fail (object != NULL);
977
978   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "adding parent %p to object %p", parent,
979       object);
980
981   priv_state = lock_priv_pointer (object);
982   /* If we already had one parent, we need to allocate the full struct now */
983   if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
984     /* Unlock again */
985     g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
986
987     ensure_priv_data (object);
988     priv_state = PRIV_DATA_STATE_PARENTS_OR_QDATA;
989   }
990
991   /* Now we either have to add the new parent to the full struct, or add
992    * our one and only parent to the pointer field */
993   if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
994     PrivData *priv_data = object->priv_pointer;
995
996     /* Lock parents */
997     while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
998
999     if (priv_data->n_parents >= priv_data->n_parents_len) {
1000       priv_data->n_parents_len *= 2;
1001       if (priv_data->n_parents_len == 0)
1002         priv_data->n_parents_len = 16;
1003
1004       priv_data->parents =
1005           g_realloc (priv_data->parents,
1006           priv_data->n_parents_len * sizeof (GstMiniObject *));
1007     }
1008     priv_data->parents[priv_data->n_parents] = parent;
1009     priv_data->n_parents++;
1010
1011     /* Unlock again */
1012     g_atomic_int_set (&priv_data->parent_lock, 0);
1013   } else if (priv_state == PRIV_DATA_STATE_NO_PARENT) {
1014     object->priv_pointer = parent;
1015
1016     /* Unlock again */
1017     g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_ONE_PARENT);
1018   } else {
1019     g_assert_not_reached ();
1020   }
1021 }
1022
1023 /**
1024  * gst_mini_object_remove_parent:
1025  * @object: a #GstMiniObject
1026  * @parent: a parent #GstMiniObject
1027  *
1028  * This removes @parent as a parent for @object. See
1029  * gst_mini_object_add_parent().
1030  *
1031  * Since: 1.16
1032  */
1033 void
1034 gst_mini_object_remove_parent (GstMiniObject * object, GstMiniObject * parent)
1035 {
1036   gint priv_state;
1037
1038   g_return_if_fail (object != NULL);
1039
1040   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "removing parent %p from object %p",
1041       parent, object);
1042
1043   priv_state = lock_priv_pointer (object);
1044
1045   /* Now we either have to add the new parent to the full struct, or add
1046    * our one and only parent to the pointer field */
1047   if (priv_state == PRIV_DATA_STATE_PARENTS_OR_QDATA) {
1048     PrivData *priv_data = object->priv_pointer;
1049     guint i;
1050
1051     /* Lock parents */
1052     while (!g_atomic_int_compare_and_exchange (&priv_data->parent_lock, 0, 1));
1053
1054     for (i = 0; i < priv_data->n_parents; i++)
1055       if (parent == priv_data->parents[i])
1056         break;
1057
1058     if (i != priv_data->n_parents) {
1059       priv_data->n_parents--;
1060       if (priv_data->n_parents != i)
1061         priv_data->parents[i] = priv_data->parents[priv_data->n_parents];
1062     } else {
1063       g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1064           object, parent);
1065     }
1066
1067     /* Unlock again */
1068     g_atomic_int_set (&priv_data->parent_lock, 0);
1069   } else if (priv_state == PRIV_DATA_STATE_ONE_PARENT) {
1070     if (object->priv_pointer != parent) {
1071       g_warning ("%s: couldn't find parent %p (object:%p)", G_STRFUNC,
1072           object, parent);
1073       /* Unlock again */
1074       g_atomic_int_set ((gint *) & object->priv_uint, priv_state);
1075     } else {
1076       object->priv_pointer = NULL;
1077       /* Unlock again */
1078       g_atomic_int_set ((gint *) & object->priv_uint,
1079           PRIV_DATA_STATE_NO_PARENT);
1080     }
1081   } else {
1082     /* Unlock again */
1083     g_atomic_int_set ((gint *) & object->priv_uint, PRIV_DATA_STATE_NO_PARENT);
1084   }
1085 }