Home | History | Annotate | Download | only in decoder
      1 // Copyright 2013 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Multi-threaded worker
     11 //
     12 // Original source:
     13 //  http://git.chromium.org/webm/libwebp.git
     14 //  100644 blob eff8f2a8c20095aade3c292b0e9292dac6cb3587  src/utils/thread.c
     15 
     16 
     17 #include <assert.h>
     18 #include <string.h>   // for memset()
     19 #include "./vp9_thread.h"
     20 
     21 #if defined(__cplusplus) || defined(c_plusplus)
     22 extern "C" {
     23 #endif
     24 
     25 #if CONFIG_MULTITHREAD
     26 
     27 //------------------------------------------------------------------------------
     28 
     29 static THREADFN thread_loop(void *ptr) {    // thread loop
     30   VP9Worker* const worker = (VP9Worker*)ptr;
     31   int done = 0;
     32   while (!done) {
     33     pthread_mutex_lock(&worker->mutex_);
     34     while (worker->status_ == OK) {   // wait in idling mode
     35       pthread_cond_wait(&worker->condition_, &worker->mutex_);
     36     }
     37     if (worker->status_ == WORK) {
     38       vp9_worker_execute(worker);
     39       worker->status_ = OK;
     40     } else if (worker->status_ == NOT_OK) {   // finish the worker
     41       done = 1;
     42     }
     43     // signal to the main thread that we're done (for Sync())
     44     pthread_cond_signal(&worker->condition_);
     45     pthread_mutex_unlock(&worker->mutex_);
     46   }
     47   return THREAD_RETURN(NULL);    // Thread is finished
     48 }
     49 
     50 // main thread state control
     51 static void change_state(VP9Worker* const worker,
     52                          VP9WorkerStatus new_status) {
     53   // no-op when attempting to change state on a thread that didn't come up
     54   if (worker->status_ < OK) return;
     55 
     56   pthread_mutex_lock(&worker->mutex_);
     57   // wait for the worker to finish
     58   while (worker->status_ != OK) {
     59     pthread_cond_wait(&worker->condition_, &worker->mutex_);
     60   }
     61   // assign new status and release the working thread if needed
     62   if (new_status != OK) {
     63     worker->status_ = new_status;
     64     pthread_cond_signal(&worker->condition_);
     65   }
     66   pthread_mutex_unlock(&worker->mutex_);
     67 }
     68 
     69 #endif  // CONFIG_MULTITHREAD
     70 
     71 //------------------------------------------------------------------------------
     72 
     73 void vp9_worker_init(VP9Worker* const worker) {
     74   memset(worker, 0, sizeof(*worker));
     75   worker->status_ = NOT_OK;
     76 }
     77 
     78 int vp9_worker_sync(VP9Worker* const worker) {
     79 #if CONFIG_MULTITHREAD
     80   change_state(worker, OK);
     81 #endif
     82   assert(worker->status_ <= OK);
     83   return !worker->had_error;
     84 }
     85 
     86 int vp9_worker_reset(VP9Worker* const worker) {
     87   int ok = 1;
     88   worker->had_error = 0;
     89   if (worker->status_ < OK) {
     90 #if CONFIG_MULTITHREAD
     91     if (pthread_mutex_init(&worker->mutex_, NULL) ||
     92         pthread_cond_init(&worker->condition_, NULL)) {
     93       return 0;
     94     }
     95     pthread_mutex_lock(&worker->mutex_);
     96     ok = !pthread_create(&worker->thread_, NULL, thread_loop, worker);
     97     if (ok) worker->status_ = OK;
     98     pthread_mutex_unlock(&worker->mutex_);
     99 #else
    100     worker->status_ = OK;
    101 #endif
    102   } else if (worker->status_ > OK) {
    103     ok = vp9_worker_sync(worker);
    104   }
    105   assert(!ok || (worker->status_ == OK));
    106   return ok;
    107 }
    108 
    109 void vp9_worker_execute(VP9Worker* const worker) {
    110   if (worker->hook != NULL) {
    111     worker->had_error |= !worker->hook(worker->data1, worker->data2);
    112   }
    113 }
    114 
    115 void vp9_worker_launch(VP9Worker* const worker) {
    116 #if CONFIG_MULTITHREAD
    117   change_state(worker, WORK);
    118 #else
    119   vp9_worker_execute(worker);
    120 #endif
    121 }
    122 
    123 void vp9_worker_end(VP9Worker* const worker) {
    124   if (worker->status_ >= OK) {
    125 #if CONFIG_MULTITHREAD
    126     change_state(worker, NOT_OK);
    127     pthread_join(worker->thread_, NULL);
    128     pthread_mutex_destroy(&worker->mutex_);
    129     pthread_cond_destroy(&worker->condition_);
    130 #else
    131     worker->status_ = NOT_OK;
    132 #endif
    133   }
    134   assert(worker->status_ == NOT_OK);
    135 }
    136 
    137 //------------------------------------------------------------------------------
    138 
    139 #if defined(__cplusplus) || defined(c_plusplus)
    140 }    // extern "C"
    141 #endif
    142