media/libvpx/vp9/decoder/vp9_thread.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libvpx/vp9/decoder/vp9_thread.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,251 @@
     1.4 +// Copyright 2013 Google Inc. All Rights Reserved.
     1.5 +//
     1.6 +// Use of this source code is governed by a BSD-style license
     1.7 +// that can be found in the COPYING file in the root of the source
     1.8 +// tree. An additional intellectual property rights grant can be found
     1.9 +// in the file PATENTS. All contributing project authors may
    1.10 +// be found in the AUTHORS file in the root of the source tree.
    1.11 +// -----------------------------------------------------------------------------
    1.12 +//
    1.13 +// Multi-threaded worker
    1.14 +//
    1.15 +// Original source:
    1.16 +//  http://git.chromium.org/webm/libwebp.git
    1.17 +//  100644 blob eff8f2a8c20095aade3c292b0e9292dac6cb3587  src/utils/thread.c
    1.18 +
    1.19 +
    1.20 +#include <assert.h>
    1.21 +#include <string.h>   // for memset()
    1.22 +#include "./vp9_thread.h"
    1.23 +
    1.24 +#if defined(__cplusplus) || defined(c_plusplus)
    1.25 +extern "C" {
    1.26 +#endif
    1.27 +
    1.28 +#if CONFIG_MULTITHREAD
    1.29 +
    1.30 +#if defined(_WIN32)
    1.31 +
    1.32 +//------------------------------------------------------------------------------
    1.33 +// simplistic pthread emulation layer
    1.34 +
    1.35 +#include <process.h>  // NOLINT
    1.36 +
    1.37 +// _beginthreadex requires __stdcall
    1.38 +#define THREADFN unsigned int __stdcall
    1.39 +#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
    1.40 +
    1.41 +static int pthread_create(pthread_t* const thread, const void* attr,
    1.42 +                          unsigned int (__stdcall *start)(void*), void* arg) {
    1.43 +  (void)attr;
    1.44 +  *thread = (pthread_t)_beginthreadex(NULL,   /* void *security */
    1.45 +                                      0,      /* unsigned stack_size */
    1.46 +                                      start,
    1.47 +                                      arg,
    1.48 +                                      0,      /* unsigned initflag */
    1.49 +                                      NULL);  /* unsigned *thrdaddr */
    1.50 +  if (*thread == NULL) return 1;
    1.51 +  SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
    1.52 +  return 0;
    1.53 +}
    1.54 +
    1.55 +static int pthread_join(pthread_t thread, void** value_ptr) {
    1.56 +  (void)value_ptr;
    1.57 +  return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 ||
    1.58 +          CloseHandle(thread) == 0);
    1.59 +}
    1.60 +
    1.61 +// Mutex
    1.62 +static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) {
    1.63 +  (void)mutexattr;
    1.64 +  InitializeCriticalSection(mutex);
    1.65 +  return 0;
    1.66 +}
    1.67 +
    1.68 +static int pthread_mutex_lock(pthread_mutex_t* const mutex) {
    1.69 +  EnterCriticalSection(mutex);
    1.70 +  return 0;
    1.71 +}
    1.72 +
    1.73 +static int pthread_mutex_unlock(pthread_mutex_t* const mutex) {
    1.74 +  LeaveCriticalSection(mutex);
    1.75 +  return 0;
    1.76 +}
    1.77 +
    1.78 +static int pthread_mutex_destroy(pthread_mutex_t* const mutex) {
    1.79 +  DeleteCriticalSection(mutex);
    1.80 +  return 0;
    1.81 +}
    1.82 +
    1.83 +// Condition
    1.84 +static int pthread_cond_destroy(pthread_cond_t* const condition) {
    1.85 +  int ok = 1;
    1.86 +  ok &= (CloseHandle(condition->waiting_sem_) != 0);
    1.87 +  ok &= (CloseHandle(condition->received_sem_) != 0);
    1.88 +  ok &= (CloseHandle(condition->signal_event_) != 0);
    1.89 +  return !ok;
    1.90 +}
    1.91 +
    1.92 +static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
    1.93 +  (void)cond_attr;
    1.94 +  condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
    1.95 +  condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
    1.96 +  condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
    1.97 +  if (condition->waiting_sem_ == NULL ||
    1.98 +      condition->received_sem_ == NULL ||
    1.99 +      condition->signal_event_ == NULL) {
   1.100 +    pthread_cond_destroy(condition);
   1.101 +    return 1;
   1.102 +  }
   1.103 +  return 0;
   1.104 +}
   1.105 +
   1.106 +static int pthread_cond_signal(pthread_cond_t* const condition) {
   1.107 +  int ok = 1;
   1.108 +  if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
   1.109 +    // a thread is waiting in pthread_cond_wait: allow it to be notified
   1.110 +    ok = SetEvent(condition->signal_event_);
   1.111 +    // wait until the event is consumed so the signaler cannot consume
   1.112 +    // the event via its own pthread_cond_wait.
   1.113 +    ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
   1.114 +           WAIT_OBJECT_0);
   1.115 +  }
   1.116 +  return !ok;
   1.117 +}
   1.118 +
   1.119 +static int pthread_cond_wait(pthread_cond_t* const condition,
   1.120 +                             pthread_mutex_t* const mutex) {
   1.121 +  int ok;
   1.122 +  // note that there is a consumer available so the signal isn't dropped in
   1.123 +  // pthread_cond_signal
   1.124 +  if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL))
   1.125 +    return 1;
   1.126 +  // now unlock the mutex so pthread_cond_signal may be issued
   1.127 +  pthread_mutex_unlock(mutex);
   1.128 +  ok = (WaitForSingleObject(condition->signal_event_, INFINITE) ==
   1.129 +        WAIT_OBJECT_0);
   1.130 +  ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
   1.131 +  pthread_mutex_lock(mutex);
   1.132 +  return !ok;
   1.133 +}
   1.134 +
   1.135 +#else  // _WIN32
   1.136 +# define THREADFN void*
   1.137 +# define THREAD_RETURN(val) val
   1.138 +#endif
   1.139 +
   1.140 +//------------------------------------------------------------------------------
   1.141 +
   1.142 +static THREADFN thread_loop(void *ptr) {    // thread loop
   1.143 +  VP9Worker* const worker = (VP9Worker*)ptr;
   1.144 +  int done = 0;
   1.145 +  while (!done) {
   1.146 +    pthread_mutex_lock(&worker->mutex_);
   1.147 +    while (worker->status_ == OK) {   // wait in idling mode
   1.148 +      pthread_cond_wait(&worker->condition_, &worker->mutex_);
   1.149 +    }
   1.150 +    if (worker->status_ == WORK) {
   1.151 +      vp9_worker_execute(worker);
   1.152 +      worker->status_ = OK;
   1.153 +    } else if (worker->status_ == NOT_OK) {   // finish the worker
   1.154 +      done = 1;
   1.155 +    }
   1.156 +    // signal to the main thread that we're done (for Sync())
   1.157 +    pthread_cond_signal(&worker->condition_);
   1.158 +    pthread_mutex_unlock(&worker->mutex_);
   1.159 +  }
   1.160 +  return THREAD_RETURN(NULL);    // Thread is finished
   1.161 +}
   1.162 +
   1.163 +// main thread state control
   1.164 +static void change_state(VP9Worker* const worker,
   1.165 +                         VP9WorkerStatus new_status) {
   1.166 +  // no-op when attempting to change state on a thread that didn't come up
   1.167 +  if (worker->status_ < OK) return;
   1.168 +
   1.169 +  pthread_mutex_lock(&worker->mutex_);
   1.170 +  // wait for the worker to finish
   1.171 +  while (worker->status_ != OK) {
   1.172 +    pthread_cond_wait(&worker->condition_, &worker->mutex_);
   1.173 +  }
   1.174 +  // assign new status and release the working thread if needed
   1.175 +  if (new_status != OK) {
   1.176 +    worker->status_ = new_status;
   1.177 +    pthread_cond_signal(&worker->condition_);
   1.178 +  }
   1.179 +  pthread_mutex_unlock(&worker->mutex_);
   1.180 +}
   1.181 +
   1.182 +#endif  // CONFIG_MULTITHREAD
   1.183 +
   1.184 +//------------------------------------------------------------------------------
   1.185 +
   1.186 +void vp9_worker_init(VP9Worker* const worker) {
   1.187 +  memset(worker, 0, sizeof(*worker));
   1.188 +  worker->status_ = NOT_OK;
   1.189 +}
   1.190 +
   1.191 +int vp9_worker_sync(VP9Worker* const worker) {
   1.192 +#if CONFIG_MULTITHREAD
   1.193 +  change_state(worker, OK);
   1.194 +#endif
   1.195 +  assert(worker->status_ <= OK);
   1.196 +  return !worker->had_error;
   1.197 +}
   1.198 +
   1.199 +int vp9_worker_reset(VP9Worker* const worker) {
   1.200 +  int ok = 1;
   1.201 +  worker->had_error = 0;
   1.202 +  if (worker->status_ < OK) {
   1.203 +#if CONFIG_MULTITHREAD
   1.204 +    if (pthread_mutex_init(&worker->mutex_, NULL) ||
   1.205 +        pthread_cond_init(&worker->condition_, NULL)) {
   1.206 +      return 0;
   1.207 +    }
   1.208 +    pthread_mutex_lock(&worker->mutex_);
   1.209 +    ok = !pthread_create(&worker->thread_, NULL, thread_loop, worker);
   1.210 +    if (ok) worker->status_ = OK;
   1.211 +    pthread_mutex_unlock(&worker->mutex_);
   1.212 +#else
   1.213 +    worker->status_ = OK;
   1.214 +#endif
   1.215 +  } else if (worker->status_ > OK) {
   1.216 +    ok = vp9_worker_sync(worker);
   1.217 +  }
   1.218 +  assert(!ok || (worker->status_ == OK));
   1.219 +  return ok;
   1.220 +}
   1.221 +
   1.222 +void vp9_worker_execute(VP9Worker* const worker) {
   1.223 +  if (worker->hook != NULL) {
   1.224 +    worker->had_error |= !worker->hook(worker->data1, worker->data2);
   1.225 +  }
   1.226 +}
   1.227 +
   1.228 +void vp9_worker_launch(VP9Worker* const worker) {
   1.229 +#if CONFIG_MULTITHREAD
   1.230 +  change_state(worker, WORK);
   1.231 +#else
   1.232 +  vp9_worker_execute(worker);
   1.233 +#endif
   1.234 +}
   1.235 +
   1.236 +void vp9_worker_end(VP9Worker* const worker) {
   1.237 +  if (worker->status_ >= OK) {
   1.238 +#if CONFIG_MULTITHREAD
   1.239 +    change_state(worker, NOT_OK);
   1.240 +    pthread_join(worker->thread_, NULL);
   1.241 +    pthread_mutex_destroy(&worker->mutex_);
   1.242 +    pthread_cond_destroy(&worker->condition_);
   1.243 +#else
   1.244 +    worker->status_ = NOT_OK;
   1.245 +#endif
   1.246 +  }
   1.247 +  assert(worker->status_ == NOT_OK);
   1.248 +}
   1.249 +
   1.250 +//------------------------------------------------------------------------------
   1.251 +
   1.252 +#if defined(__cplusplus) || defined(c_plusplus)
   1.253 +}    // extern "C"
   1.254 +#endif

mercurial