miniobject: expand docs a little
[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., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /**
22  * SECTION:gstminiobject
23  * @short_description: Lightweight base class for the GStreamer object hierarchy
24  *
25  * #GstMiniObject is a simple structure that can be used to implement refcounted
26  * types.
27  *
28  * Subclasses will include #GstMiniObject as the first member in their structure
29  * and then call gst_mini_object_init() to initialize the #GstMiniObject fields.
30  *
31  * gst_mini_object_ref() and gst_mini_object_unref() increment and decrement the
32  * refcount respectively. When the refcount of a mini-object reaches 0, the
33  * dispose function is called first and when this returns %TRUE, the free
34  * function of the miniobject is called.
35  *
36  * A copy can be made with gst_mini_object_copy().
37  *
38  * gst_mini_object_is_writable() will return %TRUE when the refcount of the
39  * object is exactly 1, meaning the current caller has the only reference to the
40  * object. gst_mini_object_make_writable() will return a writable version of the
41  * object, which might be a new copy when the refcount was not 1.
42  *
43  * Opaque data can be associated with a #GstMiniObject with
44  * gst_mini_object_set_qdata() and gst_mini_object_get_qdata(). The data is
45  * meant to be specific to the particular object and is not automatically copied
46  * with gst_mini_object_copy() or similar methods.
47  *
48  * A weak reference can be added and remove with gst_mini_object_weak_ref()
49  * and gst_mini_object_weak_unref() respectively.
50  *
51  * Last reviewed on 2012-06-15 (0.11.93)
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 #ifndef GST_DISABLE_TRACE
63 #include "gsttrace.h"
64 static GstAllocTrace *_gst_mini_object_trace;
65 #endif
66
67 /* Mutex used for weak referencing */
68 G_LOCK_DEFINE_STATIC (qdata_mutex);
69 static GQuark weak_ref_quark;
70
71 void
72 _priv_gst_mini_object_initialize (void)
73 {
74   weak_ref_quark = g_quark_from_static_string ("GstMiniObjectWeakRefQuark");
75
76 #ifndef GST_DISABLE_TRACE
77   _gst_mini_object_trace = _gst_alloc_trace_register ("GstMiniObject", 0);
78 #endif
79 }
80
81 /**
82  * gst_mini_object_init:
83  * @mini_object: a #GstMiniObject 
84  * @type: the #GType of the mini-object to create
85  * @size: the size of the data
86  *
87  * Initializes a mini-object with the desired type and size.
88  *
89  * MT safe
90  *
91  * Returns: (transfer full): the new mini-object.
92  */
93 void
94 gst_mini_object_init (GstMiniObject * mini_object, GType type)
95 {
96   mini_object->type = type;
97   mini_object->refcount = 1;
98   mini_object->flags = 0;
99   mini_object->n_qdata = 0;
100   mini_object->qdata = NULL;
101
102 #ifndef GST_DISABLE_TRACE
103   _gst_alloc_trace_new (_gst_mini_object_trace, mini_object);
104 #endif
105 }
106
107 /**
108  * gst_mini_object_copy:
109  * @mini_object: the mini-object to copy
110  *
111  * Creates a copy of the mini-object.
112  *
113  * MT safe
114  *
115  * Returns: (transfer full): the new mini-object.
116  */
117 GstMiniObject *
118 gst_mini_object_copy (const GstMiniObject * mini_object)
119 {
120   GstMiniObject *copy;
121
122   g_return_val_if_fail (mini_object != NULL, NULL);
123
124   if (mini_object->copy)
125     copy = mini_object->copy (mini_object);
126   else
127     copy = NULL;
128
129   return copy;
130 }
131
132 /**
133  * gst_mini_object_is_writable:
134  * @mini_object: the mini-object to check
135  *
136  * Checks if a mini-object is writable.  A mini-object is writable
137  * if the reference count is one. Modification of a mini-object should
138  * only be done after verifying that it is writable.
139  *
140  * MT safe
141  *
142  * Returns: TRUE if the object is writable.
143  */
144 gboolean
145 gst_mini_object_is_writable (const GstMiniObject * mini_object)
146 {
147   g_return_val_if_fail (mini_object != NULL, FALSE);
148
149   return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
150 }
151
152 /**
153  * gst_mini_object_make_writable:
154  * @mini_object: (transfer full): the mini-object to make writable
155  *
156  * Checks if a mini-object is writable.  If not, a writable copy is made and
157  * returned.  This gives away the reference to the original mini object,
158  * and returns a reference to the new object.
159  *
160  * MT safe
161  *
162  * Returns: (transfer full): a mini-object (possibly the same pointer) that
163  *     is writable.
164  */
165 GstMiniObject *
166 gst_mini_object_make_writable (GstMiniObject * mini_object)
167 {
168   GstMiniObject *ret;
169
170   g_return_val_if_fail (mini_object != NULL, NULL);
171
172   if (gst_mini_object_is_writable (mini_object)) {
173     ret = mini_object;
174   } else {
175     ret = gst_mini_object_copy (mini_object);
176     GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject %p -> %p",
177         g_type_name (GST_MINI_OBJECT_TYPE (mini_object)), mini_object, ret);
178     gst_mini_object_unref (mini_object);
179   }
180
181   return ret;
182 }
183
184 /**
185  * gst_mini_object_ref:
186  * @mini_object: the mini-object
187  *
188  * Increase the reference count of the mini-object.
189  *
190  * Note that the refcount affects the writeability
191  * of @mini-object, see gst_mini_object_is_writable(). It is
192  * important to note that keeping additional references to
193  * GstMiniObject instances can potentially increase the number
194  * of memcpy operations in a pipeline, especially if the miniobject
195  * is a #GstBuffer.
196  *
197  * Returns: (transfer full): the mini-object.
198  */
199 GstMiniObject *
200 gst_mini_object_ref (GstMiniObject * mini_object)
201 {
202   g_return_val_if_fail (mini_object != NULL, NULL);
203   /* we can't assert that the refcount > 0 since the _free functions
204    * increments the refcount from 0 to 1 again to allow resurecting
205    * the object
206    g_return_val_if_fail (mini_object->refcount > 0, NULL);
207    */
208
209   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
210       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
211       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
212
213   g_atomic_int_inc (&mini_object->refcount);
214
215   return mini_object;
216 }
217
218 static void
219 qdata_notify (GstMiniObject * obj)
220 {
221   guint i;
222
223   for (i = 0; i < obj->n_qdata; i++)
224     obj->qdata[i].notify (obj->qdata[i].data, obj);
225   g_free (obj->qdata);
226 }
227
228 /**
229  * gst_mini_object_unref:
230  * @mini_object: the mini-object
231  *
232  * Decreases the reference count of the mini-object, possibly freeing
233  * the mini-object.
234  */
235 void
236 gst_mini_object_unref (GstMiniObject * mini_object)
237 {
238   g_return_if_fail (mini_object != NULL);
239
240   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
241       mini_object,
242       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
243       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
244
245   g_return_if_fail (mini_object->refcount > 0);
246
247   if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
248     gboolean do_free;
249
250     if (mini_object->dispose)
251       do_free = mini_object->dispose (mini_object);
252     else
253       do_free = TRUE;
254
255     /* if the subclass recycled the object (and returned FALSE) we don't
256      * want to free the instance anymore */
257     if (G_LIKELY (do_free)) {
258       /* The weak reference stack is freed in the notification function */
259       if (mini_object->n_qdata)
260         qdata_notify (mini_object);
261
262 #ifndef GST_DISABLE_TRACE
263       _gst_alloc_trace_free (_gst_mini_object_trace, mini_object);
264 #endif
265       if (mini_object->free)
266         mini_object->free (mini_object);
267     }
268   }
269 }
270
271 /**
272  * gst_mini_object_replace:
273  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
274  *     be replaced
275  * @newdata: pointer to new mini-object
276  *
277  * Atomically modifies a pointer to point to a new mini-object.
278  * The reference count of @olddata is decreased and the reference count of
279  * @newdata is increased.
280  *
281  * Either @newdata and the value pointed to by @olddata may be NULL.
282  *
283  * Returns: TRUE if @newdata was different from @olddata
284  */
285 gboolean
286 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
287 {
288   GstMiniObject *olddata_val;
289
290   g_return_val_if_fail (olddata != NULL, FALSE);
291
292   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
293       *olddata, *olddata ? (*olddata)->refcount : 0,
294       newdata, newdata ? newdata->refcount : 0);
295
296   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
297
298   if (G_UNLIKELY (olddata_val == newdata))
299     return FALSE;
300
301   if (newdata)
302     gst_mini_object_ref (newdata);
303
304   while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
305               olddata, olddata_val, newdata))) {
306     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
307     if (G_UNLIKELY (olddata_val == newdata))
308       break;
309   }
310
311   if (olddata_val)
312     gst_mini_object_unref (olddata_val);
313
314   return olddata_val != newdata;
315 }
316
317 /**
318  * gst_mini_object_steal:
319  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
320  *     be stolen
321  *
322  * Replace the current #GstMiniObject pointer to by @olddata with NULL and
323  * return the old value.
324  *
325  * Returns: the #GstMiniObject at @oldata
326  */
327 GstMiniObject *
328 gst_mini_object_steal (GstMiniObject ** olddata)
329 {
330   GstMiniObject *olddata_val;
331
332   g_return_val_if_fail (olddata != NULL, NULL);
333
334   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
335       *olddata, *olddata ? (*olddata)->refcount : 0);
336
337   do {
338     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
339     if (olddata_val == NULL)
340       break;
341   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
342               olddata, olddata_val, NULL)));
343
344   return olddata_val;
345 }
346
347 /**
348  * gst_mini_object_take:
349  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
350  *     be replaced
351  * @newdata: pointer to new mini-object
352  *
353  * Modifies a pointer to point to a new mini-object. The modification
354  * is done atomically. This version is similar to gst_mini_object_replace()
355  * except that it does not increase the refcount of @newdata and thus
356  * takes ownership of @newdata.
357  *
358  * Either @newdata and the value pointed to by @olddata may be NULL.
359  *
360  * Returns: TRUE if @newdata was different from @olddata
361  */
362 gboolean
363 gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
364 {
365   GstMiniObject *olddata_val;
366
367   g_return_val_if_fail (olddata != NULL, FALSE);
368
369   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "take %p (%d) with %p (%d)",
370       *olddata, *olddata ? (*olddata)->refcount : 0,
371       newdata, newdata ? newdata->refcount : 0);
372
373   do {
374     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
375     if (G_UNLIKELY (olddata_val == newdata))
376       break;
377   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
378               olddata, olddata_val, newdata)));
379
380   if (olddata_val)
381     gst_mini_object_unref (olddata_val);
382
383   return olddata_val != newdata;
384 }
385
386 /**
387  * gst_mini_object_weak_ref: (skip)
388  * @object: #GstMiniObject to reference weakly
389  * @notify: callback to invoke before the mini object is freed
390  * @data: extra data to pass to notify
391  *
392  * Adds a weak reference callback to a mini object. Weak references are
393  * used for notification when a mini object is finalized. They are called
394  * "weak references" because they allow you to safely hold a pointer
395  * to the mini object without calling gst_mini_object_ref()
396  * (gst_mini_object_ref() adds a strong reference, that is, forces the object
397  * to stay alive).
398  *
399  * Since: 0.10.35
400  */
401 void
402 gst_mini_object_weak_ref (GstMiniObject * object,
403     GstMiniObjectWeakNotify notify, gpointer data)
404 {
405   guint i;
406
407   g_return_if_fail (object != NULL);
408   g_return_if_fail (notify != NULL);
409   g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
410
411   G_LOCK (qdata_mutex);
412   i = object->n_qdata++;
413   object->qdata =
414       g_realloc (object->qdata, sizeof (object->qdata[0]) * object->n_qdata);
415   object->qdata[i].quark = weak_ref_quark;
416   object->qdata[i].notify = notify;
417   object->qdata[i].data = data;
418   G_UNLOCK (qdata_mutex);
419 }
420
421 /**
422  * gst_mini_object_weak_unref: (skip)
423  * @object: #GstMiniObject to remove a weak reference from
424  * @notify: callback to search for
425  * @data: data to search for
426  *
427  * Removes a weak reference callback to a mini object.
428  *
429  * Since: 0.10.35
430  */
431 void
432 gst_mini_object_weak_unref (GstMiniObject * object,
433     GstMiniObjectWeakNotify notify, gpointer data)
434 {
435   guint i;
436   gboolean found_one = FALSE;
437
438   g_return_if_fail (object != NULL);
439   g_return_if_fail (notify != NULL);
440
441   G_LOCK (qdata_mutex);
442   for (i = 0; i < object->n_qdata; i++) {
443     if (object->qdata[i].quark == weak_ref_quark &&
444         object->qdata[i].notify == notify && object->qdata[i].data == data) {
445       found_one = TRUE;
446       if (--object->n_qdata == 0) {
447         /* we don't shrink but free when everything is gone */
448         g_free (object->qdata);
449         object->qdata = NULL;
450       } else if (i != object->n_qdata)
451         object->qdata[i] = object->qdata[object->n_qdata];
452       break;
453     }
454   }
455   G_UNLOCK (qdata_mutex);
456
457   if (!found_one)
458     g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data);
459 }
460
461 /**
462  * gst_mini_object_set_qdata:
463  * @object: a #GstMiniObject
464  * @quark: A #GQuark, naming the user data pointer
465  * @data: An opaque user data pointer
466  * @destroy: Function to invoke with @data as argument, when @data
467  *           needs to be freed
468  *
469  * This sets an opaque, named pointer on a miniobject.
470  * The name is specified through a #GQuark (retrived e.g. via
471  * g_quark_from_static_string()), and the pointer
472  * can be gotten back from the @object with gst_mini_object_get_qdata()
473  * until the @object is disposed.
474  * Setting a previously set user data pointer, overrides (frees)
475  * the old pointer set, using #NULL as pointer essentially
476  * removes the data stored.
477  *
478  * @destroy may be specified which is called with @data as argument
479  * when the @object is disposed, or the data is being overwritten by
480  * a call to gst_mini_object_set_qdata() with the same @quark.
481  */
482 void
483 gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark,
484     gpointer data, GDestroyNotify destroy)
485 {
486   guint i;
487   gpointer old_data = NULL;
488   GDestroyNotify old_notify = NULL;
489
490   g_return_if_fail (object != NULL);
491   g_return_if_fail (quark > 0);
492
493   G_LOCK (qdata_mutex);
494   for (i = 0; i < object->n_qdata; i++) {
495     if (object->qdata[i].quark == quark) {
496       old_data = object->qdata[i].data;
497       old_notify = (GDestroyNotify) object->qdata[i].notify;
498
499       if (data == NULL) {
500         /* remove item */
501         if (--object->n_qdata == 0) {
502           /* we don't shrink but free when everything is gone */
503           g_free (object->qdata);
504           object->qdata = NULL;
505         } else if (i != object->n_qdata)
506           object->qdata[i] = object->qdata[object->n_qdata];
507       }
508       break;
509     }
510   }
511   if (!old_data) {
512     /* add item */
513     i = object->n_qdata++;
514     object->qdata =
515         g_realloc (object->qdata, sizeof (object->qdata[0]) * object->n_qdata);
516   }
517   object->qdata[i].quark = quark;
518   object->qdata[i].data = data;
519   object->qdata[i].notify = (GstMiniObjectWeakNotify) destroy;
520   G_UNLOCK (qdata_mutex);
521
522   if (old_notify)
523     old_notify (old_data);
524 }
525
526 /**
527  * gst_mini_object_get_qdata:
528  * @object: The GstMiniObject to get a stored user data pointer from
529  * @quark: A #GQuark, naming the user data pointer
530  *
531  * This function gets back user data pointers stored via
532  * gst_mini_object_set_qdata().
533  *
534  * Returns: (transfer none): The user data pointer set, or %NULL
535  */
536 gpointer
537 gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark)
538 {
539   guint i;
540   gpointer result = NULL;
541
542   g_return_val_if_fail (object != NULL, NULL);
543   g_return_val_if_fail (quark > 0, NULL);
544
545   G_LOCK (qdata_mutex);
546   for (i = 0; i < object->n_qdata; i++) {
547     if (object->qdata[i].quark == quark) {
548       result = object->qdata[i].data;
549       break;
550     }
551   }
552   G_UNLOCK (qdata_mutex);
553
554   return result;
555 }