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