diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c index 14b7cca4fe..e7bad19f8b 100644 --- a/libavcodec/pthread.c +++ b/libavcodec/pthread.c @@ -29,6 +29,8 @@ * @see doc/multithreading.txt */ +#include "libavutil/thread.h" + #include "avcodec.h" #include "internal.h" #include "pthread_internal.h" @@ -86,3 +88,39 @@ void ff_thread_free(AVCodecContext *avctx) else ff_slice_thread_free(avctx); } + +av_cold void ff_pthread_free(void *obj, const unsigned offsets[]) +{ + unsigned cnt = *(unsigned*)((char*)obj + offsets[0]); + const unsigned *cur_offset = offsets; + + *(unsigned*)((char*)obj + offsets[0]) = 0; + + for (; *(++cur_offset) != THREAD_SENTINEL && cnt; cnt--) + pthread_mutex_destroy((pthread_mutex_t*)((char*)obj + *cur_offset)); + for (; *(++cur_offset) != THREAD_SENTINEL && cnt; cnt--) + pthread_cond_destroy ((pthread_cond_t *)((char*)obj + *cur_offset)); +} + +av_cold int ff_pthread_init(void *obj, const unsigned offsets[]) +{ + const unsigned *cur_offset = offsets; + unsigned cnt = 0; + int err; + +#define PTHREAD_INIT_LOOP(type) \ + for (; *(++cur_offset) != THREAD_SENTINEL; cnt++) { \ + pthread_ ## type ## _t *dst = (void*)((char*)obj + *cur_offset); \ + err = pthread_ ## type ## _init(dst, NULL); \ + if (err) { \ + err = AVERROR(err); \ + goto fail; \ + } \ + } + PTHREAD_INIT_LOOP(mutex) + PTHREAD_INIT_LOOP(cond) + +fail: + *(unsigned*)((char*)obj + offsets[0]) = cnt; + return err; +} diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 8c0966f026..9c5d66c0d4 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -680,59 +680,18 @@ static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count async_lock(fctx); } -#define SENTINEL 0 // This forbids putting a mutex/condition variable at the front. -#define OFFSET_ARRAY(...) __VA_ARGS__, SENTINEL -#define DEFINE_OFFSET_ARRAY(type, name, mutexes, conds) \ -static const unsigned name ## _offsets[] = { offsetof(type, pthread_init_cnt),\ - OFFSET_ARRAY mutexes, \ - OFFSET_ARRAY conds } - #define OFF(member) offsetof(FrameThreadContext, member) -DEFINE_OFFSET_ARRAY(FrameThreadContext, thread_ctx, +DEFINE_OFFSET_ARRAY(FrameThreadContext, thread_ctx, pthread_init_cnt, (OFF(buffer_mutex), OFF(hwaccel_mutex), OFF(async_mutex)), (OFF(async_cond))); #undef OFF #define OFF(member) offsetof(PerThreadContext, member) -DEFINE_OFFSET_ARRAY(PerThreadContext, per_thread, +DEFINE_OFFSET_ARRAY(PerThreadContext, per_thread, pthread_init_cnt, (OFF(progress_mutex), OFF(mutex)), (OFF(input_cond), OFF(progress_cond), OFF(output_cond))); #undef OFF -static av_cold void free_pthread(void *obj, const unsigned offsets[]) -{ - unsigned cnt = *(unsigned*)((char*)obj + offsets[0]); - const unsigned *cur_offset = offsets; - - for (; *(++cur_offset) != SENTINEL && cnt; cnt--) - pthread_mutex_destroy((pthread_mutex_t*)((char*)obj + *cur_offset)); - for (; *(++cur_offset) != SENTINEL && cnt; cnt--) - pthread_cond_destroy ((pthread_cond_t *)((char*)obj + *cur_offset)); -} - -static av_cold int init_pthread(void *obj, const unsigned offsets[]) -{ - const unsigned *cur_offset = offsets; - unsigned cnt = 0; - int err; - -#define PTHREAD_INIT_LOOP(type) \ - for (; *(++cur_offset) != SENTINEL; cnt++) { \ - pthread_ ## type ## _t *dst = (void*)((char*)obj + *cur_offset); \ - err = pthread_ ## type ## _init(dst, NULL); \ - if (err) { \ - err = AVERROR(err); \ - goto fail; \ - } \ - } - PTHREAD_INIT_LOOP(mutex) - PTHREAD_INIT_LOOP(cond) - -fail: - *(unsigned*)((char*)obj + offsets[0]) = cnt; - return err; -} - void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) { FrameThreadContext *fctx = avctx->internal->thread_ctx; @@ -792,14 +751,14 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) av_frame_free(&p->frame); - free_pthread(p, per_thread_offsets); + ff_pthread_free(p, per_thread_offsets); av_packet_free(&p->avpkt); av_freep(&p->avctx); } av_freep(&fctx->threads); - free_pthread(fctx, thread_ctx_offsets); + ff_pthread_free(fctx, thread_ctx_offsets); av_freep(&avctx->internal->thread_ctx); } @@ -845,7 +804,7 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, } } - err = init_pthread(p, per_thread_offsets); + err = ff_pthread_init(p, per_thread_offsets); if (err < 0) return err; @@ -906,9 +865,9 @@ int ff_frame_thread_init(AVCodecContext *avctx) if (!fctx) return AVERROR(ENOMEM); - err = init_pthread(fctx, thread_ctx_offsets); + err = ff_pthread_init(fctx, thread_ctx_offsets); if (err < 0) { - free_pthread(fctx, thread_ctx_offsets); + ff_pthread_free(fctx, thread_ctx_offsets); av_freep(&avctx->internal->thread_ctx); return err; } diff --git a/libavcodec/pthread_internal.h b/libavcodec/pthread_internal.h index d2115cbbaf..d0b6a7a673 100644 --- a/libavcodec/pthread_internal.h +++ b/libavcodec/pthread_internal.h @@ -31,4 +31,36 @@ void ff_slice_thread_free(AVCodecContext *avctx); int ff_frame_thread_init(AVCodecContext *avctx); void ff_frame_thread_free(AVCodecContext *avctx, int thread_count); +#define THREAD_SENTINEL 0 // This forbids putting a mutex/condition variable at the front. +/** + * Initialize/destroy a list of mutexes/conditions contained in a structure. + * The positions of these mutexes/conditions in the structure are given by + * their offsets. Because it is undefined behaviour to destroy + * an uninitialized mutex/condition, ff_pthread_init() stores the number + * of successfully initialized mutexes and conditions in the object itself + * and ff_pthread_free() uses this number to destroy exactly the mutexes and + * condition variables that have been successfully initialized. + * + * @param obj The object containing the mutexes/conditions. + * @param[in] offsets An array of offsets. Its first member gives the offset + * of the variable that contains the count of successfully + * initialized mutexes/condition variables; said variable + * must be an unsigned int. Two arrays of offsets, each + * delimited by a THREAD_SENTINEL follow. The first + * contains the offsets of all the mutexes, the second + * contains the offsets of all the condition variables. + */ +int ff_pthread_init(void *obj, const unsigned offsets[]); +void ff_pthread_free(void *obj, const unsigned offsets[]); + +/** + * Macros to help creating the above lists. mutexes and conds need + * to be parentheses-enclosed lists of offsets in the containing structure. + */ +#define OFFSET_ARRAY(...) __VA_ARGS__, THREAD_SENTINEL +#define DEFINE_OFFSET_ARRAY(type, name, cnt_variable, mutexes, conds) \ +static const unsigned name ## _offsets[] = { offsetof(type, cnt_variable), \ + OFFSET_ARRAY mutexes, \ + OFFSET_ARRAY conds } + #endif // AVCODEC_PTHREAD_INTERNAL_H