Commit af2fc026 authored by Wim Taymans's avatar Wim Taymans

memory: make the allocator refcounted

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.
parent d9577f26
......@@ -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;
......
......@@ -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);
......
......@@ -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);
}
......@@ -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,
......
......@@ -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);
......
......@@ -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:
*
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment