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