miniobject: avoid race in bufferpool release

Avoid playing with the refcount to decide when a buffer has been recycled by the
dispose function. The problem is that we then temporarily can have a buffer with
a refcount > 1 being acquired from the pool, which is not writable. Instead use
a simple boolean return value from the dispose function to inform the called
that the object was recycled or not.
This commit is contained in:
Wim Taymans 2011-07-25 12:53:10 +02:00
parent c887dd41f8
commit ee235a6b07
3 changed files with 23 additions and 18 deletions

View file

@ -363,18 +363,22 @@ _gst_buffer_copy (GstBuffer * buffer)
/* the default dispose function revives the buffer and returns it to the
* pool when there is a pool */
static void
static gboolean
_gst_buffer_dispose (GstBuffer * buffer)
{
GstBufferPool *pool;
if ((pool = buffer->pool) != NULL) {
/* keep the buffer alive */
gst_buffer_ref (buffer);
/* return the buffer to the pool */
GST_CAT_LOG (GST_CAT_BUFFER, "release %p to pool %p", buffer, pool);
gst_buffer_pool_release_buffer (pool, buffer);
}
/* no pool, do free */
if ((pool = buffer->pool) == NULL)
return TRUE;
/* keep the buffer alive */
gst_buffer_ref (buffer);
/* return the buffer to the pool */
GST_CAT_LOG (GST_CAT_BUFFER, "release %p to pool %p", buffer, pool);
gst_buffer_pool_release_buffer (pool, buffer);
return FALSE;
}
static void

View file

@ -254,17 +254,16 @@ gst_mini_object_unref (GstMiniObject * mini_object)
GST_MINI_OBJECT_REFCOUNT_VALUE (mini_object) - 1);
if (G_UNLIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
/* At this point, the refcount of the object is 0. We increase the refcount
* here because if a subclass recycles the object and gives out a new
* reference we don't want to free the instance anymore. */
gst_mini_object_ref (mini_object);
gboolean do_free;
if (mini_object->dispose)
mini_object->dispose (mini_object);
do_free = mini_object->dispose (mini_object);
else
do_free = TRUE;
/* decrement the refcount again, if the subclass recycled the object we don't
/* if the subclass recycled the object (and returned FALSE) we don't
* want to free the instance anymore */
if (G_LIKELY (g_atomic_int_dec_and_test (&mini_object->refcount))) {
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);

View file

@ -52,10 +52,12 @@ typedef GstMiniObject * (*GstMiniObjectCopyFunction) (const GstMiniObject *obj);
* Function prototype for when a miniobject has lost its last refcount.
* Implementation of the mini object are allowed to revive the
* passed object by doing a gst_mini_object_ref(). If the object is not
* revived after the dispose function, the memory associated with the
* object is freed.
* revived after the dispose function, the function should return %TRUE
* and the memory associated with the object is freed.
*
* Returns: %TRUE if the object should be cleaned up.
*/
typedef void (*GstMiniObjectDisposeFunction) (GstMiniObject *obj);
typedef gboolean (*GstMiniObjectDisposeFunction) (GstMiniObject *obj);
/**
* GstMiniObjectFreeFunction:
* @obj: MiniObject to free