memory: make the allocator refcounted
authorWim Taymans <wim.taymans@collabora.co.uk>
Mon, 30 Jan 2012 12:02:13 +0000 (13:02 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Mon, 30 Jan 2012 12:20:36 +0000 (13:20 +0100)
Add refcounting to the GstAllocator object.
Remove const from functions because the allocator is refcounted now.
Rename the vmethods for consistency
Expose the constructor for GstAllocator and add a destroy notify for the
user_data. This should make it possible to create allocators that are not
registered and shared globally along with the possibility to destroy them
properly.
Update defs with new symbols.

gst/gstbuffer.c
gst/gstbuffer.h
gst/gstmemory.c
gst/gstmemory.h
libs/gst/base/gstbasesrc.c
libs/gst/base/gstbasetransform.c
win32/common/libgstreamer.def

index fdfd6a4..d4e67a5 100644 (file)
@@ -479,8 +479,7 @@ gst_buffer_new (void)
  *     be allocated.
  */
 GstBuffer *
-gst_buffer_new_allocate (const GstAllocator * allocator, gsize size,
-    gsize align)
+gst_buffer_new_allocate (GstAllocator * allocator, gsize size, gsize align)
 {
   GstBuffer *newbuf;
   GstMemory *mem;
index 39d8d6f..2a945d6 100644 (file)
@@ -266,7 +266,7 @@ GType       gst_buffer_get_type            (void);
 
 /* allocation */
 GstBuffer * gst_buffer_new                 (void);
-GstBuffer * gst_buffer_new_allocate        (const GstAllocator * allocator, gsize size, gsize align);
+GstBuffer * gst_buffer_new_allocate        (GstAllocator * allocator, gsize size, gsize align);
 GstBuffer * gst_buffer_new_wrapped_full    (gpointer data, GFreeFunc free_func, gsize offset, gsize size);
 GstBuffer * gst_buffer_new_wrapped         (gpointer data, gsize size);
 
index 7f4d298..4e822ed 100644 (file)
@@ -93,9 +93,12 @@ size_t gst_memory_alignment = 0;
 
 struct _GstAllocator
 {
-  GQuark name;
+  gint refcount;
 
   GstMemoryInfo info;
+
+  gpointer user_data;
+  GDestroyNotify notify;
 };
 
 /* default memory implementation */
@@ -108,10 +111,10 @@ typedef struct
 } GstMemoryDefault;
 
 /* the default allocator */
-static const GstAllocator *_default_allocator;
+static GstAllocator *_default_allocator;
 
 /* our predefined allocators */
-static const GstAllocator *_default_mem_impl;
+static GstAllocator *_default_mem_impl;
 
 /* initialize the fields */
 static void
@@ -182,7 +185,8 @@ _default_mem_new_block (gsize maxsize, gsize align, gsize offset, gsize size)
 }
 
 static GstMemory *
-_default_mem_alloc (const GstAllocator * allocator, gsize maxsize, gsize align)
+_default_alloc_alloc (GstAllocator * allocator, gsize maxsize, gsize align,
+    gpointer user_data)
 {
   return (GstMemory *) _default_mem_new_block (maxsize, align, 0, maxsize);
 }
@@ -268,7 +272,7 @@ _default_mem_is_span (GstMemoryDefault * mem1, GstMemoryDefault * mem2,
 }
 
 static GstMemory *
-_fallback_copy (GstMemory * mem, gssize offset, gssize size)
+_fallback_mem_copy (GstMemory * mem, gssize offset, gssize size)
 {
   GstMemory *copy;
   GstMapInfo sinfo, dinfo;
@@ -295,7 +299,7 @@ _fallback_copy (GstMemory * mem, gssize offset, gssize size)
 }
 
 static gboolean
-_fallback_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
+_fallback_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
 {
   return FALSE;
 }
@@ -303,18 +307,23 @@ _fallback_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
 static GRWLock lock;
 static GHashTable *allocators;
 
