diff --git a/f265/enc.c b/f265/enc.c
index b9e55f6..a752fc9 100644
--- a/f265/enc.c
+++ b/f265/enc.c
@@ -989,6 +989,11 @@ void fenc_deinit_enc(f265_enc *enc)
         f265_main_data *md = &enc->md;
         f265_enc_sync *es = &enc->es;
 
+        // Abort the encoding.
+        f265_mutex_lock(&es->mutex);
+        es->abort_flag = 1;
+        f265_mutex_unlock(&es->mutex);
+
         // Terminate running threads. Check flags to avoid releasing
         // uninitialized resources.
         for (int n = 0; n < md->nb_enc_threads; n++)
@@ -997,11 +1002,6 @@ void fenc_deinit_enc(f265_enc *enc)
 
             if (t->handle_flag)
             {
-                // Update its status.
-                f265_mutex_lock(&es->mutex);
-                t->status = F265_THREAD_EXIT;
-                f265_mutex_unlock(&es->mutex);
-
                 // Wake up worker thread so it can exit properly.
                 f265_cond_signal(&t->worker_cv);
 
@@ -1374,92 +1374,76 @@ static void* fenc_encode_parallel_tile(void *args)
     // Check for colleague.
     if (t - md->enc_threads[0] < md->nb_enc_threads-1) next = t+1;
 
-    // Worker loop.
-    int exit_flag = 0;
-    while (!exit_flag)
+    // Track whether we signaled our colleague for the current frame yet.
+    int next_signaled_flag = 0;
+
+    // Enter an infinite loop in mutual exclusion.
+    f265_mutex_lock(mutex);
+    while (1)
     {
-        // Wait for work. Prevent spurious wakeup.
-        int status;
-        f265_mutex_lock(mutex);
-        do
+        // Exit requested.
+        if (es->abort_flag)
         {
-            // When woken up, make sure the thread is no longer set to IDLE.
-            f265_cond_wait(&t->worker_cv, mutex);
-            status = t->status;
+            // Tell the master that we are exiting.
+            t->status = F265_THREAD_EXIT;
+            f265_cond_signal(&es->master_cv);
 
-        } while (status == F265_THREAD_IDLE);
+            // Leave mutual exclusion and exit.
+            f265_mutex_unlock(mutex);
+            return NULL;
+        }
+
+        // We're idle. Leave mutual exclusion and wait for something to happen.
+        else if (t->status == F265_THREAD_IDLE)
+            f265_cond_wait(&t->worker_cv, mutex);
 
-        // Wake up colleague.
-        if (status == F265_THREAD_BUSY && next)
+        // An error occurred or we're out of sections to encode.
+        else if (es->error_flag || es->next_section_idx >= t->src_frame->fmap->nb_sections)
         {
-            // Get colleague thread ready for work.
-            // NOTE. Having each thread init its own data requires modifying the
-            //       parameter passed to fenc_encode_parallel_tile. It would
-            //       need to be a struct that would hold the encoding thread,
-            //       the frame and the QP for proper initialization. This
-            //       approach makes it uniform: the master thread wakes up the
-            //       first worker after having shared the info it needs to work.
-            fenc_init_enc_thread(e, t->src_frame, next, t->qp[0]);
-            next->status = F265_THREAD_BUSY;
-
-            // Wake up call.
-            f265_cond_signal(&next->worker_cv);
-        }
+            // Reset the colleague signaled status.
+            next_signaled_flag = 0;
 
-        // Stop hogging the mutex. Take a breather.
-        f265_mutex_unlock(mutex);
+            // Tell the master that we're idle.
+            t->status = F265_THREAD_IDLE;
+            f265_cond_signal(&es->master_cv);
+        }
 
