From 2745b823ab1e426b9926868f85a4e196905dc161 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Thu, 21 Jun 2001 11:19:08 +0000 Subject: [PATCH] added ref counting to the buffer pool. also _destroy will clean up the buffer pool mem_chunk if it is the default imp... Original commit message from CVS: added ref counting to the buffer pool. also _destroy will clean up the buffer pool mem_chunk if it is the default implementation --- gst/gstbufferpool.c | 162 +++++++++++++++++++++++++++++++++++++++----- gst/gstbufferpool.h | 25 ++++++- 2 files changed, 168 insertions(+), 19 deletions(-) diff --git a/gst/gstbufferpool.c b/gst/gstbufferpool.c index 78d294b468..8d81f2cf0d 100644 --- a/gst/gstbufferpool.c +++ b/gst/gstbufferpool.c @@ -25,7 +25,7 @@ #include "gstbuffer.h" -static GMutex *default_pool_lock; +static GMutex *_default_pool_lock; static GHashTable *_default_pools; static GstBuffer* gst_buffer_pool_default_create (GstBufferPool *pool, gpointer user_data); @@ -35,7 +35,7 @@ void _gst_buffer_pool_initialize (void) { _default_pools = g_hash_table_new(NULL,NULL); - default_pool_lock = g_mutex_new (); + _default_pool_lock = g_mutex_new (); } /** @@ -55,10 +55,97 @@ gst_buffer_pool_new (void) pool->new_buffer = NULL; pool->destroy_buffer = NULL; - + pool->lock = g_mutex_new (); +#ifdef HAVE_ATOMIC_H + atomic_set (&pool->refcount, 1); +#else + pool->refcount = 1; +#endif + return pool; } +/** + * gst_buffer_pool_ref: + * @pool: the GstBufferPool to reference + * + * Increment the refcount of this buffer pool. + */ +void +gst_buffer_pool_ref (GstBufferPool *pool) +{ + g_return_if_fail (pool != NULL); + + GST_DEBUG(0,"referencing buffer pool %p from %d\n", pool, GST_BUFFER_POOL_REFCOUNT(pool)); + +#ifdef HAVE_ATOMIC_H + atomic_inc (&(pool->refcount)); +#else + g_return_if_fail (pool->refcount > 0); + GST_BUFFER_POOL_LOCK (pool); + buffer->refcount++; + GST_BUFFER_POOL_UNLOCK (pool); +#endif +} + +/** + * gst_buffer_pool_ref_by_count: + * @pool: the GstBufferPool to reference + * @count: a number + * + * Increment the refcount of this buffer pool by the given number. + */ +void +gst_buffer_pool_ref_by_count (GstBufferPool *pool, int count) +{ + g_return_if_fail (pool != NULL); + g_return_if_fail (count > 0); + +#ifdef HAVE_ATOMIC_H + g_return_if_fail (atomic_read (&(pool->refcount)) > 0); + atomic_add (count, &(pool->refcount)); +#else + g_return_if_fail (pool->refcount > 0); + GST_BUFFER_POOL_LOCK (pool); + pool->refcount += count; + GST_BUFFER_POOL_UNLOCK (pool); +#endif +} + +/** + * gst_buffer_pool_unref: + * @pool: the GstBufferPool to unref + * + * Decrement the refcount of this buffer pool. If the refcount is + * zero and the pool is a default implementation, + * the buffer pool will be destroyed. + */ +void +gst_buffer_pool_unref (GstBufferPool *pool) +{ + gint zero; + + g_return_if_fail (pool != NULL); + + GST_DEBUG(0,"unreferencing buffer pool %p from %d\n", pool, GST_BUFFER_POOL_REFCOUNT(pool)); + +#ifdef HAVE_ATOMIC_H + g_return_if_fail (atomic_read (&(pool->refcount)) > 0); + zero = atomic_dec_and_test (&(pool->refcount)); +#else + g_return_if_fail (pool->refcount > 0); + GST_BUFFER_POOL_LOCK (pool); + pool->refcount--; + zero = (pool->refcount == 0); + GST_BUFFER_POOL_UNLOCK (pool); +#endif + + /* if we ended up with the refcount at zero, destroy the buffer pool*/ + if (zero) { + gst_buffer_pool_destroy (pool); + } +} + /** * gst_buffer_pool_set_create_function: * @pool: the pool to set the create function for @@ -108,8 +195,18 @@ gst_buffer_pool_set_destroy_function (GstBufferPool *pool, void gst_buffer_pool_destroy (GstBufferPool *pool) { + GMemChunk *data_chunk; g_return_if_fail (pool != NULL); - + + // if its a default buffer pool, we know how to free the user data + if (pool->new_buffer == gst_buffer_pool_default_create && + pool->destroy_buffer == gst_buffer_pool_default_destroy){ + GST_DEBUG(0,"destroying default buffer pool %p\n", pool); + data_chunk = (GMemChunk*)pool->new_user_data; + g_mem_chunk_reset(data_chunk); + g_free(data_chunk); + } + g_free(pool); } @@ -151,23 +248,46 @@ gst_buffer_pool_destroy_buffer (GstBufferPool *pool, pool->destroy_buffer (pool, buffer, pool->new_user_data); } +/** + * gst_buffer_pool_get_default: + * @pool: instance of GstBufferPool which is no longer required (or NULL if it doesn't exist) + * @buffer_size: the number of bytes this buffer will store + * @pool_size: the default number of buffers to be preallocated + * + * Returns an instance of a buffer pool using the default + * implementation. If a buffer pool instance with the same buffer_size + * already exists this will be returned, otherwise a new instance will + * be created. + * + * Returns: an instance of GstBufferPool + */ GstBufferPool* -gst_buffer_pool_get_default (guint buffer_size, guint pool_size) +gst_buffer_pool_get_default (GstBufferPool *oldpool, guint buffer_size, guint pool_size) { GstBufferPool *pool; GMemChunk *data_chunk; guint real_buffer_size; + + // round up to the nearest 32 bytes for cache-line and other efficiencies + real_buffer_size = (((buffer_size-1) / 32) + 1) * 32; - // check for an existing GstBufferPool with the same buffer_size + // check for an existing GstBufferPool with the same real_buffer_size // (we won't worry about the pool_size) - if ((pool = (GstBufferPool*)g_hash_table_lookup(_default_pools,GINT_TO_POINTER(buffer_size)))){ + g_mutex_lock (_default_pool_lock); + pool = (GstBufferPool*)g_hash_table_lookup(_default_pools,GINT_TO_POINTER(real_buffer_size)); + g_mutex_unlock (_default_pool_lock); + + if (pool != NULL){ + if (oldpool != pool){ + gst_buffer_pool_ref(pool); + + if (oldpool != NULL){ + gst_buffer_pool_unref(oldpool); + } + } return pool; } - // g_print("new buffer pool bytes:%d size:%d\n", buffer_size, pool_size); - - // round up to the nearest 32 bytes for cache-line and other efficiencies - real_buffer_size = ((buffer_size-1 / 32) + 1) * 32; data_chunk = g_mem_chunk_new ("GstBufferPoolDefault", real_buffer_size, real_buffer_size * pool_size, G_ALLOC_AND_FREE); @@ -176,7 +296,15 @@ gst_buffer_pool_get_default (guint buffer_size, guint pool_size) gst_buffer_pool_set_create_function (pool, gst_buffer_pool_default_create, data_chunk); gst_buffer_pool_set_destroy_function (pool, gst_buffer_pool_default_destroy, data_chunk); - g_hash_table_insert(_default_pools,GINT_TO_POINTER(buffer_size),pool); + g_mutex_lock (_default_pool_lock); + g_hash_table_insert(_default_pools,GINT_TO_POINTER(real_buffer_size),pool); + g_mutex_unlock (_default_pool_lock); + + GST_DEBUG(0,"new buffer pool %p bytes:%d size:%d\n", pool, real_buffer_size, pool_size); + + if (oldpool != NULL){ + gst_buffer_pool_unref(oldpool); + } return pool; } @@ -186,13 +314,14 @@ gst_buffer_pool_default_create (GstBufferPool *pool, gpointer user_data) GMemChunk *data_chunk = (GMemChunk*)user_data; GstBuffer *buffer; + gst_buffer_pool_ref(pool); buffer = gst_buffer_new(); GST_BUFFER_FLAG_SET(buffer,GST_BUFFER_DONTFREE); buffer->pool = pool; - g_mutex_lock (default_pool_lock); + g_mutex_lock (pool->lock); GST_BUFFER_DATA(buffer) = g_mem_chunk_alloc(data_chunk); - g_mutex_unlock (default_pool_lock); + g_mutex_unlock (pool->lock); return buffer; } @@ -203,11 +332,12 @@ gst_buffer_pool_default_destroy (GstBufferPool *pool, GstBuffer *buffer, gpointe GMemChunk *data_chunk = (GMemChunk*)user_data; gpointer data = GST_BUFFER_DATA(buffer); - g_mutex_lock (default_pool_lock); + g_mutex_lock (pool->lock); g_mem_chunk_free (data_chunk,data); - g_mutex_unlock (default_pool_lock); + g_mutex_unlock (pool->lock); buffer->pool = NULL; + gst_buffer_pool_unref(pool); gst_buffer_destroy (buffer); } diff --git a/gst/gstbufferpool.h b/gst/gstbufferpool.h index 1b7fa47292..e8b8908dbc 100644 --- a/gst/gstbufferpool.h +++ b/gst/gstbufferpool.h @@ -31,8 +31,9 @@ extern "C" { #endif /* __cplusplus */ -#define GST_BUFFER_POOL(buf) \ - ((GstBufferPool *)(buf)) +#define GST_BUFFER_POOL(pool) \ + ((GstBufferPool *)(pool)) +#define GST_BUFFER_POOL_LOCK(pool) (g_mutex_lock(GST_BUFFER_POOL(pool)->lock)) typedef struct _GstBufferPool GstBufferPool; @@ -40,6 +41,18 @@ typedef GstBuffer* (*GstBufferPoolCreateFunction) (GstBufferPool *pool, gpointe typedef void (*GstBufferPoolDestroyFunction) (GstBufferPool *pool, GstBuffer *buffer, gpointer user_data); struct _GstBufferPool { + /* locking */ + GMutex *lock; + + /* refcounting */ +#ifdef HAVE_ATOMIC_H + atomic_t refcount; +#define GST_BUFFER_POOL_REFCOUNT(pool) (atomic_read(&(GST_BUFFER_POOL((pool))->refcount))) +#else + int refcount; +#define GST_BUFFER_POOL_REFCOUNT(pool) (GST_BUFFER_POOL(pool)->refcount) +#endif + /* will be called when a new buffer is to be created */ GstBufferPoolCreateFunction new_buffer; /* user data to pass with the new_buffer function */ @@ -47,6 +60,7 @@ struct _GstBufferPool { gpointer destroy_user_data; GstBufferPoolDestroyFunction destroy_buffer; + }; void _gst_buffer_pool_initialize (void); @@ -58,6 +72,11 @@ GstBufferPool* gst_buffer_pool_new (void); GstBuffer* gst_buffer_pool_new_buffer (GstBufferPool *pool); void gst_buffer_pool_destroy_buffer (GstBufferPool *pool, GstBuffer *buffer); +/* refcounting */ +void gst_buffer_pool_ref (GstBufferPool *pool); +void gst_buffer_pool_ref_by_count (GstBufferPool *pool, int count); +void gst_buffer_pool_unref (GstBufferPool *buffer); + /* setting create and destroy functions */ void gst_buffer_pool_set_create_function (GstBufferPool *pool, GstBufferPoolCreateFunction create, @@ -70,7 +89,7 @@ void gst_buffer_pool_set_destroy_function (GstBufferPool *pool, void gst_buffer_pool_destroy (GstBufferPool *pool); /* a default buffer pool implementation */ -GstBufferPool* gst_buffer_pool_get_default (guint buffer_size, guint pool_size); +GstBufferPool* gst_buffer_pool_get_default (GstBufferPool *oldpool, guint buffer_size, guint pool_size); #ifdef __cplusplus }