+static void
+_priv_sysmem_notify (gpointer user_data)
+{
+  g_warning ("The default memory allocator was freed!");
+}
+
 void
 _priv_gst_memory_initialize (void)
 {
   static const GstMemoryInfo _mem_info = {
-    (GstMemoryAllocFunction) _default_mem_alloc,
+    (GstAllocatorAllocFunction) _default_alloc_alloc,
     (GstMemoryMapFunction) _default_mem_map,
     (GstMemoryUnmapFunction) _default_mem_unmap,
     (GstMemoryFreeFunction) _default_mem_free,
     (GstMemoryCopyFunction) _default_mem_copy,
     (GstMemoryShareFunction) _default_mem_share,
     (GstMemoryIsSpanFunction) _default_mem_is_span,
-    NULL
   };
 
   g_rw_lock_init (&lock);
@@ -328,9 +337,11 @@ _priv_gst_memory_initialize (void)
 
   GST_DEBUG ("memory alignment: %" G_GSIZE_FORMAT, gst_memory_alignment);
 
-  _default_mem_impl = gst_allocator_register (GST_ALLOCATOR_SYSMEM, &_mem_info);
+  _default_mem_impl = gst_allocator_new (&_mem_info, NULL, _priv_sysmem_notify);
 
-  _default_allocator = _default_mem_impl;
+  _default_allocator = gst_allocator_ref (_default_mem_impl);
+  gst_allocator_register (GST_ALLOCATOR_SYSMEM,
+      gst_allocator_ref (_default_mem_impl));
 }
 
 /**
@@ -396,7 +407,7 @@ gst_memory_unref (GstMemory * mem)
   GST_DEBUG ("memory %p, %d->%d", mem, mem->refcount, mem->refcount - 1);
 
   if (g_atomic_int_dec_and_test (&mem->refcount))
-    mem->allocator->info.free (mem);
+    mem->allocator->info.mem_free (mem);
 }
 
 /**
@@ -587,7 +598,7 @@ gst_memory_map (GstMemory * mem, GstMapInfo * info, GstMapFlags flags)
   if (!gst_memory_lock (mem, flags))
     goto lock_failed;
 
-  info->data = mem->allocator->info.map (mem, mem->maxsize, flags);
+  info->data = mem->allocator->info.mem_map (mem, mem->maxsize, flags);
 
   if (G_UNLIKELY (info->data == NULL))
     goto error;
@@ -631,7 +642,7 @@ gst_memory_unmap (GstMemory * mem, GstMapInfo * info)
   /* there must be a ref */
   g_return_if_fail (g_atomic_int_get (&mem->state) >= 4);
 
-  mem->allocator->info.unmap (mem);
+  mem->allocator->info.mem_unmap (mem);
   gst_memory_unlock (mem);
 }
 
@@ -655,7 +666,7 @@ gst_memory_copy (GstMemory * mem, gssize offset, gssize size)
   g_return_val_if_fail (mem != NULL, NULL);
   g_return_val_if_fail (gst_memory_lock (mem, GST_MAP_READ), NULL);
 
-  copy = mem->allocator->info.copy (mem, offset, size);
+  copy = mem->allocator->info.mem_copy (mem, offset, size);
 
   gst_memory_unlock (mem);
 
@@ -680,7 +691,7 @@ gst_memory_share (GstMemory * mem, gssize offset, gssize size)
 {
   g_return_val_if_fail (mem != NULL, NULL);
 
-  return mem->allocator->info.share (mem, offset, size);
+  return mem->allocator->info.mem_share (mem, offset, size);
 }
 
 /**
@@ -713,7 +724,7 @@ gst_memory_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
     return FALSE;
 
   /* and memory is contiguous */
-  if (!mem1->allocator->info.is_span (mem1, mem2, offset))
+  if (!mem1->allocator->info.mem_is_span (mem1, mem2, offset))
     return FALSE;
 
   return TRUE;
@@ -721,50 +732,112 @@ gst_memory_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
 
 /**
  * gst_allocator_register:
- * @name: the name of the allocator
- * @info: #GstMemoryInfo
+ * @info: a #GstMemoryInfo
+ * @user_data: user data
+ * @notify: a #GDestroyNotify for @user_data
  *
- * Registers the memory allocator with @name and implementation functions
- * @info.
+ * Create a new memory allocator with @info and @user_data.
  *
  * All functions in @info are mandatory exept the copy and is_span
  * functions, which will have a default implementation when left NULL.
  *
- * The user_data field in @info will be passed to all calls of the alloc
- * function.
+ * The @user_data will be passed to all calls of the alloc function and the
+ * @notify function.
  *
  * Returns: a new #GstAllocator.
  */
-const GstAllocator *
-gst_allocator_register (const gchar * name, const GstMemoryInfo * info)
+GstAllocator *
+gst_allocator_new (const GstMemoryInfo * info, gpointer user_data,
+    GDestroyNotify notify)
 {
   GstAllocator *allocator;
 
 #define INSTALL_FALLBACK(_t) \
   if (allocator->info._t == NULL) allocator->info._t = _fallback_ ##_t;
 
-  g_return_val_if_fail (name != NULL, NULL);
   g_return_val_if_fail (info != NULL, NULL);
   g_return_val_if_fail (info->alloc != NULL, NULL);
-  g_return_val_if_fail (info->map != NULL, NULL);
-  g_return_val_if_fail (info->unmap != NULL, NULL);
-  g_return_val_if_fail (info->free != NULL, NULL);
-  g_return_val_if_fail (info->share != NULL, NULL);
+  g_return_val_if_fail (info->mem_map != NULL, NULL);
+  g_return_val_if_fail (info->mem_unmap != NULL, NULL);
+  g_return_val_if_fail (info->mem_free != NULL, NULL);
+  g_return_val_if_fail (info->mem_share != NULL, NULL);
 
   allocator = g_slice_new (GstAllocator);
-  allocator->name = g_quark_from_string (name);
+  allocator->refcount = 1;
   allocator->info = *info;
-  INSTALL_FALLBACK (copy);
-  INSTALL_FALLBACK (is_span);
+  allocator->user_data = user_data;
+  allocator->notify = notify;
+  INSTALL_FALLBACK (mem_copy);
+  INSTALL_FALLBACK (mem_is_span);
 #undef INSTALL_FALLBACK
 
-  GST_DEBUG ("registering allocator \"%s\"", name);
+  GST_DEBUG ("new allocator %p", allocator);
+
+  return allocator;
+}
+
+/**
+ * gst_alocator_ref:
+ * @allocator: a #GstAllocator
+ *
+ * Increases the refcount of @allocator.
+ *
+ * Returns: @allocator with increased refcount
+ */
+GstAllocator *
+gst_allocator_ref (GstAllocator * allocator)
+{
+  g_return_val_if_fail (allocator != NULL, NULL);
+
+  GST_DEBUG ("alocator %p, %d->%d", allocator, allocator->refcount,
+      allocator->refcount + 1);
+
+  g_atomic_int_inc (&allocator->refcount);
+
+  return allocator;
+}
+
+/**
+ * gst_allocator_unref:
+ * @allocator: a #GstAllocator
+ *
+ * Decreases the refcount of @allocator. When the refcount reaches 0, the free
+ * function of @allocator will be called.
+ */
+void
+gst_allocator_unref (GstAllocator * allocator)
+{
+  g_return_if_fail (allocator != NULL);
+
+  GST_DEBUG ("allocator %p, %d->%d", allocator, allocator->refcount,
+      allocator->refcount - 1);
+
+  if (g_atomic_int_dec_and_test (&allocator->refcount)) {
+    if (allocator->notify)
+      allocator->notify (allocator->user_data);
+    g_slice_free1 (sizeof (GstAllocator), allocator);
+  }
+}
+
+/**
+ * gst_allocator_register:
+ * @name: the name of the allocator
+ * @allocator: (transfer full): #GstAllocator
+ *
+ * Registers the memory @allocator with @name. This function takes ownership of
+ * @allocator.
+ */
+void
+gst_allocator_register (const gchar * name, GstAllocator * allocator)
+{
+  g_return_if_fail (name != NULL);
+  g_return_if_fail (allocator != NULL);
+
+  GST_DEBUG ("registering allocator %p with name \"%s\"", allocator, name);
 
   g_rw_lock_writer_lock (&lock);
   g_hash_table_insert (allocators, (gpointer) name, (gpointer) allocator);
   g_rw_lock_writer_unlock (&lock);
-
-  return allocator;
 }
 
 /**
@@ -774,13 +847,13 @@ gst_allocator_register (const gchar * name, const GstMemoryInfo * info)
  * Find a previously registered allocator with @name. When @name is NULL, the
  * default allocator will be returned.
  *
- * Returns: a #GstAllocator or NULL when the allocator with @name was not
- * registered.
+ * Returns: (transfer full): a #GstAllocator or NULL when the allocator with @name was not
+ * registered. Use gst_allocator_unref() to release the allocator after usage.
  */
