diff --git a/libavutil/buffer.c b/libavutil/buffer.c index 2b38081e1d..1bc4a93f38 100644 --- a/libavutil/buffer.c +++ b/libavutil/buffer.c @@ -23,6 +23,7 @@ #include "buffer_internal.h" #include "common.h" #include "mem.h" +#include "thread.h" AVBufferRef *av_buffer_create(uint8_t *data, int size, void (*free)(void *opaque, uint8_t *data), @@ -199,6 +200,8 @@ AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)) if (!pool) return NULL; + ff_mutex_init(&pool->mutex, NULL); + pool->size = size; pool->alloc = alloc ? alloc : av_buffer_alloc; @@ -220,6 +223,7 @@ static void buffer_pool_free(AVBufferPool *pool) buf->free(buf->opaque, buf->data); av_freep(&buf); } + ff_mutex_destroy(&pool->mutex); av_freep(&pool); } @@ -236,47 +240,16 @@ void av_buffer_pool_uninit(AVBufferPool **ppool) buffer_pool_free(pool); } -/* remove the whole buffer list from the pool and return it */ -static BufferPoolEntry *get_pool(AVBufferPool *pool) -{ - BufferPoolEntry *cur = NULL, *last = NULL; - - do { - FFSWAP(BufferPoolEntry*, cur, last); - cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL); - if (!cur) - return NULL; - } while (cur != last); - - return cur; -} - -static void add_to_pool(BufferPoolEntry *buf) -{ - AVBufferPool *pool; - BufferPoolEntry *cur, *end = buf; - - if (!buf) - return; - pool = buf->pool; - - while (end->next) - end = end->next; - - while ((cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf))) { - /* pool is not empty, retrieve it and append it to our list */ - cur = get_pool(pool); - end->next = cur; - while (end->next) - end = end->next; - } -} - static void pool_release_buffer(void *opaque, uint8_t *data) { BufferPoolEntry *buf = opaque; AVBufferPool *pool = buf->pool; - add_to_pool(buf); + + ff_mutex_lock(&pool->mutex); + buf->next = pool->pool; + pool->pool = buf; + ff_mutex_unlock(&pool->mutex); + if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1)) buffer_pool_free(pool); } @@ -306,8 +279,6 @@ static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool) ret->buffer->opaque = buf; ret->buffer->free = pool_release_buffer; - avpriv_atomic_int_add_and_fetch(&pool->refcount, 1); - return ret; } @@ -316,22 +287,22 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) AVBufferRef *ret; BufferPoolEntry *buf; - /* check whether the pool is empty */ - buf = get_pool(pool); - if (!buf) - return pool_alloc_buffer(pool); - - /* keep the first entry, return the rest of the list to the pool */ - add_to_pool(buf->next); - buf->next = NULL; - - ret = av_buffer_create(buf->data, pool->size, pool_release_buffer, - buf, 0); - if (!ret) { - add_to_pool(buf); - return NULL; + ff_mutex_lock(&pool->mutex); + buf = pool->pool; + if (buf) { + ret = av_buffer_create(buf->data, pool->size, pool_release_buffer, + buf, 0); + if (ret) { + pool->pool = buf->next; + buf->next = NULL; + } + } else { + ret = pool_alloc_buffer(pool); } - avpriv_atomic_int_add_and_fetch(&pool->refcount, 1); + ff_mutex_unlock(&pool->mutex); + + if (ret) + avpriv_atomic_int_add_and_fetch(&pool->refcount, 1); return ret; } diff --git a/libavutil/buffer_internal.h b/libavutil/buffer_internal.h index cce83c3cd1..1032a543e5 100644 --- a/libavutil/buffer_internal.h +++ b/libavutil/buffer_internal.h @@ -22,6 +22,7 @@ #include #include "buffer.h" +#include "thread.h" /** * The buffer is always treated as read-only. @@ -68,11 +69,12 @@ typedef struct BufferPoolEntry { void (*free)(void *opaque, uint8_t *data); AVBufferPool *pool; - struct BufferPoolEntry * volatile next; + struct BufferPoolEntry *next; } BufferPoolEntry; struct AVBufferPool { - BufferPoolEntry * volatile pool; + AVMutex mutex; + BufferPoolEntry *pool; /* * This is used to track when the pool is to be freed.