[FFmpeg-devel] [PATCH] Move the |die| member of FrameThreadContext to PerThreadContext.
Wan-Teh Chang
wtc at google.com
Fri Feb 26 02:26:42 CET 2016
Hi Ronald,
On Thu, Feb 25, 2016 at 12:00 PM, Ronald S. Bultje <rsbultje at gmail.com> wrote:
>
> But does it fix an actual bug? (Is there a sample this fixes?)
I assume you agree that reading and writing the non-atomic int |die|
flag without mutex protection is a data race. Code inspection verifies
libavcodec/pthread_frame.c reads and writes |die| without mutex
protection.
To fix the data race, we can either protect |die| with a mutex, or
declare |die| as an atomic int.
> If anything, you can use atomic ints instead of regular ints if we don't
> already [1].
>
[...]
> [1] https://ffmpeg.org/doxygen/trunk/atomic_8h_source.html
Thanks for the link. avpriv_atomic_int_get and avpriv_atomic_int_set
perform the load and store with sequential consistency, which requires
a full memory barrier and is slower than simply relying on the
existing per-thread mutex. The drawback of my patch is that it uses
more memory. I think that's the right trade-off, but I would be happy
to use an atomic int. Please let me know what you prefer.
Thanks,
Wan-Teh Chang
PS: Here is the relevant part of the ThreadSanitizer report. I'm using
an old version of ffmpeg (the code is in libavcodec/pthread.c in that
version):
WARNING: ThreadSanitizer: data race (pid=959745)
Write of size 4 at 0x7d1800055a24 by main thread (mutexes: write M18754):
#0 frame_thread_free ffmpeg/libavcodec/pthread.c:761:15
(c9c6e60608e58c16d6d8dc75627a71ed+0x000000985b5a)
#1 ff_thread_free ffmpeg/libavcodec/pthread.c:1103:9
(c9c6e60608e58c16d6d8dc75627a71ed+0x0000009859ea)
#2 avcodec_close ffmpeg/libavcodec/utils.c:1825:13
(c9c6e60608e58c16d6d8dc75627a71ed+0x000000a8f7a6)
...
Previous read of size 4 at 0x7d1800055a24 by thread T11 (mutexes:
write M18771):
#0 frame_worker_thread ffmpeg/libavcodec/pthread.c:378:60
(c9c6e60608e58c16d6d8dc75627a71ed+0x00000098656b)
Note that although some mutexes were acquired when the write and read
occurred, they were not the same mutex. Here are the relevant code
snippets:
361 /**
362 * Codec worker thread.
363 *
364 * Automatically calls ff_thread_finish_setup() if the codec does
365 * not provide an update_thread_context method, or if the codec returns
366 * before calling it.
367 */
368 static attribute_align_arg void *frame_worker_thread(void *arg)
369 {
370 PerThreadContext *p = arg;
371 FrameThreadContext *fctx = p->parent;
372 AVCodecContext *avctx = p->avctx;
373 const AVCodec *codec = avctx->codec;
374
375 pthread_mutex_lock(&p->mutex);
376 while (1) {
377 int i;
378 while (p->state == STATE_INPUT_READY && !fctx->die)
379 pthread_cond_wait(&p->input_cond, &p->mutex);
380
381 if (fctx->die) break;
382
...
750 static void frame_thread_free(AVCodecContext *avctx, int thread_count)
751 {
752 FrameThreadContext *fctx = avctx->thread_opaque;
753 const AVCodec *codec = avctx->codec;
754 int i;
755
756 park_frame_worker_threads(fctx, thread_count);
757
758 if (fctx->prev_thread && fctx->prev_thread != fctx->threads)
759 update_context_from_thread(fctx->threads->avctx,
fctx->prev_thread- >avctx, 0);
760
761 fctx->die = 1;
762
763 for (i = 0; i < thread_count; i++) {
764 PerThreadContext *p = &fctx->threads[i];
765
766 pthread_mutex_lock(&p->mutex);
767 pthread_cond_signal(&p->input_cond);
768 pthread_mutex_unlock(&p->mutex);
769
770 if (p->thread_init)
771 pthread_join(p->thread, NULL);
772 p->thread_init=0;
773
774 if (codec->close)
775 codec->close(p->avctx);
776
777 avctx->codec = NULL;
778
779 release_delayed_buffers(p);
780 }
More information about the ffmpeg-devel
mailing list