summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2022-08-04 10:04:24 +0200
committerAnton Khirnov <anton@khirnov.net>2022-08-04 10:13:39 +0200
commit4c9009dd1b6fa98200d859df3a0a0ea7aa7e3ffc (patch)
tree1ba1b2c5b154732ffa8d66ed930e58e688d8de14
parentad67ea9eeed2cc8edab8662b7503ce4a49247b1d (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/Makefile2
-rw-r--r--libavutil/refcount.c61
-rw-r--r--libavutil/refcount.h77
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 */