diff options
author | Anton Khirnov <anton@khirnov.net> | 2022-08-04 10:04:24 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2022-08-04 10:13:39 +0200 |
commit | 4c9009dd1b6fa98200d859df3a0a0ea7aa7e3ffc (patch) | |
tree | 1ba1b2c5b154732ffa8d66ed930e58e688d8de14 | |
parent | ad67ea9eeed2cc8edab8662b7503ce4a49247b1d (diff) |
lavu: add a public refcounting API
The AVBuffer API is currently often abused as a generic thread-safe
refcount in cases it is not appropriate for.
This API is intended to replace those uses.
-rw-r--r-- | libavutil/Makefile | 2 | ||||
-rw-r--r-- | libavutil/refcount.c | 61 | ||||
-rw-r--r-- | libavutil/refcount.h | 77 |
3 files changed, 140 insertions, 0 deletions
diff --git a/libavutil/Makefile b/libavutil/Makefile index 9435a0bfb0..e411b45ae7 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -70,6 +70,7 @@ HEADERS = adler32.h \ random_seed.h \ rc4.h \ rational.h \ + refcount.h \ replaygain.h \ ripemd.h \ samplefmt.h \ @@ -155,6 +156,7 @@ OBJS = adler32.o \ pixelutils.o \ random_seed.o \ rational.o \ + refcount.o \ reverse.o \ rc4.o \ ripemd.o \ diff --git a/libavutil/refcount.c b/libavutil/refcount.c new file mode 100644 index 0000000000..27c0718116 --- /dev/null +++ b/libavutil/refcount.c @@ -0,0 +1,61 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdatomic.h> + +#include "refcount.h" + +typedef struct AVRefcountImpl { + void (*free)(void *opaque); + void *opaque; + atomic_uint refcount; +} AVRefcountImpl; + + +void av_refcount_init(AVRefcount *rc, void (*free)(void *opaque), + void *opaque) +{ + AVRefcountImpl *rci = (AVRefcountImpl*)rc; + rci->free = free; + rci->opaque = opaque; + atomic_init(&rci->refcount, 1); +} + +void av_refcount_inc(AVRefcount *rc) +{ + AVRefcountImpl *rci = (AVRefcountImpl*)rc; + atomic_fetch_add_explicit(&rci->refcount, 1, memory_order_relaxed); +} + +unsigned int av_refcount_dec(AVRefcount *rc) +{ + AVRefcountImpl *rci = (AVRefcountImpl*)rc; + unsigned int ret = atomic_fetch_sub_explicit(&rci->refcount, 1, + memory_order_acq_rel) - 1; + + if (!ret && rci->free) + rci->free(rci->opaque); + + return ret; +} + +int av_refcount_exclusive(AVRefcount *rc) +{ + AVRefcountImpl *rci = (AVRefcountImpl*)rc; + return atomic_load(&rci->refcount) == 1; +} diff --git a/libavutil/refcount.h b/libavutil/refcount.h new file mode 100644 index 0000000000..92039ec020 --- /dev/null +++ b/libavutil/refcount.h @@ -0,0 +1,77 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REFCOUNT_H +#define AVUTIL_REFCOUNT_H + +#include <stdint.h> + +/** + * A thread-safe reference counter. + * + * Unlike most libav* structs, sizeof(AVRefcount) IS a part of the public ABI + * and so it can be embedded directly in other structs. + * + * None of its fields should be accessed directly by the caller, always use the + * av_refcount_*() functions. + */ +typedef struct AVRefcount { + void (*_internal0)(void *); + void *_internal1; + intmax_t _internal2; +} AVRefcount; + +/** + * Initialize an AVRefcount to a reference count of 1. This function MUST be + * called on an AVRefcount before doing anything else with it. + * + * @param free The callback to be invoked when the counter reaches zero. May be + * NULL, then nothing is called. + * @param opaque arbitrary user data that will be passed to the free() callback. + */ +void av_refcount_init(AVRefcount *rc, void (*free)(void *opaque), + void *opaque); + +/** + * Increase the reference count by 1. + */ +void av_refcount_inc(AVRefcount *rc); + +/** + * Decrease the reference count by 1. + * + * @return + * - 0 when the new reference count is 0. If a free() callback was passed to + * av_refcount_init(), it has been invoked. + * - a positive value when the new reference count is non-zero + * + * @note the return value is the new reference count, which may be useful for + * debugging, but this is not guaranteed by the API and the callers MUST NOT + * rely on this + */ +unsigned int av_refcount_dec(AVRefcount *rc); + +/** + * Check whether the caller is the exclusive owner of the reference. + * @return + * - a positive number if the reference count is exactly 1 + * - zero otherwise + */ +int av_refcount_exclusive(AVRefcount *rc); + +#endif /* AVUTIL_REFCOUNT_H */ |