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) 22extern "C" { 23#endif 24 25#if CONFIG_MULTITHREAD 26 27//------------------------------------------------------------------------------ 28 29static 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 51static 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 73void vp9_worker_init(VP9Worker* const worker) { 74 memset(worker, 0, sizeof(*worker)); 75 worker->status_ = NOT_OK; 76} 77 78int 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 86int 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 109void vp9_worker_execute(VP9Worker* const worker) { 110 if (worker->hook != NULL) { 111 worker->had_error |= !worker->hook(worker->data1, worker->data2); 112 } 113} 114 115void 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 123void 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