-        // Tile encoding loop.
-        do
+        // We have a section to encode.
+        else
         {
-            // Fetch next available tile.
-            // NOTE. Optimize this eventually. For the first loop, this results
-            //       in a back-to-back unlock-lock combo.
-            f265_mutex_lock(mutex);
+            // Get the index of the section to encode and update the section
+            // index.
             int section_idx = es->next_section_idx++;
-            exit_flag = es->abort_flag | es->error_flag | status == F265_THREAD_EXIT;
-            f265_mutex_unlock(mutex);
-
-            // Stop work loop entirely if any thread aborted, an error occurred,
-            // or exit was requested.
-            if (exit_flag) break;
 
-            // Pause when all other tiles have been, or are being processed.
-            if (section_idx >= t->src_frame->fmap->nb_sections)
+            // Initialize and change the status of our colleague in mutual
+            // exclusion. Don't signal it yet because it cannot acquire the
+            // mutex yet.
+            if (next && !next_signaled_flag)
             {
-                // Update status.
-                f265_mutex_lock(mutex);
-                status = t->status = F265_THREAD_IDLE;
-                f265_mutex_unlock(mutex);
-
-                // Notify master thread.
-                f265_cond_signal(&es->master_cv);
+                fenc_init_enc_thread(e, t->src_frame, next, t->qp[0]);
+                next->status = F265_THREAD_BUSY;
             }
 
-            // Process tile. Signal any problems to coworkers.
-            else
+            // Leave mutual exclusion.
+            f265_mutex_unlock(mutex);
+
+            // Signal our colleague now that we have released the mutex.
+            if (next && !next_signaled_flag)
             {
-                int res = fenc_encode_section(t, section_idx);
-                if (res == F265_RET_ABORT)
-                {
-                    f265_mutex_lock(mutex);
-                    es->abort_flag = 1;
-                    f265_mutex_unlock(mutex);
-                }
+                next_signaled_flag = 1;
+                f265_cond_signal(&next->worker_cv);
             }
-        } while (status == F265_THREAD_BUSY);
-    }
 
-    // Clean exit. Force EXIT status in case this was caused by an abort signal
-    // or an error during encoding.
-    f265_mutex_lock(mutex);
-    t->status = F265_THREAD_EXIT;
-    f265_mutex_unlock(mutex);
+            // Process our section.
+            int res = fenc_encode_section(t, section_idx);
 
-    // Tell the master thread about it.
-    f265_cond_signal(&es->master_cv);
+            // Enter mutual exclusion.
+            f265_mutex_lock(mutex);
 
-    return NULL;
+            // Report a problem.
+            if (res == F265_RET_ABORT) es->abort_flag = 1;
+        }
+    }
 }
 
 // Have the main thread use the worker threads. The main thread then makes sure
@@ -1483,36 +1467,38 @@ static int fenc_encode_frame_mt_tile(f265_enc *e, f265_frame *f)
     // Frame re-encoding loop.
     while (1)
     {
-        // Avoid spurious wakeup locking problems.
+        // Enter mutual exclusion.
         f265_mutex_lock(mutex);
 
-        // Init the first worker thread.
+        // Initialize the job list.
+        es->next_section_idx = 0;
+
+        // Initialize the first worker thread.
         f265_enc_thread *t = md->enc_threads[0];
         fenc_init_enc_thread(e, f, t, -1);
 
-        // Update its status to BUSY.
+        // Set its status to BUSY.
         t->status = F265_THREAD_BUSY;
 
-        // Update job listing.
-        es->next_section_idx = 0;
-
-        f265_mutex_unlock(mutex);
-
         // Wake it up. It will wake up the others.
         f265_cond_signal(&t->worker_cv);
 
-        // Wait for all the threads to finish.
-        int busy_flag;
-        f265_mutex_lock(mutex);
-        do
+        // Wait for all the threads to become idle.
+        while (1)
         {
-            f265_cond_wait(&es->master_cv, mutex);
-
-            busy_flag = 0;
+            // Check if a thread is busy.
+            int busy_flag = 0;
             for (int n = 0; n < md->nb_enc_threads; n++)
                 busy_flag |= md->enc_threads[n]->status == F265_THREAD_BUSY;
 
-        } while (busy_flag);
+            // All threads are idle, leave.
+            if (!busy_flag) break;
+
+            // Wait for threads to become idle.
+            f265_cond_wait(&es->master_cv, mutex);
+        }
+
+        // Leave mutual exclusion.
         f265_mutex_unlock(mutex);
 
         // The main thread validates the results.

Reply via email to