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