Bug Summary

File:root/firefox-clang/media/ffvpx/libavutil/refstruct.c
Warning:line 279, column 21
Called function pointer is null (null dereference)

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name refstruct.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/ffvpx/libavutil -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/ffvpx/libavutil -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -include libavutil_visibility.h -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D HAVE_AV_CONFIG_H -D ASSERT_LEVEL=2 -I /root/firefox-clang/media/ffvpx/libavutil -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/media/ffvpx/libavutil -I /root/firefox-clang/third_party/khronos/vulkan-headers/include -I /root/firefox-clang/media/mozva -I /root/firefox-clang/media/ffvpx -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-character-conversion -Wno-parentheses -Wno-pointer-sign -Wno-sign-compare -Wno-switch -Wno-type-limits -Wno-unused-function -Wno-deprecated-declarations -Wno-absolute-value -Wno-incompatible-pointer-types -Wno-string-conversion -Wno-visibility -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c /root/firefox-clang/media/ffvpx/libavutil/refstruct.c

/root/firefox-clang/media/ffvpx/libavutil/refstruct.c

1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <stdatomic.h>
20#include <stdint.h>
21#include <string.h>
22
23#include "refstruct.h"
24
25#include "avassert.h"
26#include "error.h"
27#include "macros.h"
28#include "mem.h"
29#include "mem_internal.h"
30#include "thread.h"
31
32#ifndef REFSTRUCT_CHECKED(2 >= 1)
33#ifndef ASSERT_LEVEL2
34#define ASSERT_LEVEL2 0
35#endif
36#define REFSTRUCT_CHECKED(2 >= 1) (ASSERT_LEVEL2 >= 1)
37#endif
38
39#if REFSTRUCT_CHECKED(2 >= 1)
40#define ff_assert(cond)do { if (!(cond)) { av_log(((void*)0), 0, "Assertion %s failed at %s:%d\n"
, "cond", "/root/firefox-clang/media/ffvpx/libavutil/refstruct.c"
, 40); abort(); } } while (0)
av_assert0(cond)do { if (!(cond)) { av_log(((void*)0), 0, "Assertion %s failed at %s:%d\n"
, "cond", "/root/firefox-clang/media/ffvpx/libavutil/refstruct.c"
, 40); abort(); } } while (0)
41#else
42#define ff_assert(cond)do { if (!(cond)) { av_log(((void*)0), 0, "Assertion %s failed at %s:%d\n"
, "cond", "/root/firefox-clang/media/ffvpx/libavutil/refstruct.c"
, 42); abort(); } } while (0)
((void)0)
43#endif
44
45#define REFSTRUCT_COOKIE((('R') | (('e') << 8) | (('f') << 16) | ((unsigned
)('S') << 24)) | (uint64_t)(('t') | (('r') << 8) |
(('u') << 16) | ((unsigned)('c') << 24)) <<
32)
AV_NE((uint64_t)MKBETAG('R', 'e', 'f', 'S') << 32 | MKBETAG('t', 'r', 'u', 'c'), \((('R') | (('e') << 8) | (('f') << 16) | ((unsigned
)('S') << 24)) | (uint64_t)(('t') | (('r') << 8) |
(('u') << 16) | ((unsigned)('c') << 24)) <<
32)
46 MKTAG('R', 'e', 'f', 'S') | (uint64_t)MKTAG('t', 'r', 'u', 'c') << 32)((('R') | (('e') << 8) | (('f') << 16) | ((unsigned
)('S') << 24)) | (uint64_t)(('t') | (('r') << 8) |
(('u') << 16) | ((unsigned)('c') << 24)) <<
32)
47
48#ifndef _MSC_VER
49#define REFCOUNT_OFFSET(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
FFALIGN(sizeof(RefCount), FFMAX(ALIGN_64, _Alignof(max_align_t)))(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
50#else
51#define REFCOUNT_OFFSET(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
FFALIGN(sizeof(RefCount), ALIGN_64)(((sizeof(RefCount))+(64)-1)&~((64)-1))
52#endif
53
54typedef struct RefCount {
55 /**
56 * An uintptr_t is big enough to hold the address of every reference,
57 * so no overflow can happen when incrementing the refcount as long as
58 * the user does not throw away references.
59 */
60 atomic_uintptr_t refcount;
61 AVRefStructOpaque opaque;
62 void (*free_cb)(AVRefStructOpaque opaque, void *obj);
63 void (*free)(void *ref);
64
65#if REFSTRUCT_CHECKED(2 >= 1)
66 uint64_t cookie;
67#endif
68} RefCount;
69
70static RefCount *get_refcount(void *obj)
71{
72 RefCount *ref = (RefCount*)((char*)obj - REFCOUNT_OFFSET(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
);
73 ff_assert(ref->cookie == REFSTRUCT_COOKIE)do { if (!(ref->cookie == ((('R') | (('e') << 8) | (
('f') << 16) | ((unsigned)('S') << 24)) | (uint64_t
)(('t') | (('r') << 8) | (('u') << 16) | ((unsigned
)('c') << 24)) << 32))) { av_log(((void*)0), 0, "Assertion %s failed at %s:%d\n"
, "ref->cookie == ((('R') | (('e') << 8) | (('f') << 16) | ((unsigned)('S') << 24)) | (uint64_t)(('t') | (('r') << 8) | (('u') << 16) | ((unsigned)('c') << 24)) << 32)"
, "/root/firefox-clang/media/ffvpx/libavutil/refstruct.c", 73
); abort(); } } while (0)
;
74 return ref;
75}
76
77static const RefCount *cget_refcount(const void *obj)
78{
79 const RefCount *ref = (const RefCount*)((const char*)obj - REFCOUNT_OFFSET(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
);
80 ff_assert(ref->cookie == REFSTRUCT_COOKIE)do { if (!(ref->cookie == ((('R') | (('e') << 8) | (
('f') << 16) | ((unsigned)('S') << 24)) | (uint64_t
)(('t') | (('r') << 8) | (('u') << 16) | ((unsigned
)('c') << 24)) << 32))) { av_log(((void*)0), 0, "Assertion %s failed at %s:%d\n"
, "ref->cookie == ((('R') | (('e') << 8) | (('f') << 16) | ((unsigned)('S') << 24)) | (uint64_t)(('t') | (('r') << 8) | (('u') << 16) | ((unsigned)('c') << 24)) << 32)"
, "/root/firefox-clang/media/ffvpx/libavutil/refstruct.c", 80
); abort(); } } while (0)
;
81 return ref;
82}
83
84static void *get_userdata(void *buf)
85{
86 return (char*)buf + REFCOUNT_OFFSET(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
;
31
'?' condition is true
32
'?' condition is true
33
Returning pointer, which participates in a condition later
87}
88
89static void refcount_init(RefCount *ref, AVRefStructOpaque opaque,
90 void (*free_cb)(AVRefStructOpaque opaque, void *obj))
91{
92 atomic_init__c11_atomic_init(&ref->refcount, 1);
28
Assigning value, which participates in a condition later
93 ref->opaque = opaque;
94 ref->free_cb = free_cb;
95 ref->free = av_free;
96
97#if REFSTRUCT_CHECKED(2 >= 1)
98 ref->cookie = REFSTRUCT_COOKIE((('R') | (('e') << 8) | (('f') << 16) | ((unsigned
)('S') << 24)) | (uint64_t)(('t') | (('r') << 8) |
(('u') << 16) | ((unsigned)('c') << 24)) <<
32)
;
99#endif
100}
101
102void *av_refstruct_alloc_ext_c(size_t size, unsigned flags, AVRefStructOpaque opaque,
103 void (*free_cb)(AVRefStructOpaque opaque, void *obj))
104{
105 void *buf, *obj;
106
107 if (size > SIZE_MAX(18446744073709551615UL) - REFCOUNT_OFFSET(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
)
19
'?' condition is true
20
'?' condition is true
21
Assuming the condition is false
22
Taking false branch
108 return NULL((void*)0);
109 buf = av_malloc(size + REFCOUNT_OFFSET(((sizeof(RefCount))+(((64) > (_Alignof(max_align_t)) ? (64
) : (_Alignof(max_align_t))))-1)&~((((64) > (_Alignof(
max_align_t)) ? (64) : (_Alignof(max_align_t))))-1))
);
23
'?' condition is true
24
'?' condition is true
110 if (!buf)
25
Assuming 'buf' is non-null, which participates in a condition later
26
Taking false branch
111 return NULL((void*)0);
112 refcount_init(buf, opaque, free_cb);
27
Calling 'refcount_init'
29
Returning from 'refcount_init'
113 obj = get_userdata(buf);
30
Calling 'get_userdata'
34
Returning from 'get_userdata'
114 if (!(flags & AV_REFSTRUCT_FLAG_NO_ZEROING(1 << 0)))
35
Assuming the condition is false
36
Taking false branch
115 memset(obj, 0, size);
116
117 return obj;
37
Returning pointer (loaded from 'obj'), which participates in a condition later
118}
119
120void av_refstruct_unref(void *objp)
121{
122 void *obj;
123 RefCount *ref;
124
125 memcpy(&obj, objp, sizeof(obj));
126 if (!obj)
127 return;
128 memcpy(objp, &(void *){ NULL((void*)0) }, sizeof(obj));
129
130 ref = get_refcount(obj);
131 if (atomic_fetch_sub_explicit__c11_atomic_fetch_sub(&ref->refcount, 1, memory_order_acq_rel) == 1) {
132 if (ref->free_cb)
133 ref->free_cb(ref->opaque, obj);
134 ref->free(ref);
135 }
136
137 return;
138}
139
140void *av_refstruct_ref(void *obj)
141{
142 RefCount *ref = get_refcount(obj);
143
144 atomic_fetch_add_explicit__c11_atomic_fetch_add(&ref->refcount, 1, memory_order_relaxed);
145
146 return obj;
147}
148
149const void *av_refstruct_ref_c(const void *obj)
150{
151 /* Casting const away here is fine, as it is only supposed
152 * to apply to the user's data and not our bookkeeping data. */
153 RefCount *ref = get_refcount((void*)obj);
154
155 atomic_fetch_add_explicit__c11_atomic_fetch_add(&ref->refcount, 1, memory_order_relaxed);
156
157 return obj;
158}
159
160void av_refstruct_replace(void *dstp, const void *src)
161{
162 const void *dst;
163 memcpy(&dst, dstp, sizeof(dst));
164
165 if (src == dst)
166 return;
167 av_refstruct_unref(dstp);
168 if (src) {
169 dst = av_refstruct_ref_c(src);
170 memcpy(dstp, &dst, sizeof(dst));
171 }
172}
173
174int av_refstruct_exclusive(const void *obj)
175{
176 const RefCount *ref = cget_refcount(obj);
177 /* Casting const away here is safe, because it is a load.
178 * It is necessary because atomic_load_explicit() does not
179 * accept const atomics in C11 (see also N1807). */
180 return atomic_load_explicit__c11_atomic_load((atomic_uintptr_t*)&ref->refcount, memory_order_acquire) == 1;
181}
182
183struct AVRefStructPool {
184 size_t size;
185 AVRefStructOpaque opaque;
186 int (*init_cb)(AVRefStructOpaque opaque, void *obj);
187 void (*reset_cb)(AVRefStructOpaque opaque, void *obj);
188 void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj);
189 void (*free_cb)(AVRefStructOpaque opaque);
190
191 int uninited;
192 unsigned entry_flags;
193 unsigned pool_flags;
194
195 /** The number of outstanding entries not in available_entries. */
196 atomic_uintptr_t refcount;
197 /**
198 * This is a linked list of available entries;
199 * the RefCount's opaque pointer is used as next pointer
200 * for available entries.
201 * While the entries are in use, the opaque is a pointer
202 * to the corresponding AVRefStructPool.
203 */
204 RefCount *available_entries;
205 AVMutexpthread_mutex_t mutex;
206};
207
208static void pool_free(AVRefStructPool *pool)
209{
210 ff_mutex_destroystrict_pthread_mutex_destroy(&pool->mutex);
211 if (pool->free_cb)
212 pool->free_cb(pool->opaque);
213 av_free(get_refcount(pool));
214}
215
216static void pool_free_entry(AVRefStructPool *pool, RefCount *ref)
217{
218 if (pool->free_entry_cb)
219 pool->free_entry_cb(pool->opaque, get_userdata(ref));
220 av_free(ref);
221}
222
223static void pool_return_entry(void *ref_)
224{
225 RefCount *ref = ref_;
226 AVRefStructPool *pool = ref->opaque.nc;
227
228 ff_mutex_lockstrict_pthread_mutex_lock(&pool->mutex);
229 if (!pool->uninited) {
230 ref->opaque.nc = pool->available_entries;
231 pool->available_entries = ref;
232 ref = NULL((void*)0);
233 }
234 ff_mutex_unlockstrict_pthread_mutex_unlock(&pool->mutex);
235
236 if (ref)
237 pool_free_entry(pool, ref);
238
239 if (atomic_fetch_sub_explicit__c11_atomic_fetch_sub(&pool->refcount, 1, memory_order_acq_rel) == 1)
240 pool_free(pool);
241}
242
243static void pool_reset_entry(AVRefStructOpaque opaque, void *entry)
244{
245 AVRefStructPool *pool = opaque.nc;
246
247 pool->reset_cb(pool->opaque, entry);
248}
249
250static int refstruct_pool_get_ext(void *datap, AVRefStructPool *pool)
251{
252 void *ret = NULL((void*)0);
253
254 memcpy(datap, &(void *){ NULL((void*)0) }, sizeof(void*));
255
256 ff_mutex_lockstrict_pthread_mutex_lock(&pool->mutex);
257 ff_assert(!pool->uninited)do { if (!(!pool->uninited)) { av_log(((void*)0), 0, "Assertion %s failed at %s:%d\n"
, "!pool->uninited", "/root/firefox-clang/media/ffvpx/libavutil/refstruct.c"
, 257); abort(); } } while (0)
;
2
Assuming field 'uninited' is 0
3
Taking false branch
4
Loop condition is false. Exiting loop
258 if (pool->available_entries) {
5
Assuming field 'available_entries' is null
6
Taking false branch
259 RefCount *ref = pool->available_entries;
260 ret = get_userdata(ref);
261 pool->available_entries = ref->opaque.nc;
262 ref->opaque.nc = pool;
263 atomic_init__c11_atomic_init(&ref->refcount, 1);
264 }
265 ff_mutex_unlockstrict_pthread_mutex_unlock(&pool->mutex);
7
Calling 'strict_pthread_mutex_unlock'
13
Returning from 'strict_pthread_mutex_unlock'
266
267 if (!ret
13.1
'ret' is null
13.1
'ret' is null
13.1
'ret' is null
) {
14
Taking true branch
268 RefCount *ref;
269 ret = av_refstruct_alloc_ext(pool->size, pool->entry_flags, pool,
17
Calling 'av_refstruct_alloc_ext'
40
Returning from 'av_refstruct_alloc_ext'
270 pool->reset_cb ? pool_reset_entry : NULL((void*)0));
15
Assuming field 'reset_cb' is null
16
'?' condition is false
271 if (!ret
40.1
'ret' is non-null
40.1
'ret' is non-null
40.1
'ret' is non-null
)
41
Taking false branch
272 return AVERROR(ENOMEM)(-(12));
273 ref = get_refcount(ret);
274 ref->free = pool_return_entry;
275 if (pool->init_cb) {
42
Assuming field 'init_cb' is non-null
43
Taking true branch
276 int err = pool->init_cb(pool->opaque, ret);
277 if (err < 0) {
44
Assuming 'err' is < 0
45
Taking true branch
278 if (pool->pool_flags & AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR(1 << 16))
46
Assuming the condition is true
47
Taking true branch
279 pool->reset_cb(pool->opaque, ret);
48
Called function pointer is null (null dereference)
280 if (pool->pool_flags & AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR(1 << 17))
281 pool->free_entry_cb(pool->opaque, ret);
282 av_free(ref);
283 return err;
284 }
285 }
286 }
287 atomic_fetch_add_explicit__c11_atomic_fetch_add(&pool->refcount, 1, memory_order_relaxed);
288
289 if (pool->pool_flags & AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME(1 << 18))
290 memset(ret, 0, pool->size);
291
292 memcpy(datap, &ret, sizeof(ret));
293
294 return 0;
295}
296
297void *av_refstruct_pool_get(AVRefStructPool *pool)
298{
299 void *ret;
300 refstruct_pool_get_ext(&ret, pool);
1
Calling 'refstruct_pool_get_ext'
301 return ret;
302}
303
304/**
305 * Hint: The content of pool_unref() and refstruct_pool_uninit()
306 * could currently be merged; they are only separate functions
307 * in case we would ever introduce weak references.
308 */
309static void pool_unref(void *ref)
310{
311 AVRefStructPool *pool = get_userdata(ref);
312 if (atomic_fetch_sub_explicit__c11_atomic_fetch_sub(&pool->refcount, 1, memory_order_acq_rel) == 1)
313 pool_free(pool);
314}
315
316static void refstruct_pool_uninit(AVRefStructOpaque unused, void *obj)
317{
318 AVRefStructPool *pool = obj;
319 RefCount *entry;
320
321 ff_mutex_lockstrict_pthread_mutex_lock(&pool->mutex);
322 ff_assert(!pool->uninited)do { if (!(!pool->uninited)) { av_log(((void*)0), 0, "Assertion %s failed at %s:%d\n"
, "!pool->uninited", "/root/firefox-clang/media/ffvpx/libavutil/refstruct.c"
, 322); abort(); } } while (0)
;
323 pool->uninited = 1;
324 entry = pool->available_entries;
325 pool->available_entries = NULL((void*)0);
326 ff_mutex_unlockstrict_pthread_mutex_unlock(&pool->mutex);
327
328 while (entry) {
329 void *next = entry->opaque.nc;
330 pool_free_entry(pool, entry);
331 entry = next;
332 }
333}
334
335AVRefStructPool *av_refstruct_pool_alloc(size_t size, unsigned flags)
336{
337 return av_refstruct_pool_alloc_ext(size, flags, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0));
338}
339
340AVRefStructPool *av_refstruct_pool_alloc_ext_c(size_t size, unsigned flags,
341 AVRefStructOpaque opaque,
342 int (*init_cb)(AVRefStructOpaque opaque, void *obj),
343 void (*reset_cb)(AVRefStructOpaque opaque, void *obj),
344 void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj),
345 void (*free_cb)(AVRefStructOpaque opaque))
346{
347 AVRefStructPool *pool = av_refstruct_alloc_ext(sizeof(*pool), 0, NULL((void*)0),
348 refstruct_pool_uninit);
349 int err;
350
351 if (!pool)
352 return NULL((void*)0);
353 get_refcount(pool)->free = pool_unref;
354
355 pool->size = size;
356 pool->opaque = opaque;
357 pool->init_cb = init_cb;
358 pool->reset_cb = reset_cb;
359 pool->free_entry_cb = free_entry_cb;
360 pool->free_cb = free_cb;
361#define COMMON_FLAGS(1 << 0) AV_REFSTRUCT_POOL_FLAG_NO_ZEROING(1 << 0)
362 pool->entry_flags = flags & COMMON_FLAGS(1 << 0);
363 // Filter out nonsense combinations to avoid checks later.
364 if (!pool->reset_cb)
365 flags &= ~AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR(1 << 16);
366 if (!pool->free_entry_cb)
367 flags &= ~AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR(1 << 17);
368 pool->pool_flags = flags;
369
370 if (flags & AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME(1 << 18)) {
371 // We will zero the buffer before every use, so zeroing
372 // upon allocating the buffer is unnecessary.
373 pool->entry_flags |= AV_REFSTRUCT_FLAG_NO_ZEROING(1 << 0);
374 }
375
376 atomic_init__c11_atomic_init(&pool->refcount, 1);
377
378 err = ff_mutex_initstrict_pthread_mutex_init(&pool->mutex, NULL((void*)0));
379 if (err) {
380 // Don't call av_refstruct_uninit() on pool, as it hasn't been properly
381 // set up and is just a POD right now.
382 av_free(get_refcount(pool));
383 return NULL((void*)0);
384 }
385 return pool;
386}

/root/firefox-clang/media/ffvpx/libavutil/thread.h

1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19// This header should only be used to simplify code where
20// threading is optional, not as a generic threading abstraction.
21
22#ifndef AVUTIL_THREAD_H
23#define AVUTIL_THREAD_H
24
25#include "config.h"
26
27#if HAVE_PRCTL
28#include <sys/prctl.h>
29#elif (HAVE_PTHREAD_SETNAME_NP || HAVE_PTHREAD_SET_NAME_NP) && HAVE_PTHREAD_NP_H
30#include <pthread_np.h>
31#endif
32
33#include "error.h"
34
35#if HAVE_PTHREADS1 || HAVE_W32THREADS0 || HAVE_OS2THREADS0
36
37#if HAVE_PTHREADS1
38#include <pthread.h>
39
40#if defined(ASSERT_LEVEL2) && ASSERT_LEVEL2 > 1
41
42#include <stdlib.h>
43
44#include "log.h"
45#include "macros.h"
46
47#define ASSERT_PTHREAD_ABORT(func, ret)do { char errbuf[64] = ""; av_log(((void*)0), 8, "func" " failed with error: %s\n"
, av_make_error_string(errbuf, 64, (-(ret)))); abort(); } while
(0)
do { \
48 char errbuf[AV_ERROR_MAX_STRING_SIZE64] = ""; \
49 av_log(NULL((void*)0), AV_LOG_FATAL8, AV_STRINGIFY(func)"func" \
50 " failed with error: %s\n", \
51 av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE64, \
52 AVERROR(ret)(-(ret)))); \
53 abort(); \
54} while (0)
55
56#define ASSERT_PTHREAD_NORET(func, ...)do { int ret = func(...); if (ret) do { char errbuf[64] = "";
av_log(((void*)0), 8, "func" " failed with error: %s\n", av_make_error_string
(errbuf, 64, (-(ret)))); abort(); } while (0); } while (0)
do { \
57 int ret = func(__VA_ARGS__); \
58 if (ret) \
59 ASSERT_PTHREAD_ABORT(func, ret)do { char errbuf[64] = ""; av_log(((void*)0), 8, "func" " failed with error: %s\n"
, av_make_error_string(errbuf, 64, (-(ret)))); abort(); } while
(0)
; \
60} while (0)
61
62#define ASSERT_PTHREAD(func, ...)do { do { int ret = func(...); if (ret) do { char errbuf[64] =
""; av_log(((void*)0), 8, "func" " failed with error: %s\n",
av_make_error_string(errbuf, 64, (-(ret)))); abort(); } while
(0); } while (0); return 0; } while (0)
do { \
63 ASSERT_PTHREAD_NORET(func, __VA_ARGS__)do { int ret = func(__VA_ARGS__); if (ret) do { char errbuf[64
] = ""; av_log(((void*)0), 8, "func" " failed with error: %s\n"
, av_make_error_string(errbuf, 64, (-(ret)))); abort(); } while
(0); } while (0)
; \
64 return 0; \
65} while (0)
66
67static inline int strict_pthread_join(pthread_t thread, void **value_ptr)
68{
69 ASSERT_PTHREAD(pthread_join, thread, value_ptr)do { do { int ret = strict_pthread_join(thread, value_ptr); if
(ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_join"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
70}
71
72static inline int strict_pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
73{
74 if (attr) {
75 ASSERT_PTHREAD_NORET(pthread_mutex_init, mutex, attr)do { int ret = strict_pthread_mutex_init(mutex, attr); if (ret
) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_mutex_init"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0)
;
76 } else {
77 pthread_mutexattr_t local_attr;
78 ASSERT_PTHREAD_NORET(pthread_mutexattr_init, &local_attr)do { int ret = pthread_mutexattr_init(&local_attr); if (ret
) do { char errbuf[64] = ""; av_log(((void*)0), 8, "pthread_mutexattr_init"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0)
;
79 ASSERT_PTHREAD_NORET(pthread_mutexattr_settype, &local_attr, PTHREAD_MUTEX_ERRORCHECK)do { int ret = pthread_mutexattr_settype(&local_attr, PTHREAD_MUTEX_ERRORCHECK
); if (ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "pthread_mutexattr_settype"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0)
;
80 ASSERT_PTHREAD_NORET(pthread_mutex_init, mutex, &local_attr)do { int ret = strict_pthread_mutex_init(mutex, &local_attr
); if (ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_mutex_init"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0)
;
81 ASSERT_PTHREAD_NORET(pthread_mutexattr_destroy, &local_attr)do { int ret = pthread_mutexattr_destroy(&local_attr); if
(ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "pthread_mutexattr_destroy"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0)
;
82 }
83 return 0;
84}
85
86static inline int strict_pthread_mutex_destroy(pthread_mutex_t *mutex)
87{
88 ASSERT_PTHREAD(pthread_mutex_destroy, mutex)do { do { int ret = strict_pthread_mutex_destroy(mutex); if (
ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_mutex_destroy"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
89}
90
91static inline int strict_pthread_mutex_lock(pthread_mutex_t *mutex)
92{
93 ASSERT_PTHREAD(pthread_mutex_lock, mutex)do { do { int ret = strict_pthread_mutex_lock(mutex); if (ret
) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_mutex_lock"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
94}
95
96static inline int strict_pthread_mutex_unlock(pthread_mutex_t *mutex)
97{
98 ASSERT_PTHREAD(pthread_mutex_unlock, mutex)do { do { int ret = strict_pthread_mutex_unlock(mutex); if (ret
) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_mutex_unlock"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
8
Value assigned to field 'init_cb', which participates in a condition later
9
Value assigned to field 'reset_cb'
10
Assuming 'ret' is 0
11
Taking false branch
12
Loop condition is false. Exiting loop
99}
100
101static inline int strict_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
102{
103 ASSERT_PTHREAD(pthread_cond_init, cond, attr)do { do { int ret = strict_pthread_cond_init(cond, attr); if (
ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_cond_init"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
104}
105
106static inline int strict_pthread_cond_destroy(pthread_cond_t *cond)
107{
108 ASSERT_PTHREAD(pthread_cond_destroy, cond)do { do { int ret = strict_pthread_cond_destroy(cond); if (ret
) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_cond_destroy"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
109}
110
111static inline int strict_pthread_cond_signal(pthread_cond_t *cond)
112{
113 ASSERT_PTHREAD(pthread_cond_signal, cond)do { do { int ret = strict_pthread_cond_signal(cond); if (ret
) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_cond_signal"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
114}
115
116static inline int strict_pthread_cond_broadcast(pthread_cond_t *cond)
117{
118 ASSERT_PTHREAD(pthread_cond_broadcast, cond)do { do { int ret = strict_pthread_cond_broadcast(cond); if (
ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_cond_broadcast"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
119}
120
121static inline int strict_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
122{
123 ASSERT_PTHREAD(pthread_cond_wait, cond, mutex)do { do { int ret = strict_pthread_cond_wait(cond, mutex); if
(ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_cond_wait"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
124}
125
126static inline int strict_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
127 const struct timespec *abstime)
128{
129 int ret = pthread_cond_timedwaitstrict_pthread_cond_timedwait(cond, mutex, abstime);
130 if (ret && ret != ETIMEDOUT110)
131 ASSERT_PTHREAD_ABORT(pthread_cond_timedwait, ret)do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_cond_timedwait"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0)
;
132 return ret;
133}
134
135static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
136{
137 ASSERT_PTHREAD(pthread_once, once_control, init_routine)do { do { int ret = strict_pthread_once(once_control, init_routine
); if (ret) do { char errbuf[64] = ""; av_log(((void*)0), 8, "strict_pthread_once"
" failed with error: %s\n", av_make_error_string(errbuf, 64,
(-(ret)))); abort(); } while (0); } while (0); return 0; } while
(0)
;
138}
139
140#define pthread_joinstrict_pthread_join strict_pthread_join
141#define pthread_mutex_initstrict_pthread_mutex_init strict_pthread_mutex_init
142#define pthread_mutex_destroystrict_pthread_mutex_destroy strict_pthread_mutex_destroy
143#define pthread_mutex_lockstrict_pthread_mutex_lock strict_pthread_mutex_lock
144#define pthread_mutex_unlockstrict_pthread_mutex_unlock strict_pthread_mutex_unlock
145#define pthread_cond_initstrict_pthread_cond_init strict_pthread_cond_init
146#define pthread_cond_destroystrict_pthread_cond_destroy strict_pthread_cond_destroy
147#define pthread_cond_signalstrict_pthread_cond_signal strict_pthread_cond_signal
148#define pthread_cond_broadcaststrict_pthread_cond_broadcast strict_pthread_cond_broadcast
149#define pthread_cond_waitstrict_pthread_cond_wait strict_pthread_cond_wait
150#define pthread_cond_timedwaitstrict_pthread_cond_timedwait strict_pthread_cond_timedwait
151#define pthread_oncestrict_pthread_once strict_pthread_once
152#endif
153
154#elif HAVE_OS2THREADS0
155#include "compat/os2threads.h"
156#else
157#include "compat/w32pthreads.h"
158#endif
159
160#define AVMutexpthread_mutex_t pthread_mutex_t
161#define AV_MUTEX_INITIALIZER{ { 0, 0, 0, 0, PTHREAD_MUTEX_TIMED_NP, 0, 0, { ((void*)0), (
(void*)0) } } }
PTHREAD_MUTEX_INITIALIZER{ { 0, 0, 0, 0, PTHREAD_MUTEX_TIMED_NP, 0, 0, { ((void*)0), (
(void*)0) } } }
162
163#define ff_mutex_initstrict_pthread_mutex_init pthread_mutex_initstrict_pthread_mutex_init
164#define ff_mutex_lockstrict_pthread_mutex_lock pthread_mutex_lockstrict_pthread_mutex_lock
165#define ff_mutex_unlockstrict_pthread_mutex_unlock pthread_mutex_unlockstrict_pthread_mutex_unlock
166#define ff_mutex_destroystrict_pthread_mutex_destroy pthread_mutex_destroystrict_pthread_mutex_destroy
167
168#define AVCondpthread_cond_t pthread_cond_t
169
170#define ff_cond_initstrict_pthread_cond_init pthread_cond_initstrict_pthread_cond_init
171#define ff_cond_destroystrict_pthread_cond_destroy pthread_cond_destroystrict_pthread_cond_destroy
172#define ff_cond_signalstrict_pthread_cond_signal pthread_cond_signalstrict_pthread_cond_signal
173#define ff_cond_broadcaststrict_pthread_cond_broadcast pthread_cond_broadcaststrict_pthread_cond_broadcast
174#define ff_cond_waitstrict_pthread_cond_wait pthread_cond_waitstrict_pthread_cond_wait
175#define ff_cond_timedwaitstrict_pthread_cond_timedwait pthread_cond_timedwaitstrict_pthread_cond_timedwait
176
177#define AVOncepthread_once_t pthread_once_t
178#define AV_ONCE_INIT0 PTHREAD_ONCE_INIT0
179
180#define ff_thread_once(control, routine)strict_pthread_once(control, routine) pthread_oncestrict_pthread_once(control, routine)
181
182#else
183
184#define AVMutexpthread_mutex_t char
185#define AV_MUTEX_INITIALIZER{ { 0, 0, 0, 0, PTHREAD_MUTEX_TIMED_NP, 0, 0, { ((void*)0), (
(void*)0) } } }
0
186
187static inline int ff_mutex_initstrict_pthread_mutex_init(AVMutexpthread_mutex_t *mutex, const void *attr){ return 0; }
188static inline int ff_mutex_lockstrict_pthread_mutex_lock(AVMutexpthread_mutex_t *mutex){ return 0; }
189static inline int ff_mutex_unlockstrict_pthread_mutex_unlock(AVMutexpthread_mutex_t *mutex){ return 0; }
190static inline int ff_mutex_destroystrict_pthread_mutex_destroy(AVMutexpthread_mutex_t *mutex){ return 0; }
191
192#define AVCondpthread_cond_t char
193
194static inline int ff_cond_initstrict_pthread_cond_init(AVCondpthread_cond_t *cond, const void *attr){ return 0; }
195static inline int ff_cond_destroystrict_pthread_cond_destroy(AVCondpthread_cond_t *cond){ return 0; }
196static inline int ff_cond_signalstrict_pthread_cond_signal(AVCondpthread_cond_t *cond){ return 0; }
197static inline int ff_cond_broadcaststrict_pthread_cond_broadcast(AVCondpthread_cond_t *cond){ return 0; }
198static inline int ff_cond_waitstrict_pthread_cond_wait(AVCondpthread_cond_t *cond, AVMutexpthread_mutex_t *mutex){ return 0; }
199static inline int ff_cond_timedwaitstrict_pthread_cond_timedwait(AVCondpthread_cond_t *cond, AVMutexpthread_mutex_t *mutex,
200 const void *abstime){ return 0; }
201
202#define AVOncepthread_once_t char
203#define AV_ONCE_INIT0 0
204
205static inline int ff_thread_once(char *control, void (*routine)(void))strict_pthread_once(char *control, void (*routine)(void))
206{
207 if (!*control) {
208 routine();
209 *control = 1;
210 }
211 return 0;
212}
213
214#endif
215
216static inline int ff_thread_setname(const char *name)
217{
218 int ret = 0;
219
220#if HAVE_PRCTL
221 ret = AVERROR(prctl(PR_SET_NAME, name))(-(prctl(PR_SET_NAME, name)));
222#elif HAVE_PTHREAD_SETNAME_NP
223#if defined(__APPLE__)
224 ret = AVERROR(pthread_setname_np(name))(-(pthread_setname_np(name)));
225#elif defined(__NetBSD__)
226 ret = AVERROR(pthread_setname_np(pthread_self(), "%s", name))(-(pthread_setname_np(pthread_self(), "%s", name)));
227#else
228 ret = AVERROR(pthread_setname_np(pthread_self(), name))(-(pthread_setname_np(pthread_self(), name)));
229#endif
230#elif HAVE_PTHREAD_SET_NAME_NP
231 pthread_set_name_np(pthread_self(), name);
232#elif HAVE_W32THREADS0
233 ret = win32_thread_setname(name);
234#else
235 ret = AVERROR(ENOSYS)(-(38));
236#endif
237
238 return ret;
239}
240
241#endif /* AVUTIL_THREAD_H */

/root/firefox-clang/media/ffvpx/libavutil/refstruct.h

1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#ifndef AVUTIL_REFSTRUCT_H
20#define AVUTIL_REFSTRUCT_H
21
22#include <stddef.h>
23
24/**
25 * RefStruct is an API for creating reference-counted objects
26 * with minimal overhead. The API is designed for objects,
27 * not buffers like the AVBuffer API. The main differences
28 * to the AVBuffer API are as follows:
29 *
30 * - It uses void* instead of uint8_t* as its base type due to
31 * its focus on objects.
32 * - There are no equivalents of AVBuffer and AVBufferRef.
33 * E.g. there is no way to get the usable size of the object:
34 * The user is supposed to know what is at the other end of
35 * the pointer. It also avoids one level of indirection.
36 * - Custom allocators are not supported. This allows to simplify
37 * the implementation and reduce the amount of allocations.
38 * - It also has the advantage that the user's free callback need
39 * only free the resources owned by the object, but not the
40 * object itself.
41 * - Because referencing (and replacing) an object managed by the
42 * RefStruct API does not involve allocations, they can not fail
43 * and therefore need not be checked.
44 *
45 * @note Referencing and unreferencing the buffers is thread-safe and thus
46 * may be done from multiple threads simultaneously without any need for
47 * additional locking.
48 */
49
50/**
51 * This union is used for all opaque parameters in this API to spare the user
52 * to cast const away in case the opaque to use is const-qualified.
53 *
54 * The functions provided by this API with an AVRefStructOpaque come in pairs
55 * named foo_c and foo. The foo function accepts void* as opaque and is just
56 * a wrapper around the foo_c function; "_c" means "(potentially) const".
57 */
58typedef union {
59 void *nc;
60 const void *c;
61} AVRefStructOpaque;
62
63/**
64 * If this flag is set in av_refstruct_alloc_ext_c(), the object will not
65 * be initially zeroed.
66 */
67#define AV_REFSTRUCT_FLAG_NO_ZEROING(1 << 0) (1 << 0)
68
69/**
70 * Allocate a refcounted object of usable size `size` managed via
71 * the RefStruct API.
72 *
73 * By default (in the absence of flags to the contrary),
74 * the returned object is initially zeroed.
75 *
76 * @param size Desired usable size of the returned object.
77 * @param flags A bitwise combination of AV_REFSTRUCT_FLAG_* flags.
78 * @param opaque A pointer that will be passed to the free_cb callback.
79 * @param free_cb A callback for freeing this object's content
80 * when its reference count reaches zero;
81 * it must not free the object itself.
82 * @return A pointer to an object of the desired size or NULL on failure.
83 */
84void *av_refstruct_alloc_ext_c(size_t size, unsigned flags, AVRefStructOpaque opaque,
85 void (*free_cb)(AVRefStructOpaque opaque, void *obj));
86
87/**
88 * A wrapper around av_refstruct_alloc_ext_c() for the common case
89 * of a non-const qualified opaque.
90 *
91 * @see av_refstruct_alloc_ext_c()
92 */
93static inline
94void *av_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque,
95 void (*free_cb)(AVRefStructOpaque opaque, void *obj))
96{
97 return av_refstruct_alloc_ext_c(size, flags, (AVRefStructOpaque){.nc = opaque},
18
Calling 'av_refstruct_alloc_ext_c'
38
Returning from 'av_refstruct_alloc_ext_c'
39
Returning pointer, which participates in a condition later
98 free_cb);
99}
100
101/**
102 * Equivalent to av_refstruct_alloc_ext(size, 0, NULL, NULL)
103 */
104static inline
105void *av_refstruct_allocz(size_t size)
106{
107 return av_refstruct_alloc_ext(size, 0, NULL((void*)0), NULL((void*)0));
108}
109
110/**
111 * Decrement the reference count of the underlying object and automatically
112 * free the object if there are no more references to it.
113 *
114 * `*objp == NULL` is legal and a no-op.
115 *
116 * @param objp Pointer to a pointer that is either NULL or points to an object
117 * managed via this API. `*objp` is set to NULL on return.
118 */
119void av_refstruct_unref(void *objp);
120
121/**
122 * Create a new reference to an object managed via this API,
123 * i.e. increment the reference count of the underlying object
124 * and return obj.
125 * @return a pointer equal to obj.
126 */
127void *av_refstruct_ref(void *obj);
128
129/**
130 * Analog of av_refstruct_ref(), but for constant objects.
131 * @see av_refstruct_ref()
132 */
133const void *av_refstruct_ref_c(const void *obj);
134
135/**
136 * Ensure `*dstp` refers to the same object as src.
137 *
138 * If `*dstp` is already equal to src, do nothing. Otherwise unreference `*dstp`
139 * and replace it with a new reference to src in case `src != NULL` (this
140 * involves incrementing the reference count of src's underlying object) or
141 * with NULL otherwise.
142 *
143 * @param dstp Pointer to a pointer that is either NULL or points to an object
144 * managed via this API.
145 * @param src A pointer to an object managed via this API or NULL.
146 */
147void av_refstruct_replace(void *dstp, const void *src);
148
149/**
150 * Check whether the reference count of an object managed
151 * via this API is 1.
152 *
153 * @param obj A pointer to an object managed via this API.
154 * @return 1 if the reference count of obj is 1; 0 otherwise.
155 */
156int av_refstruct_exclusive(const void *obj);
157
158/**
159 * AVRefStructPool is an API for a thread-safe pool of objects managed
160 * via the RefStruct API.
161 *
162 * Frequently allocating and freeing large or complicated objects may be slow
163 * and wasteful. This API is meant to solve this in cases when the caller
164 * needs a set of interchangeable objects.
165 *
166 * At the beginning, the user must call allocate the pool via
167 * av_refstruct_pool_alloc() or its analogue av_refstruct_pool_alloc_ext().
168 * Then whenever an object is needed, call av_refstruct_pool_get() to
169 * get a new or reused object from the pool. This new object works in all
170 * aspects the same way as the ones created by av_refstruct_alloc_ext().
171 * However, when the last reference to this object is unreferenced, it is
172 * (optionally) reset and returned to the pool instead of being freed and
173 * will be reused for subsequent av_refstruct_pool_get() calls.
174 *
175 * When the caller is done with the pool and no longer needs to create any new
176 * objects, av_refstruct_pool_uninit() must be called to mark the pool as
177 * freeable. Then entries returned to the pool will then be freed.
178 * Once all the entries are freed, the pool will automatically be freed.
179 *
180 * Allocating and releasing objects with this API is thread-safe as long as
181 * the user-supplied callbacks (if provided) are thread-safe.
182 */
183
184/**
185 * The buffer pool. This structure is opaque and not meant to be accessed
186 * directly. It is allocated with the allocators below and freed with
187 * av_refstruct_pool_uninit().
188 */
189typedef struct AVRefStructPool AVRefStructPool;
190
191/**
192 * If this flag is not set, every object in the pool will be zeroed before
193 * the init callback is called or before it is turned over to the user
194 * for the first time if no init callback has been provided.
195 */
196#define AV_REFSTRUCT_POOL_FLAG_NO_ZEROING(1 << 0) AV_REFSTRUCT_FLAG_NO_ZEROING(1 << 0)
197/**
198 * If this flag is set and both init_cb and reset_cb callbacks are provided,
199 * then reset_cb will be called if init_cb fails.
200 * The object passed to reset_cb will be in the state left by init_cb.
201 */
202#define AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR(1 << 16) (1 << 16)
203/**
204 * If this flag is set and both init_cb and free_entry_cb callbacks are
205 * provided, then free_cb will be called if init_cb fails.
206 *
207 * It will be called after reset_cb in case reset_cb and the
208 * AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR flag are also set.
209 *
210 * The object passed to free_cb will be in the state left by
211 * the callbacks applied earlier (init_cb potentially followed by reset_cb).
212 */
213#define AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR(1 << 17) (1 << 17)
214/**
215 * If this flag is set, the entries will be zeroed before
216 * being returned to the user (after the init or reset callbacks
217 * have been called (if provided)). Furthermore, to avoid zeroing twice
218 * it also makes the pool behave as if the AV_REFSTRUCT_POOL_FLAG_NO_ZEROING
219 * flag had been provided.
220 */
221#define AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME(1 << 18) (1 << 18)
222
223/**
224 * Equivalent to av_refstruct_pool_alloc(size, flags, NULL, NULL, NULL, NULL, NULL)
225 */
226AVRefStructPool *av_refstruct_pool_alloc(size_t size, unsigned flags);
227
228/**
229 * Allocate an AVRefStructPool, potentially using complex callbacks.
230 *
231 * @param size size of the entries of the pool
232 * @param flags a bitwise combination of AV_REFSTRUCT_POOL_FLAG_* flags
233 * @param opaque A pointer that will be passed to the callbacks below.
234 * @param init A callback that will be called directly after a new entry
235 * has been allocated. obj has already been zeroed unless
236 * the AV_REFSTRUCT_POOL_FLAG_NO_ZEROING flag is in use.
237 * @param reset A callback that will be called after an entry has been
238 * returned to the pool and before it is reused.
239 * @param free_entry A callback that will be called when an entry is freed
240 * after the pool has been marked as to be uninitialized.
241 * @param free A callback that will be called when the pool itself is
242 * freed (after the last entry has been returned and freed).
243 */
244AVRefStructPool *av_refstruct_pool_alloc_ext_c(size_t size, unsigned flags,
245 AVRefStructOpaque opaque,
246 int (*init_cb)(AVRefStructOpaque opaque, void *obj),
247 void (*reset_cb)(AVRefStructOpaque opaque, void *obj),
248 void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj),
249 void (*free_cb)(AVRefStructOpaque opaque));
250
251/**
252 * A wrapper around av_refstruct_pool_alloc_ext_c() for the common case
253 * of a non-const qualified opaque.
254 *
255 * @see av_refstruct_pool_alloc_ext_c()
256 */
257static inline
258AVRefStructPool *av_refstruct_pool_alloc_ext(size_t size, unsigned flags,
259 void *opaque,
260 int (*init_cb)(AVRefStructOpaque opaque, void *obj),
261 void (*reset_cb)(AVRefStructOpaque opaque, void *obj),
262 void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj),
263 void (*free_cb)(AVRefStructOpaque opaque))
264{
265 return av_refstruct_pool_alloc_ext_c(size, flags, (AVRefStructOpaque){.nc = opaque},
266 init_cb, reset_cb, free_entry_cb, free_cb);
267}
268
269/**
270 * Get an object from the pool, reusing an old one from the pool when
271 * available.
272 *
273 * Every call to this function must happen before av_refstruct_pool_uninit().
274 * Otherwise undefined behaviour may occur.
275 *
276 * @param pool the pool from which to get the object
277 * @return a reference to the object on success, NULL on error.
278 */
279void *av_refstruct_pool_get(AVRefStructPool *pool);
280
281/**
282 * Mark the pool as being available for freeing. It will actually be freed
283 * only once all the allocated buffers associated with the pool are released.
284 * Thus it is safe to call this function while some of the allocated buffers
285 * are still in use.
286 *
287 * It is illegal to try to get a new entry after this function has been called.
288 *
289 * @param poolp pointer to a pointer to either NULL or a pool to be freed.
290 * `*poolp` will be set to NULL.
291 */
292static inline void av_refstruct_pool_uninit(AVRefStructPool **poolp)
293{
294 av_refstruct_unref(poolp);
295}
296
297#endif /* AVUTIL_REFSTRUCT_H */