Merge remote-tracking branch 'origin/0.10'
[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  * Last reviewed on 2012-03-28 (0.11.3)
44  */
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include "gst/gst_private.h"
50 #include "gst/gstminiobject.h"
51 #include "gst/gstinfo.h"
52 #include <gobject/gvaluecollector.h>
53
54 #ifndef GST_DISABLE_TRACE
55 #include "gsttrace.h"
56 static GstAllocTrace *_gst_mini_object_trace;
57 #endif
58
59 /* Mutex used for weak referencing */
60 G_LOCK_DEFINE_STATIC (weak_refs_mutex);
61
62 void
63 _priv_gst_mini_object_initialize (void)
64 {
65 #ifndef GST_DISABLE_TRACE
66   _gst_mini_object_trace = _gst_alloc_trace_register ("GstMiniObject", 0);
67 #endif
68 }
69
70 /**
71  * gst_mini_object_init:
72  * @mini_object: a #GstMiniObject 
73  * @type: the #GType of the mini-object to create
74  * @size: the size of the data
75  *
76  * Initializes a mini-object with the desired type and size.
77  *
78  * MT safe
79  *
80  * Returns: (transfer full): the new mini-object.
81  */
82 void
83 gst_mini_object_init (GstMiniObject * mini_object, GType type, gsize size)
84 {
85   mini_object->type = type;
86   mini_object->refcount = 1;
87   mini_object->flags = 0;
88   mini_object->size = size;
89   mini_object->n_weak_refs = 0;
90   mini_object->weak_refs = NULL;
91
92 #ifndef GST_DISABLE_TRACE
93   _gst_alloc_trace_new (_gst_mini_object_trace, mini_object);
94 #endif
95 }
96
97 /**
98  * gst_mini_object_copy:
99  * @mini_object: the mini-object to copy
100  *
101  * Creates a copy of the mini-object.
102  *
103  * MT safe
104  *
105  * Returns: (transfer full): the new mini-object.
106  */
107 GstMiniObject *
108 gst_mini_object_copy (const GstMiniObject * mini_object)
109 {
110   GstMiniObject *copy;
111
112   g_return_val_if_fail (mini_object != NULL, NULL);
113
114   if (mini_object->copy)
115     copy = mini_object->copy (mini_object);
116   else
117     copy = NULL;
118
119   return copy;
120 }
121
122 /**
123  * gst_mini_object_is_writable:
124  * @mini_object: the mini-object to check
125  *
126  * Checks if a mini-object is writable.  A mini-object is writable
127  * if the reference count is one. Modification of a mini-object should
128  * only be done after verifying that it is writable.
129  *
130  * MT safe
131  *
132  * Returns: TRUE if the object is writable.
133  */
134 gboolean
135 gst_mini_object_is_writable (const GstMiniObject * mini_object)
136 {
137   g_return_val_if_fail (mini_object != NULL, FALSE);
138
139   return (GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) == 1);
140 }
141
142 /**
143  * gst_mini_object_make_writable:
144  * @mini_object: (transfer full): the mini-object to make writable
145  *
146  * Checks if a mini-object is writable.  If not, a writable copy is made and
147  * returned.  This gives away the reference to the original mini object,
148  * and returns a reference to the new object.
149  *
150  * MT safe
151  *
152  * Returns: (transfer full): a mini-object (possibly the same pointer) that
153  *     is writable.
154  */
155 GstMiniObject *
156 gst_mini_object_make_writable (GstMiniObject * mini_object)
157 {
158   GstMiniObject *ret;
159
160   g_return_val_if_fail (mini_object != NULL, NULL);
161
162   if (gst_mini_object_is_writable (mini_object)) {
163     ret = mini_object;
164   } else {
165     ret = gst_mini_object_copy (mini_object);
166     GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy %s miniobject %p -> %p",
167         g_type_name (GST_MINI_OBJECT_TYPE (mini_object)), mini_object, ret);
168     gst_mini_object_unref (mini_object);
169   }
170
171   return ret;
172 }
173
174 /**
175  * gst_mini_object_ref:
176  * @mini_object: the mini-object
177  *
178  * Increase the reference count of the mini-object.
179  *
180  * Note that the refcount affects the writeability
181  * of @mini-object, see gst_mini_object_is_writable(). It is
182  * important to note that keeping additional references to
183  * GstMiniObject instances can potentially increase the number
184  * of memcpy operations in a pipeline, especially if the miniobject
185  * is a #GstBuffer.
186  *
187  * Returns: (transfer full): the mini-object.
188  */
189 GstMiniObject *
190 gst_mini_object_ref (GstMiniObject * mini_object)
191 {
192   g_return_val_if_fail (mini_object != NULL, NULL);
193   /* we can't assert that the refcount > 0 since the _free functions
194    * increments the refcount from 0 to 1 again to allow resurecting
195    * the object
196    g_return_val_if_fail (mini_object->refcount > 0, NULL);
197    */
198
199   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p ref %d->%d", mini_object,
200       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
201       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) + 1);
202
203   g_atomic_int_inc (&mini_object->refcount);
204
205   return mini_object;
206 }
207
208 static void
209 weak_refs_notify (GstMiniObject * obj)
210 {
211   guint i;
212
213   for (i = 0; i < obj->n_weak_refs; i++)
214     obj->weak_refs[i].notify (obj->weak_refs[i].data, obj);
215   g_free (obj->weak_refs);
216 }
217
218 /**
219  * gst_mini_object_unref:
220  * @mini_object: the mini-object
221  *
222  * Decreases the reference count of the mini-object, possibly freeing
223  * the mini-object.
224  */
225 void
226 gst_mini_object_unref (GstMiniObject * mini_object)
227 {
228   g_return_if_fail (mini_object != NULL);
229
230   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d",
231       mini_object,
232       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object),
233       GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
234
235   g_return_if_fail (mini_object->refcount > 0);
236
237   if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
238     gboolean do_free;
239
240     if (mini_object->dispose)
241       do_free = mini_object->dispose (mini_object);
242     else
243       do_free = TRUE;
244
245     /* if the subclass recycled the object (and returned FALSE) we don't
246      * want to free the instance anymore */
247     if (G_LIKELY (do_free)) {
248       /* The weak reference stack is freed in the notification function */
249       if (mini_object->n_weak_refs)
250         weak_refs_notify (mini_object);
251
252 #ifndef GST_DISABLE_TRACE
253       _gst_alloc_trace_free (_gst_mini_object_trace, mini_object);
254 #endif
255       if (mini_object->free)
256         mini_object->free (mini_object);
257     }
258   }
259 }
260
261 /**
262  * gst_mini_object_replace:
263  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
264  *     be replaced
265  * @newdata: pointer to new mini-object
266  *
267  * Atomically modifies a pointer to point to a new mini-object.
268  * The reference count of @olddata is decreased and the reference count of
269  * @newdata is increased.
270  *
271  * Either @newdata and the value pointed to by @olddata may be NULL.
272  *
273  * Returns: TRUE if @newdata was different from @olddata
274  */
275 gboolean
276 gst_mini_object_replace (GstMiniObject ** olddata, GstMiniObject * newdata)
277 {
278   GstMiniObject *olddata_val;
279
280   g_return_val_if_fail (olddata != NULL, FALSE);
281
282   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "replace %p (%d) with %p (%d)",
283       *olddata, *olddata ? (*olddata)->refcount : 0,
284       newdata, newdata ? newdata->refcount : 0);
285
286   olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
287
288   if (G_UNLIKELY (olddata_val == newdata))
289     return FALSE;
290
291   if (newdata)
292     gst_mini_object_ref (newdata);
293
294   while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
295               olddata, olddata_val, newdata))) {
296     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
297     if (G_UNLIKELY (olddata_val == newdata))
298       break;
299   }
300
301   if (olddata_val)
302     gst_mini_object_unref (olddata_val);
303
304   return olddata_val != newdata;
305 }
306
307 /**
308  * gst_mini_object_steal:
309  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
310  *     be stolen
311  *
312  * Replace the current #GstMiniObject pointer to by @olddata with NULL and
313  * return the old value.
314  *
315  * Returns: the #GstMiniObject at @oldata
316  */
317 GstMiniObject *
318 gst_mini_object_steal (GstMiniObject ** olddata)
319 {
320   GstMiniObject *olddata_val;
321
322   g_return_val_if_fail (olddata != NULL, NULL);
323
324   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "steal %p (%d)",
325       *olddata, *olddata ? (*olddata)->refcount : 0);
326
327   do {
328     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
329     if (olddata_val == NULL)
330       break;
331   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
332               olddata, olddata_val, NULL)));
333
334   return olddata_val;
335 }
336
337 /**
338  * gst_mini_object_take:
339  * @olddata: (inout) (transfer full): pointer to a pointer to a mini-object to
340  *     be replaced
341  * @newdata: pointer to new mini-object
342  *
343  * Modifies a pointer to point to a new mini-object. The modification
344  * is done atomically. This version is similar to gst_mini_object_replace()
345  * except that it does not increase the refcount of @newdata and thus
346  * takes ownership of @newdata.
347  *
348  * Either @newdata and the value pointed to by @olddata may be NULL.
349  *
350  * Returns: TRUE if @newdata was different from @olddata
351  */
352 gboolean
353 gst_mini_object_take (GstMiniObject ** olddata, GstMiniObject * newdata)
354 {
355   GstMiniObject *olddata_val;
356
357   g_return_val_if_fail (olddata != NULL, FALSE);
358
359   GST_CAT_TRACE (GST_CAT_REFCOUNTING, "take %p (%d) with %p (%d)",
360       *olddata, *olddata ? (*olddata)->refcount : 0,
361       newdata, newdata ? newdata->refcount : 0);
362
363   do {
364     olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
365     if (G_UNLIKELY (olddata_val == newdata))
366       break;
367   } while (G_UNLIKELY (!g_atomic_pointer_compare_and_exchange ((gpointer *)
368               olddata, olddata_val, newdata)));
369
370   if (olddata_val)
371     gst_mini_object_unref (olddata_val);
372
373   return olddata_val != newdata;
374 }
375
376 /**
377  * gst_mini_object_weak_ref: (skip)
378  * @object: #GstMiniObject to reference weakly
379  * @notify: callback to invoke before the mini object is freed
380  * @data: extra data to pass to notify
381  *
382  * Adds a weak reference callback to a mini object. Weak references are
383  * used for notification when a mini object is finalized. They are called
384  * "weak references" because they allow you to safely hold a pointer
385  * to the mini object without calling gst_mini_object_ref()
386  * (gst_mini_object_ref() adds a strong reference, that is, forces the object
387  * to stay alive).
388  *
389  * Since: 0.10.35
390  */
391 void
392 gst_mini_object_weak_ref (GstMiniObject * object,
393     GstMiniObjectWeakNotify notify, gpointer data)
394 {
395   guint i;
396
397   g_return_if_fail (object != NULL);
398   g_return_if_fail (notify != NULL);
399   g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1);
400
401   G_LOCK (weak_refs_mutex);
402
403   if (object->n_weak_refs) {
404     /* Don't add the weak reference if it already exists. */
405     for (i = 0; i < object->n_weak_refs; i++) {
406       if (object->weak_refs[i].notify == notify &&
407           object->weak_refs[i].data == data) {
408         g_warning ("%s: Attempt to re-add existing weak ref %p(%p) failed.",
409             G_STRFUNC, notify, data);
410         goto found;
411       }
412     }
413
414     i = object->n_weak_refs++;
415     object->weak_refs =
416         g_realloc (object->weak_refs, sizeof (object->weak_refs[0]) * i);
417   } else {
418     object->weak_refs = g_malloc0 (sizeof (object->weak_refs[0]));
419     object->n_weak_refs = 1;
420     i = 0;
421   }
422   object->weak_refs[i].notify = notify;
423   object->weak_refs[i].data = data;
424 found:
425   G_UNLOCK (weak_refs_mutex);
426 }
427
428 /**
429  * gst_mini_object_weak_unref: (skip)
430  * @object: #GstMiniObject to remove a weak reference from
431  * @notify: callback to search for
432  * @data: data to search for
433  *
434  * Removes a weak reference callback to a mini object.
435  *
436  * Since: 0.10.35
437  */
438 void
439 gst_mini_object_weak_unref (GstMiniObject * object,
440     GstMiniObjectWeakNotify notify, gpointer data)
441 {
442   gboolean found_one = FALSE;
443
444   g_return_if_fail (object != NULL);
445   g_return_if_fail (notify != NULL);
446
447   G_LOCK (weak_refs_mutex);
448
449   if (object->n_weak_refs) {
450     guint i;
451
452     for (i = 0; i < object->n_weak_refs; i++)
453       if (object->weak_refs[i].notify == notify &&
454           object->weak_refs[i].data == data) {
455         found_one = TRUE;
456         object->n_weak_refs -= 1;
457         if (i != object->n_weak_refs)
458           object->weak_refs[i] = object->weak_refs[object->n_weak_refs];
459
460         break;
461       }
462   }
463   G_UNLOCK (weak_refs_mutex);
464   if (!found_one)
465     g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data);
466 }