| File: | root/firefox-clang/media/ffvpx/libavutil/refstruct.c |
| Warning: | line 279, column 21 Called function pointer is null (null dereference) |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | |||||||
| 54 | typedef 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 | |||||||
| 70 | static 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 | |||||||
| 77 | static 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 | |||||||
| 84 | static 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)); | ||||||
| 87 | } | ||||||
| 88 | |||||||
| 89 | static 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); | ||||||
| 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 | |||||||
| 102 | void *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))) | ||||||
| 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))); | ||||||
| 110 | if (!buf) | ||||||
| 111 | return NULL((void*)0); | ||||||
| 112 | refcount_init(buf, opaque, free_cb); | ||||||
| 113 | obj = get_userdata(buf); | ||||||
| 114 | if (!(flags & AV_REFSTRUCT_FLAG_NO_ZEROING(1 << 0))) | ||||||
| 115 | memset(obj, 0, size); | ||||||
| 116 | |||||||
| 117 | return obj; | ||||||
| 118 | } | ||||||
| 119 | |||||||
| 120 | void 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 | |||||||
| 140 | void *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 | |||||||
| 149 | const 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 | |||||||
| 160 | void 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 | |||||||
| 174 | int 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 | |||||||
| 183 | struct 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 | |||||||
| 208 | static 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 | |||||||
| 216 | static 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 | |||||||
| 223 | static 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 | |||||||
| 243 | static void pool_reset_entry(AVRefStructOpaque opaque, void *entry) | ||||||
| 244 | { | ||||||
| 245 | AVRefStructPool *pool = opaque.nc; | ||||||
| 246 | |||||||
| 247 | pool->reset_cb(pool->opaque, entry); | ||||||
| 248 | } | ||||||
| 249 | |||||||
| 250 | static 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); | ||||||
| 258 | if (pool->available_entries) { | ||||||
| 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); | ||||||
| 266 | |||||||
| 267 | if (!ret
| ||||||
| 268 | RefCount *ref; | ||||||
| 269 | ret = av_refstruct_alloc_ext(pool->size, pool->entry_flags, pool, | ||||||
| 270 | pool->reset_cb ? pool_reset_entry : NULL((void*)0)); | ||||||
| 271 | if (!ret
| ||||||
| 272 | return AVERROR(ENOMEM)(-(12)); | ||||||
| 273 | ref = get_refcount(ret); | ||||||
| 274 | ref->free = pool_return_entry; | ||||||
| 275 | if (pool->init_cb) { | ||||||
| 276 | int err = pool->init_cb(pool->opaque, ret); | ||||||
| 277 | if (err < 0) { | ||||||
| 278 | if (pool->pool_flags & AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR(1 << 16)) | ||||||
| 279 | pool->reset_cb(pool->opaque, ret); | ||||||
| |||||||
| 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 | |||||||
| 297 | void *av_refstruct_pool_get(AVRefStructPool *pool) | ||||||
| 298 | { | ||||||
| 299 | void *ret; | ||||||
| 300 | refstruct_pool_get_ext(&ret, pool); | ||||||
| |||||||
| 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 | */ | ||||||
| 309 | static 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 | |||||||
| 316 | static 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 | |||||||
| 335 | AVRefStructPool *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 | |||||||
| 340 | AVRefStructPool *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 | } |
| 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 | |
| 67 | static 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 | |
| 72 | static 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 | |
| 86 | static 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 | |
| 91 | static 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 | |
| 96 | static 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); |
| 99 | } |
| 100 | |
| 101 | static 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 | |
| 106 | static 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 | |
| 111 | static 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 | |
| 116 | static 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 | |
| 121 | static 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 | |
| 126 | static 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 | |
| 135 | static 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 | |
| 187 | static inline int ff_mutex_initstrict_pthread_mutex_init(AVMutexpthread_mutex_t *mutex, const void *attr){ return 0; } |
| 188 | static inline int ff_mutex_lockstrict_pthread_mutex_lock(AVMutexpthread_mutex_t *mutex){ return 0; } |
| 189 | static inline int ff_mutex_unlockstrict_pthread_mutex_unlock(AVMutexpthread_mutex_t *mutex){ return 0; } |
| 190 | static inline int ff_mutex_destroystrict_pthread_mutex_destroy(AVMutexpthread_mutex_t *mutex){ return 0; } |
| 191 | |
| 192 | #define AVCondpthread_cond_t char |
| 193 | |
| 194 | static inline int ff_cond_initstrict_pthread_cond_init(AVCondpthread_cond_t *cond, const void *attr){ return 0; } |
| 195 | static inline int ff_cond_destroystrict_pthread_cond_destroy(AVCondpthread_cond_t *cond){ return 0; } |
| 196 | static inline int ff_cond_signalstrict_pthread_cond_signal(AVCondpthread_cond_t *cond){ return 0; } |
| 197 | static inline int ff_cond_broadcaststrict_pthread_cond_broadcast(AVCondpthread_cond_t *cond){ return 0; } |
| 198 | static inline int ff_cond_waitstrict_pthread_cond_wait(AVCondpthread_cond_t *cond, AVMutexpthread_mutex_t *mutex){ return 0; } |
| 199 | static 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 | |
| 205 | static 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 | |
| 216 | static 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 */ |
| 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 | */ |
| 58 | typedef 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 | */ |
| 84 | void *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 | */ |
| 93 | static inline |
| 94 | void *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}, |
| 98 | free_cb); |
| 99 | } |
| 100 | |
| 101 | /** |
| 102 | * Equivalent to av_refstruct_alloc_ext(size, 0, NULL, NULL) |
| 103 | */ |
| 104 | static inline |
| 105 | void *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 | */ |
| 119 | void 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 | */ |
| 127 | void *av_refstruct_ref(void *obj); |
| 128 | |
| 129 | /** |
| 130 | * Analog of av_refstruct_ref(), but for constant objects. |
| 131 | * @see av_refstruct_ref() |
| 132 | */ |
| 133 | const 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 | */ |
| 147 | void 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 | */ |
| 156 | int 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 | */ |
| 189 | typedef 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 | */ |
| 226 | AVRefStructPool *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 | */ |
| 244 | AVRefStructPool *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 | */ |
| 257 | static inline |
| 258 | AVRefStructPool *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 | */ |
| 279 | void *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 | */ |
| 292 | static inline void av_refstruct_pool_uninit(AVRefStructPool **poolp) |
| 293 | { |
| 294 | av_refstruct_unref(poolp); |
| 295 | } |
| 296 | |
| 297 | #endif /* AVUTIL_REFSTRUCT_H */ |