X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstminiobject.c;h=123feff5eee5c1a1c891f7e8b8f1447dc2d1d886;hb=1be934f0ddac980437d800f4f5b79e3d5c91eafa;hp=78749ddc99074735448ee3cdc29f05c947abb641;hpb=5acdc22001033be1310fa9085b44ab79157e6f82;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstminiobject.c b/gst/gstminiobject.c index 78749dd..123feff 100644 --- a/gst/gstminiobject.c +++ b/gst/gstminiobject.c @@ -22,12 +22,33 @@ * SECTION:gstminiobject * @short_description: Lightweight base class for the GStreamer object hierarchy * - * #GstMiniObject is a baseclass like #GObject, but has been stripped down of - * features to be fast and small. - * It offers sub-classing and ref-counting in the same way as #GObject does. - * It has no properties and no signal-support though. + * #GstMiniObject is a simple structure that can be used to implement refcounted + * types. * - * Last reviewed on 2005-11-23 (0.9.5) + * Subclasses will include #GstMiniObject as the first member in their structure + * and then call gst_mini_object_init() to initialize the #GstMiniObject fields. + * + * gst_mini_object_ref() and gst_mini_object_unref() increment and decrement the + * refcount respectively. When the refcount of a mini-object reaches 0, the + * dispose function is called first and when this returns %TRUE, the free + * function of the miniobject is called. + * + * A copy can be made with gst_mini_object_copy(). + * + * gst_mini_object_is_writable() will return %TRUE when the refcount of the + * object is exactly 1, meaning the current caller has the only reference to the + * object. gst_mini_object_make_writable() will return a writable version of the + * object, which might be a new copy when the refcount was not 1. + * + * Opaque data can be associated with a #GstMiniObject with + * gst_mini_object_set_qdata() and gst_mini_object_get_qdata(). The data is + * meant to be specific to the particular object and is not automatically copied + * with gst_mini_object_copy() or similar methods. + * + * A weak reference can be added and remove with gst_mini_object_weak_ref() + * and gst_mini_object_weak_unref() respectively. + * + * Last reviewed on 2012-06-15 (0.11.93) */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -38,37 +59,72 @@ #include "gst/gstinfo.h" #include -#define GST_DISABLE_TRACE - #ifndef GST_DISABLE_TRACE #include "gsttrace.h" static GstAllocTrace *_gst_mini_object_trace; #endif /* Mutex used for weak referencing */ -G_LOCK_DEFINE_STATIC (weak_refs_mutex); +G_LOCK_DEFINE_STATIC (qdata_mutex); +static GQuark weak_ref_quark; + +typedef struct +{ + GQuark quark; + GstMiniObjectWeakNotify notify; + gpointer data; +} GstQData; + +#define QDATA(o,i) ((GstQData *)(o)->qdata)[(i)] +#define QDATA_QUARK(o,i) (QDATA(o,i).quark) +#define QDATA_NOTIFY(o,i) (QDATA(o,i).notify) +#define QDATA_DATA(o,i) (QDATA(o,i).data) + +void +_priv_gst_mini_object_initialize (void) +{ + weak_ref_quark = g_quark_from_static_string ("GstMiniObjectWeakRefQuark"); + +#ifndef GST_DISABLE_TRACE + _gst_mini_object_trace = _gst_alloc_trace_register ("GstMiniObject", 0); +#endif +} /** - * gst_mini_object_init: + * gst_mini_object_init: (skip) * @mini_object: a #GstMiniObject * @type: the #GType of the mini-object to create - * @size: the size of the data + * @copy_func: the copy function, or NULL + * @dispose_func: the dispose function, or NULL + * @free_func: the free function or NULL * - * Initializes a mini-object with the desired type and size. + * Initializes a mini-object with the desired type and copy/dispose/free + * functions. * * MT safe * * Returns: (transfer full): the new mini-object. */ void -gst_mini_object_init (GstMiniObject * mini_object, GType type, gsize size) +gst_mini_object_init (GstMiniObject * mini_object, GType type, + GstMiniObjectCopyFunction copy_func, + GstMiniObjectDisposeFunction dispose_func, + GstMiniObjectFreeFunction free_func) { mini_object->type = type; mini_object->refcount = 1; mini_object->flags = 0; - mini_object->size = size; - mini_object->n_weak_refs = 0; - mini_object->weak_refs = NULL; + + mini_object->copy = copy_func; + mini_object->dispose = dispose_func; + mini_object->free = free_func; + + mini_object->n_qdata = 0; + mini_object->qdata = NULL; + +#ifndef GST_DISABLE_TRACE + _gst_alloc_trace_new (_gst_mini_object_trace, mini_object); +#endif } /** @@ -101,9 +157,8 @@ gst_mini_object_copy (const GstMiniObject * mini_object) * @mini_object: the mini-object to check * * Checks if a mini-object is writable. A mini-object is writable - * if the reference count is one and the #GST_MINI_OBJECT_FLAG_READONLY - * flag is not set. Modification of a mini-object should only be - * done after verifying that it is writable. + * if the reference count is one. Modification of a mini-object should + * only be done after verifying that it is writable. * * MT safe * @@ -184,13 +239,13 @@ gst_mini_object_ref (GstMiniObject * mini_object) } static void -weak_refs_notify (GstMiniObject * obj) +qdata_notify (GstMiniObject * obj) { guint i; - for (i = 0; i < obj->n_weak_refs; i++) - obj->weak_refs[i].notify (obj->weak_refs[i].data, obj); - g_free (obj->weak_refs); + for (i = 0; i < obj->n_qdata; i++) + QDATA_NOTIFY (obj, i) (QDATA_DATA (obj, i), obj); + g_free (obj->qdata); } /** @@ -204,13 +259,14 @@ void gst_mini_object_unref (GstMiniObject * mini_object) { g_return_if_fail (mini_object != NULL); - g_return_if_fail (mini_object->refcount > 0); GST_CAT_TRACE (GST_CAT_REFCOUNTING, "%p unref %d->%d", mini_object, GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object), GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1); + g_return_if_fail (mini_object->refcount > 0); + if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) { gboolean do_free; @@ -223,11 +279,11 @@ gst_mini_object_unref (GstMiniObject * mini_object) * want to free the instance anymore */ if (G_LIKELY (do_free)) { /* The weak reference stack is freed in the notification function */ - if (mini_object->n_weak_refs) - weak_refs_notify (mini_object); + if (mini_object->n_qdata) + qdata_notify (mini_object); #ifndef GST_DISABLE_TRACE - gst_alloc_trace_free (_gst_mini_object_trace, mini_object); + _gst_alloc_trace_free (_gst_mini_object_trace, mini_object); #endif if (mini_object->free) mini_object->free (mini_object); @@ -375,31 +431,14 @@ gst_mini_object_weak_ref (GstMiniObject * object, g_return_if_fail (notify != NULL); g_return_if_fail (GST_MINI_OBJECT_REFCOUNT_VALUE (object) >= 1); - G_LOCK (weak_refs_mutex); - - if (object->n_weak_refs) { - /* Don't add the weak reference if it already exists. */ - for (i = 0; i < object->n_weak_refs; i++) { - if (object->weak_refs[i].notify == notify && - object->weak_refs[i].data == data) { - g_warning ("%s: Attempt to re-add existing weak ref %p(%p) failed.", - G_STRFUNC, notify, data); - goto found; - } - } - - i = object->n_weak_refs++; - object->weak_refs = - g_realloc (object->weak_refs, sizeof (object->weak_refs[0]) * i); - } else { - object->weak_refs = g_malloc0 (sizeof (object->weak_refs[0])); - object->n_weak_refs = 1; - i = 0; - } - object->weak_refs[i].notify = notify; - object->weak_refs[i].data = data; -found: - G_UNLOCK (weak_refs_mutex); + G_LOCK (qdata_mutex); + i = object->n_qdata++; + object->qdata = + g_realloc (object->qdata, sizeof (GstQData) * object->n_qdata); + QDATA_QUARK (object, i) = weak_ref_quark; + QDATA_NOTIFY (object, i) = notify; + QDATA_DATA (object, i) = data; + G_UNLOCK (qdata_mutex); } /** @@ -416,28 +455,124 @@ void gst_mini_object_weak_unref (GstMiniObject * object, GstMiniObjectWeakNotify notify, gpointer data) { + guint i; gboolean found_one = FALSE; g_return_if_fail (object != NULL); g_return_if_fail (notify != NULL); - G_LOCK (weak_refs_mutex); + G_LOCK (qdata_mutex); + for (i = 0; i < object->n_qdata; i++) { + if (QDATA_QUARK (object, i) == weak_ref_quark && + QDATA_NOTIFY (object, i) == notify && QDATA_DATA (object, i) == data) { + found_one = TRUE; + if (--object->n_qdata == 0) { + /* we don't shrink but free when everything is gone */ + g_free (object->qdata); + object->qdata = NULL; + } else if (i != object->n_qdata) + QDATA (object, i) = QDATA (object, object->n_qdata); + break; + } + } + G_UNLOCK (qdata_mutex); - if (object->n_weak_refs) { - guint i; + if (!found_one) + g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data); +} - for (i = 0; i < object->n_weak_refs; i++) - if (object->weak_refs[i].notify == notify && - object->weak_refs[i].data == data) { - found_one = TRUE; - object->n_weak_refs -= 1; - if (i != object->n_weak_refs) - object->weak_refs[i] = object->weak_refs[object->n_weak_refs]; +/** + * gst_mini_object_set_qdata: + * @object: a #GstMiniObject + * @quark: A #GQuark, naming the user data pointer + * @data: An opaque user data pointer + * @destroy: Function to invoke with @data as argument, when @data + * needs to be freed + * + * This sets an opaque, named pointer on a miniobject. + * The name is specified through a #GQuark (retrived e.g. via + * g_quark_from_static_string()), and the pointer + * can be gotten back from the @object with gst_mini_object_get_qdata() + * until the @object is disposed. + * Setting a previously set user data pointer, overrides (frees) + * the old pointer set, using #NULL as pointer essentially + * removes the data stored. + * + * @destroy may be specified which is called with @data as argument + * when the @object is disposed, or the data is being overwritten by + * a call to gst_mini_object_set_qdata() with the same @quark. + */ +void +gst_mini_object_set_qdata (GstMiniObject * object, GQuark quark, + gpointer data, GDestroyNotify destroy) +{ + guint i; + gpointer old_data = NULL; + GDestroyNotify old_notify = NULL; - break; + g_return_if_fail (object != NULL); + g_return_if_fail (quark > 0); + + G_LOCK (qdata_mutex); + for (i = 0; i < object->n_qdata; i++) { + if (QDATA_QUARK (object, i) == quark) { + old_data = QDATA_DATA (object, i); + old_notify = (GDestroyNotify) QDATA_NOTIFY (object, i); + + if (data == NULL) { + /* remove item */ + if (--object->n_qdata == 0) { + /* we don't shrink but free when everything is gone */ + g_free (object->qdata); + object->qdata = NULL; + } else if (i != object->n_qdata) + QDATA (object, i) = QDATA (object, object->n_qdata); } + break; + } } - G_UNLOCK (weak_refs_mutex); - if (!found_one) - g_warning ("%s: couldn't find weak ref %p(%p)", G_STRFUNC, notify, data); + if (!old_data) { + /* add item */ + i = object->n_qdata++; + object->qdata = + g_realloc (object->qdata, sizeof (GstQData) * object->n_qdata); + } + QDATA_QUARK (object, i) = quark; + QDATA_DATA (object, i) = data; + QDATA_NOTIFY (object, i) = (GstMiniObjectWeakNotify) destroy; + G_UNLOCK (qdata_mutex); + + if (old_notify) + old_notify (old_data); +} + +/** + * gst_mini_object_get_qdata: + * @object: The GstMiniObject to get a stored user data pointer from + * @quark: A #GQuark, naming the user data pointer + * + * This function gets back user data pointers stored via + * gst_mini_object_set_qdata(). + * + * Returns: (transfer none): The user data pointer set, or %NULL + */ +gpointer +gst_mini_object_get_qdata (GstMiniObject * object, GQuark quark) +{ + guint i; + gpointer result = NULL; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (quark > 0, NULL); + + G_LOCK (qdata_mutex); + for (i = 0; i < object->n_qdata; i++) { + if (QDATA_QUARK (object, i) == quark) { + result = QDATA_DATA (object, i); + break; + } + } + G_UNLOCK (qdata_mutex); + + return result; }