-const GstAllocator *
+GstAllocator *
 gst_allocator_find (const gchar * name)
 {
-  const GstAllocator *allocator;
+  GstAllocator *allocator;
 
   g_rw_lock_reader_lock (&lock);
   if (name) {
@@ -788,6 +861,8 @@ gst_allocator_find (const gchar * name)
   } else {
     allocator = _default_allocator;
   }
+  if (allocator)
+    gst_allocator_ref (allocator);
   g_rw_lock_reader_unlock (&lock);
 
   return allocator;
@@ -795,18 +870,23 @@ gst_allocator_find (const gchar * name)
 
 /**
  * gst_allocator_set_default:
- * @allocator: a #GstAllocator
+ * @allocator: (transfer full): a #GstAllocator
  *
- * Set the default allocator.
+ * Set the default allocator. This function takes ownership of @allocator.
  */
 void
-gst_allocator_set_default (const GstAllocator * allocator)
+gst_allocator_set_default (GstAllocator * allocator)
 {
+  GstAllocator *old;
   g_return_if_fail (allocator != NULL);
 
   g_rw_lock_writer_lock (&lock);
+  old = _default_allocator;
   _default_allocator = allocator;
   g_rw_lock_writer_unlock (&lock);
+
+  if (old)
+    gst_allocator_unref (old);
 }
 
 /**
@@ -826,7 +906,7 @@ gst_allocator_set_default (const GstAllocator * allocator)
  * Returns: (transfer full): a new #GstMemory.
  */
 GstMemory *
-gst_allocator_alloc (const GstAllocator * allocator, gsize maxsize, gsize align)
+gst_allocator_alloc (GstAllocator * allocator, gsize maxsize, gsize align)
 {
   g_return_val_if_fail (((align + 1) & align) == 0, NULL);
 
@@ -834,5 +914,5 @@ gst_allocator_alloc (const GstAllocator * allocator, gsize maxsize, gsize align)
     allocator = _default_allocator;
 
   return allocator->info.alloc (allocator, maxsize, align,
-      allocator->info.user_data);
+      allocator->user_data);
 }
