History

lavc/hevcdec: unbreak WPP/progress2 code

The "progress2" API in pthread_slice.c currently associates a progress value with a thread rather than a job, relying on the broken assumption that a job's thread number is equal to its job number modulo thread count. This removes this API entirely, and changes hevcdec to use a ThreadProgress-based implementation that associates a mutex/cond/progress value with every job. Fixes races and deadlocks in hevdec with slice threading, e.g. some of those mentioned in #11221.

Anton Khirnov committed 2 years ago

Commit 79c47df1 parent c50f79a5 files · +46 −139Browse files

Showing the changes to libavcodec (5 of 5 files). Show all

Unified · Split

5 files
  1. libavcodec/hevc/hevcdec.c +43 −14
  2. libavcodec/hevc/hevcdec.h +3 −0
  3. libavcodec/pthread_slice.c +0 −102
  4. libavcodec/thread.h +0 −4
  5. libavcodec/utils.c +0 −19
libavcodec/hevc/hevcdec.c+43−14
@@ -54,6 +54,7 @@ · 53 unmodified lines
5454 #include "progressframe.h"
5555 #include "refstruct.h"
5656 #include "thread.h"
57+#include "threadprogress.h"
5758
5859 static const uint8_t hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 };
5960
@@ -2751,6 +2752,8 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, · 2691 unmodified lines
27512752 const uint8_t *data = s->data + s->sh.offset[ctb_row];
27522753 const size_t data_size = s->sh.size[ctb_row];
27532754
2755+ int progress = 0;
2756+
27542757 int ret;
27552758
27562759 if (ctb_row)
@@ -2762,13 +2765,15 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, · 5 unmodified lines
27622765
27632766 hls_decode_neighbour(lc, l, pps, sps, x_ctb, y_ctb, ctb_addr_ts);
27642767
2765− ff_thread_await_progress2(s->avctx, ctb_row, thread, SHIFT_CTB_WPP);
2768+ if (ctb_row)
2769+ ff_thread_progress_await(&s->wpp_progress[ctb_row - 1],
2770+ progress + SHIFT_CTB_WPP + 1);
27662771
27672772 /* atomic_load's prototype requires a pointer to non-const atomic variable
27682773 * (due to implementations via mutexes, where reads involve writes).
27692774 * Of course, casting const away here is nevertheless safe. */
27702775 if (atomic_load((atomic_int*)&s->wpp_err)) {
2771− ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP);
2776+ ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX);
27722777 return 0;
27732778 }
27742779
@@ -2792,19 +2797,19 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, · 17 unmodified lines
27922797 ctb_addr_ts++;
27932798
27942799 ff_hevc_save_states(lc, pps, ctb_addr_ts);
2795− ff_thread_report_progress2(s->avctx, ctb_row, thread, 1);
2800+ ff_thread_progress_report(&s->wpp_progress[ctb_row], ++progress);
27962801 ff_hevc_hls_filters(lc, l, pps, x_ctb, y_ctb, ctb_size);
27972802
27982803 if (!more_data && (x_ctb+ctb_size) < sps->width && ctb_row != s->sh.num_entry_point_offsets) {
27992804 /* Casting const away here is safe, because it is an atomic operation. */
28002805 atomic_store((atomic_int*)&s->wpp_err, 1);
2801− ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP);
2806+ ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX);
28022807 return 0;
28032808 }
28042809
28052810 if ((x_ctb+ctb_size) >= sps->width && (y_ctb+ctb_size) >= sps->height ) {
28062811 ff_hevc_hls_filter(lc, l, pps, x_ctb, y_ctb, ctb_size);
2807− ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP);
2812+ ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX);
28082813 return ctb_addr_ts;
28092814 }
28102815 ctb_addr_rs = pps->ctb_addr_ts_to_rs[ctb_addr_ts];
@@ -2814,17 +2819,43 @@ static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, · 3 unmodified lines
28142819 break;
28152820 }
28162821 }
2817− ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP);
2822+ ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX);
28182823
28192824 return 0;
28202825 error:
28212826 l->tab_slice_address[ctb_addr_rs] = -1;
28222827 /* Casting const away here is safe, because it is an atomic operation. */
28232828 atomic_store((atomic_int*)&s->wpp_err, 1);
2824− ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP);
2829+ ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX);
28252830 return ret;
28262831 }
28272832
2833+static int wpp_progress_init(HEVCContext *s, unsigned count)
2834+{
2835+ if (s->nb_wpp_progress < count) {
2836+ void *tmp = av_realloc_array(s->wpp_progress, count,
2837+ sizeof(*s->wpp_progress));
2838+ if (!tmp)
2839+ return AVERROR(ENOMEM);
2840+
2841+ s->wpp_progress = tmp;
2842+ memset(s->wpp_progress + s->nb_wpp_progress, 0,
2843+ (count - s->nb_wpp_progress) * sizeof(*s->wpp_progress));
2844+
2845+ for (int i = s->nb_wpp_progress; i < count; i++) {
2846+ int ret = ff_thread_progress_init(&s->wpp_progress[i], 1);
2847+ if (ret < 0)
2848+ return ret;
2849+ s->nb_wpp_progress = i + 1;
2850+ }
2851+ }
2852+
2853+ for (int i = 0; i < count; i++)
2854+ ff_thread_progress_reset(&s->wpp_progress[i]);
2855+
2856+ return 0;
2857+}
2858+
28282859 static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal)
28292860 {
28302861 const HEVCPPS *const pps = s->pps;
@@ -2909,7 +2940,7 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) · 78 unmodified lines
29092940 }
29102941
29112942 atomic_store(&s->wpp_err, 0);
2912− res = ff_slice_thread_allocz_entries(s->avctx, s->sh.num_entry_point_offsets + 1);
2943+ res = wpp_progress_init(s, s->sh.num_entry_point_offsets + 1);
29132944 if (res < 0)
29142945 return res;
29152946
@@ -3826,6 +3857,10 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) · 910 unmodified lines
38263857
38273858 ff_hevc_ps_uninit(&s->ps);
38283859
3860+ for (int i = 0; i < s->nb_wpp_progress; i++)
3861+ ff_thread_progress_destroy(&s->wpp_progress[i]);
3862+ av_freep(&s->wpp_progress);
3863+
38293864 av_freep(&s->sh.entry_point_offset);
38303865 av_freep(&s->sh.offset);
38313866 av_freep(&s->sh.size);
@@ -3981,12 +4016,6 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) · 149 unmodified lines
39814016 HEVCContext *s = avctx->priv_data;
39824017 int ret;
39834018
3984− if (avctx->active_thread_type & FF_THREAD_SLICE) {
3985− ret = ff_slice_thread_init_progress(avctx);
3986− if (ret < 0)
3987− return ret;
3988− }
3989−
39904019 ret = hevc_init_context(avctx);
39914020 if (ret < 0)
39924021 return ret;
libavcodec/hevc/hevcdec.h+3−0
@@ -540,6 +540,9 @@ typedef struct HEVCContext { · 539 unmodified lines
540540 /** The target for the common_cabac_state of the local contexts. */
541541 HEVCCABACState cabac;
542542
543+ struct ThreadProgress *wpp_progress;
544+ unsigned nb_wpp_progress;
545+
543546 atomic_int wpp_err;
544547
545548 const uint8_t *data;
libavcodec/pthread_slice.c+0−102
@@ -41,11 +41,6 @@ typedef int (action_func)(AVCodecContext *c, void *arg); · 40 unmodified lines
4141 typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr);
4242 typedef int (main_func)(AVCodecContext *c);
4343
44−typedef struct Progress {
45− pthread_cond_t cond;
46− pthread_mutex_t mutex;
47−} Progress;
48−
4944 typedef struct SliceThreadContext {
5045 AVSliceThread *thread;
5146 action_func *func;
@@ -54,11 +49,6 @@ typedef struct SliceThreadContext { · 2 unmodified lines
5449 void *args;
5550 int *rets;
5651 int job_size;
57−
58− int *entries;
59− int entries_count;
60− int thread_count;
61− Progress *progress;
6252 } SliceThreadContext;
6353
6454 static void main_function(void *priv) {
@@ -82,18 +72,9 @@ static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb · 17 unmodified lines
8272 void ff_slice_thread_free(AVCodecContext *avctx)
8373 {
8474 SliceThreadContext *c = avctx->internal->thread_ctx;
85− int i;
8675
8776 avpriv_slicethread_free(&c->thread);
8877
89− for (i = 0; i < c->thread_count; i++) {
90− Progress *const progress = &c->progress[i];
91− pthread_mutex_destroy(&progress->mutex);
92− pthread_cond_destroy(&progress->cond);
93− }
94−
95− av_freep(&c->entries);
96− av_freep(&c->progress);
9778 av_freep(&avctx->internal->thread_ctx);
9879 }
9980
@@ -175,86 +156,3 @@ int ff_slice_thread_init(AVCodecContext *avctx) · 75 unmodified lines
175156 avctx->execute2 = thread_execute2;
176157 return 0;
177158 }
178−
179−int av_cold ff_slice_thread_init_progress(AVCodecContext *avctx)
180−{
181− SliceThreadContext *const p = avctx->internal->thread_ctx;
182− int err, i = 0, thread_count = avctx->thread_count;
183−
184− p->progress = av_calloc(thread_count, sizeof(*p->progress));
185− if (!p->progress) {
186− err = AVERROR(ENOMEM);
187− goto fail;
188− }
189−
190− for (; i < thread_count; i++) {
191− Progress *const progress = &p->progress[i];
192− err = pthread_mutex_init(&progress->mutex, NULL);
193− if (err) {
194− err = AVERROR(err);
195− goto fail;
196− }
197− err = pthread_cond_init (&progress->cond, NULL);
198− if (err) {
199− err = AVERROR(err);
200− pthread_mutex_destroy(&progress->mutex);
201− goto fail;
202− }
203− }
204− err = 0;
205−fail:
206− p->thread_count = i;
207− return err;
208−}
209−
210−void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n)
211−{
212− SliceThreadContext *p = avctx->internal->thread_ctx;
213− Progress *const progress = &p->progress[thread];
214− int *entries = p->entries;
215−
216− pthread_mutex_lock(&progress->mutex);
217− entries[field] +=n;
218− pthread_cond_signal(&progress->cond);
219− pthread_mutex_unlock(&progress->mutex);
220−}
221−
222−void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift)
223−{
224− SliceThreadContext *p = avctx->internal->thread_ctx;
225− Progress *progress;
226− int *entries = p->entries;
227−
228− if (!entries || !field) return;
229−
230− thread = thread ? thread - 1 : p->thread_count - 1;
231− progress = &p->progress[thread];
232−
233− pthread_mutex_lock(&progress->mutex);
234− while ((entries[field - 1] - entries[field]) < shift){
235− pthread_cond_wait(&progress->cond, &progress->mutex);
236− }
237− pthread_mutex_unlock(&progress->mutex);
238−}
239−
240−int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count)
241−{
242− if (avctx->active_thread_type & FF_THREAD_SLICE) {
243− SliceThreadContext *p = avctx->internal->thread_ctx;
244−
245− if (p->entries_count == count) {
246− memset(p->entries, 0, p->entries_count * sizeof(*p->entries));
247− return 0;
248− }
249− av_freep(&p->entries);
250−
251− p->entries = av_calloc(count, sizeof(*p->entries));
252− if (!p->entries) {
253− p->entries_count = 0;
254− return AVERROR(ENOMEM);
255− }
256− p->entries_count = count;
257− }
258−
259− return 0;
260−}
libavcodec/thread.h+0−4
@@ -56,10 +56,6 @@ int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags); · 55 unmodified lines
5656 int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx,
5757 int (*action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr),
5858 int (*main_func)(AVCodecContext *c), void *arg, int *ret, int job_count);
59−int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count);
60−int ff_slice_thread_init_progress(AVCodecContext *avctx);
61−void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n);
62−void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift);
6359
6460 enum ThreadingStatus {
6561 FF_THREAD_IS_COPY,
libavcodec/utils.c+0−19
@@ -913,25 +913,6 @@ int ff_thread_can_start_frame(AVCodecContext *avctx) · 912 unmodified lines
913913 {
914914 return 1;
915915 }
916−
917−int ff_slice_thread_init_progress(AVCodecContext *avctx)
918−{
919− return 0;
920−}
921−
922−int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count)
923−{
924− return 0;
925−}
926−
927−void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift)
928−{
929−}
930−
931−void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n)
932−{
933−}
934−
935916 #endif
936917
937918 const uint8_t *avpriv_find_start_code(const uint8_t *restrict p,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t