[FFmpeg-devel] [PATCH] Always read frame progress values under progress_mutex.

Wan-Teh Chang wtc at google.com
Fri Feb 26 01:42:22 CET 2016


On Thu, Feb 25, 2016 at 4:15 PM, Hendrik Leppkes <h.leppkes at gmail.com> wrote:
>
> Similar to the other patch, please explain what this actually fixes,
> those sanitizer tools produce a lot of false positives and nonsensical
> warnings.

Yes, certainly.

In libavcodec/pthread_frame.c, we have:

 46 /**
 47  * Context used by codec threads and stored in their
AVCodecInternal thread_    ctx.
 48  */
 49 typedef struct PerThreadContext {
 ...
 59     pthread_mutex_t progress_mutex; ///< Mutex used to protect
frame progress values and progress_cond.

The comment on line 59 documents that progress_mutex guards frame
progress values and progress_cond. (In fact, progress_mutex also
guards the |state| field in many places, but that's not the subject of
this patch.)

I assume "frame progess values" mean f->progress->data, where |f|
points to a ThreadFrame. I inspected libavcodec/pthread_frame.c and
concluded the code (ff_thread_report_progress and
ff_thread_await_progress) matches that comment, except that it also
does a double-checked locking style performance optimization. For
example, here is ff_thread_report_progress:

472 void ff_thread_report_progress(ThreadFrame *f, int n, int field)
473 {
474     PerThreadContext *p;
475     volatile int *progress = f->progress ? (int*)f->progress->data : NULL;
476
477     if (!progress || progress[field] >= n) return;
478
479     p = f->owner->internal->thread_ctx;
480
481     if (f->owner->debug&FF_DEBUG_THREADS)
482         av_log(f->owner, AV_LOG_DEBUG, "%p finished %d field
%d\n", progress    , n, field);
483
484     pthread_mutex_lock(&p->progress_mutex);
485     progress[field] = n;
486     pthread_cond_broadcast(&p->progress_cond);
487     pthread_mutex_unlock(&p->progress_mutex);
488 }

progress[field] can only increase. So, both ff_thread_report_progress
and ff_thread_await_progress have a fast code path (line 477 and line
495, respectively) that reads progress[field] without acquiring
progress_mutex. If the speculatively read value of progress[field] is
>= |n|, then the functions return immediately. Otherwise, the
functions take the slow code path, which acquires progress_mutex
properly and does what the functions need to do.

The fast code path is in the style of double-checked locking and has a
data race. ThreadSanitizer is right in this case.

Wan-Teh Chang


More information about the ffmpeg-devel mailing list