index 6cebb76..f3d3095 100644 (file)
@@ -71,7 +71,7 @@ typedef enum {
  * as the first member of their structure.
  */
 struct _GstMemory {
-  const GstAllocator *allocator;
+  GstAllocator   *allocator;
 
   GstMemoryFlags  flags;
   gint            refcount;
@@ -134,7 +134,7 @@ typedef struct {
 #define GST_ALLOCATOR_SYSMEM   "SystemMemory"
 
 /**
- * GstMemoryAllocFunction:
+ * GstAllocatorAllocFunction:
  * @allocator: a #GstAllocator
  * @maxsize: the maxsize
  * @align: the alignment
@@ -143,13 +143,13 @@ typedef struct {
  * Allocate a new #GstMemory from @allocator that can hold at least @maxsize bytes
  * and is aligned to (@align + 1) bytes.
  *
- * @user_data is the data that was used when registering @allocator.
+ * @user_data is the data that was used when creating @allocator.
  *
  * Returns: a newly allocated #GstMemory. Free with gst_memory_unref()
  */
-typedef GstMemory *  (*GstMemoryAllocFunction)  (const GstAllocator *allocator,
-                                                 gsize maxsize, gsize align,
-                                                 gpointer user_data);
+typedef GstMemory *  (*GstAllocatorAllocFunction)  (GstAllocator *allocator,
+                                                    gsize maxsize, gsize align,
+                                                    gpointer user_data);
 
 /**
  * GstMemoryMapFunction:
@@ -229,42 +229,46 @@ typedef gboolean    (*GstMemoryIsSpanFunction)    (GstMemory *mem1, GstMemory *m
 
 /**
  * GstMemoryInfo:
- * @alloc: the implementation of the GstMemoryAllocFunction
- * @map: the implementation of the GstMemoryMapFunction
- * @unmap: the implementation of the GstMemoryUnmapFunction
- * @free: the implementation of the GstMemoryFreeFunction
- * @copy: the implementation of the GstMemoryCopyFunction
- * @share: the implementation of the GstMemoryShareFunction
- * @is_span: the implementation of the GstMemoryIsSpanFunction
- * @user_data: generic user data for the allocator
+ * @alloc: the implementation of the GstAllocatorAllocFunction
+ * @mem_map: the implementation of the GstMemoryMapFunction
+ * @mem_unmap: the implementation of the GstMemoryUnmapFunction
+ * @mem_free: the implementation of the GstMemoryFreeFunction
+ * @mem_copy: the implementation of the GstMemoryCopyFunction
+ * @mem_share: the implementation of the GstMemoryShareFunction
+ * @mem_is_span: the implementation of the GstMemoryIsSpanFunction
  *
  * The #GstMemoryInfo is used to register new memory allocators and contain
  * the implementations for various memory operations.
  */
 struct _GstMemoryInfo {
-  GstMemoryAllocFunction    alloc;
-  GstMemoryMapFunction      map;
-  GstMemoryUnmapFunction    unmap;
-  GstMemoryFreeFunction     free;
+  GstAllocatorAllocFunction alloc;
 
-  GstMemoryCopyFunction     copy;
-  GstMemoryShareFunction    share;
-  GstMemoryIsSpanFunction   is_span;
+  GstMemoryMapFunction      mem_map;
+  GstMemoryUnmapFunction    mem_unmap;
+  GstMemoryFreeFunction     mem_free;
 
-  gpointer user_data;
+  GstMemoryCopyFunction     mem_copy;
+  GstMemoryShareFunction    mem_share;
+  GstMemoryIsSpanFunction   mem_is_span;
 
   /*< private >*/
   gpointer _gst_reserved[GST_PADDING];
 };
 
 /* allocators */
-const GstAllocator *  gst_allocator_register    (const gchar *name, const GstMemoryInfo *info);
-const GstAllocator *  gst_allocator_find        (const gchar *name);
+GstAllocator *        gst_allocator_new         (const GstMemoryInfo * info,
+                                                 gpointer user_data, GDestroyNotify notify);
 
-void                  gst_allocator_set_default (const GstAllocator * allocator);
+GstAllocator *        gst_allocator_ref         (GstAllocator * allocator);
+void                  gst_allocator_unref       (GstAllocator * allocator);
+
+void                  gst_allocator_register    (const gchar *name, GstAllocator *alloc);
+GstAllocator *        gst_allocator_find        (const gchar *name);
+
+void                  gst_allocator_set_default (GstAllocator * allocator);
 
 /* allocating memory blocks */
-GstMemory * gst_allocator_alloc        (const GstAllocator * allocator,
+GstMemory * gst_allocator_alloc        (GstAllocator * allocator,
                                         gsize maxsize, gsize align);
 
 GstMemory * gst_memory_new_wrapped     (GstMemoryFlags flags, gpointer data, GFreeFunc free_func,
index 4430028..13b0c07 100644 (file)
@@ -246,7 +246,7 @@ struct _GstBaseSrcPrivate
   GstClockTime earliest_time;
 
   GstBufferPool *pool;
-  const GstAllocator *allocator;
+  GstAllocator *allocator;
   guint prefix;
   guint alignment;
 };
@@ -2701,8 +2701,9 @@ null_buffer:
 
 static gboolean
 gst_base_src_set_allocation (GstBaseSrc * basesrc, GstBufferPool * pool,
-    const GstAllocator * allocator, guint prefix, guint alignment)
+    GstAllocator * allocator, guint prefix, guint alignment)
 {
+  GstAllocator *oldalloc;
   GstBufferPool *oldpool;
   GstBaseSrcPrivate *priv = basesrc->priv;
 
@@ -2716,6 +2717,7 @@ gst_base_src_set_allocation (GstBaseSrc * basesrc, GstBufferPool * pool,
   oldpool = priv->pool;
   priv->pool = pool;
 
+  oldalloc = priv->allocator;
   priv->allocator = allocator;
 
   priv->prefix = prefix;
@@ -2730,6 +2732,9 @@ gst_base_src_set_allocation (GstBaseSrc * basesrc, GstBufferPool * pool,
     }
     gst_object_unref (oldpool);
   }
+  if (oldalloc) {
+    gst_allocator_unref (oldalloc);
+  }
   return TRUE;
 
   /* ERRORS */
@@ -2766,7 +2771,7 @@ gst_base_src_prepare_allocation (GstBaseSrc * basesrc, GstCaps * caps)
   gboolean result = TRUE;
   GstQuery *query;
   GstBufferPool *pool = NULL;
-  const GstAllocator *allocator = NULL;
+  GstAllocator *allocator = NULL;
   guint size, min, max, prefix, alignment;
 
   bclass = GST_BASE_SRC_GET_CLASS (basesrc);
index 698ce31..3735a19 100644 (file)
@@ -254,7 +254,7 @@ struct _GstBaseTransformPrivate
   GstClockTime position_out;
 
   GstBufferPool *pool;
-  const GstAllocator *allocator;
+  GstAllocator *allocator;
   guint prefix;
   guint alignment;
 };
@@ -747,9 +747,10 @@ done:
 
 static gboolean
 gst_base_transform_set_allocation (GstBaseTransform * trans,
-    GstBufferPool * pool, const GstAllocator * allocator, guint prefix,
+    GstBufferPool * pool, GstAllocator * allocator, guint prefix,
     guint alignment)
 {
+  GstAllocator *oldalloc;
   GstBufferPool *oldpool;
   GstBaseTransformPrivate *priv = trans->priv;
 
@@ -763,6 +764,7 @@ gst_base_transform_set_allocation (GstBaseTransform * trans,
   GST_OBJECT_LOCK (trans);
   oldpool = priv->pool;
   priv->pool = pool;
+  oldalloc = priv->allocator;
   priv->allocator = allocator;
   priv->prefix = prefix;
   priv->alignment = alignment;
@@ -773,6 +775,9 @@ gst_base_transform_set_allocation (GstBaseTransform * trans,
     gst_buffer_pool_set_active (oldpool, FALSE);
     gst_object_unref (oldpool);
   }
+  if (oldalloc) {
+    gst_allocator_unref (oldalloc);
+  }
   return TRUE;
 
   /* ERRORS */
@@ -791,7 +796,7 @@ gst_base_transform_do_bufferpool (GstBaseTransform * trans, GstCaps * outcaps)
   GstBufferPool *pool = NULL, *oldpool;
   guint size, min, max, prefix, alignment;
   GstBaseTransformClass *klass;
-  const GstAllocator *allocator = NULL;
+  GstAllocator *allocator = NULL;
 
   /* there are these possibilities:
    *
index 6fb08f1..68a5733 100644 (file)
@@ -51,8 +51,11 @@ EXPORTS
        _gst_trace_mutex DATA
        gst_allocator_alloc
        gst_allocator_find
+       gst_allocator_new
+       gst_allocator_ref
        gst_allocator_register
        gst_allocator_set_default
+       gst_allocator_unref
        gst_atomic_queue_length
        gst_atomic_queue_new
        gst_atomic_queue_peek