Due to the nature of multithreading, using a "ready check" mechanism may introduce a deadlock. For example: Suppose all tasks have been submitted to the executor, and the last thread checks the entire list and finds no ready tasks. It then goes to sleep, waiting for a new task. However, for some multithreading-related reason, a task becomes ready after the check. Since no other thread is aware of this and no new tasks are being added to the executor, a deadlock occurs. In VVC, this function is unnecessary because we use a scoreboard. All tasks submitted to the executor are ready tasks.
Unified · Split
| @@ -79,10 +79,8 @@ static void add_task(FFTask **prev, FFTask *t) · 78 unmodified lines | ||
| 79 | 79 | static int run_one_task(FFExecutor *e, void *lc) |
| 80 | 80 | { |
| 81 | 81 | FFTaskCallbacks *cb = &e->cb; |
| 82 | − FFTask **prev; | |
| 82 | + FFTask **prev = &e->tasks; | |
| 83 | 83 | |
| 84 | − for (prev = &e->tasks; *prev && !cb->ready(*prev, cb->user_data); prev = &(*prev)->next) | |
| 85 | − /* nothing */; | |
| 86 | 84 | if (*prev) { |
| 87 | 85 | FFTask *t = remove_task(prev, *prev); |
| 88 | 86 | if (e->thread_count > 0) |
| @@ -143,7 +141,7 @@ FFExecutor* ff_executor_alloc(const FFTaskCallbacks *cb, int thread_count) · 54 unmodified lines | ||
| 143 | 141 | { |
| 144 | 142 | FFExecutor *e; |
| 145 | 143 | int has_lock = 0, has_cond = 0; |
| 146 | − if (!cb || !cb->user_data || !cb->ready || !cb->run || !cb->priority_higher) | |
| 144 | + if (!cb || !cb->user_data || !cb->run || !cb->priority_higher) | |
| 147 | 145 | return NULL; |
| 148 | 146 | |
| 149 | 147 | e = av_mallocz(sizeof(*e)); |
| @@ -42,9 +42,6 @@ typedef struct FFTaskCallbacks { · 41 unmodified lines | ||
| 42 | 42 | // return 1 if a's priority > b's priority |
| 43 | 43 | int (*priority_higher)(const FFTask *a, const FFTask *b); |
| 44 | 44 | |
| 45 | − // task is ready for run | |
| 46 | − int (*ready)(const FFTask *t, void *user_data); | |
| 47 | − | |
| 48 | 45 | // run the task |
| 49 | 46 | int (*run)(FFTask *t, void *local_context, void *user_data); |
| 50 | 47 | } FFTaskCallbacks; |
| @@ -372,13 +372,6 @@ static int task_is_stage_ready(VVCTask *t, int add) · 371 unmodified lines | ||
| 372 | 372 | return task_has_target_score(t, stage, score); |
| 373 | 373 | } |
| 374 | 374 | |
| 375 | −static int task_ready(const FFTask *_t, void *user_data) | |
| 376 | −{ | |
| 377 | − VVCTask *t = (VVCTask*)_t; | |
| 378 | − | |
| 379 | − return task_is_stage_ready(t, 0); | |
| 380 | −} | |
| 381 | − | |
| 382 | 375 | #define CHECK(a, b) \ |
| 383 | 376 | do { \ |
| 384 | 377 | if ((a) != (b)) \ |
| @@ -689,7 +682,6 @@ FFExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count) · 304 unmodified lines | ||
| 689 | 682 | s, |
| 690 | 683 | sizeof(VVCLocalContext), |
| 691 | 684 | task_priority_higher, |
| 692 | − task_ready, | |
| 693 | 685 | task_run, |
| 694 | 686 | }; |
| 695 | 687 | return ff_executor_alloc(&callbacks, thread_count); |