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