diff options
author | James Zern <jzern@google.com> | 2014-06-19 21:14:51 -0700 |
---|---|---|
committer | James Zern <jzern@google.com> | 2014-07-01 00:39:10 -0700 |
commit | e656f44c241293134445496c3c005a0e543eb022 (patch) | |
tree | 57f4b92f12cd05085e3919c8942a3a54ac8ff47e /vp9/decoder/vp9_thread.c | |
parent | 8c6263e8dc9e1656057e51d7cd916b4db26b1aea (diff) | |
download | libvpx-e656f44c241293134445496c3c005a0e543eb022.tar libvpx-e656f44c241293134445496c3c005a0e543eb022.tar.gz libvpx-e656f44c241293134445496c3c005a0e543eb022.tar.bz2 libvpx-e656f44c241293134445496c3c005a0e543eb022.zip |
update vp9_thread.[hc]
pull the latest from WebP, which adds a worker interface abstraction
allowing an application to override init/reset/sync/launch/execute/end
this has the side effect of removing a harmless, but annoying, TSan
warning.
Original source:
http://git.chromium.org/webm/libwebp.git
100644 blob 08ad4e1fecba302bf1247645e84a7d2779956bc3 src/utils/thread.c
100644 blob 7bd451b124ae3b81596abfbcc823e3cb129d3a38 src/utils/thread.h
Local modifications:
- s/WebP/VP9/g
- camelcase functions -> lower with _'s
- associate '*' with the variable, not the type
Change-Id: I875ac5a74ed873cbcb19a3a100b5e0ca6fcd9aed
Diffstat (limited to 'vp9/decoder/vp9_thread.c')
-rw-r--r-- | vp9/decoder/vp9_thread.c | 134 |
1 files changed, 88 insertions, 46 deletions
diff --git a/vp9/decoder/vp9_thread.c b/vp9/decoder/vp9_thread.c index 5d31d3d98..348bdf6db 100644 --- a/vp9/decoder/vp9_thread.c +++ b/vp9/decoder/vp9_thread.c @@ -11,71 +11,79 @@ // // Original source: // http://git.chromium.org/webm/libwebp.git -// 100644 blob eff8f2a8c20095aade3c292b0e9292dac6cb3587 src/utils/thread.c - +// 100644 blob 08ad4e1fecba302bf1247645e84a7d2779956bc3 src/utils/thread.c #include <assert.h> #include <string.h> // for memset() #include "./vp9_thread.h" - -#if defined(__cplusplus) || defined(c_plusplus) -extern "C" { -#endif +#include "vpx_mem/vpx_mem.h" #if CONFIG_MULTITHREAD +struct VP9WorkerImpl { + pthread_mutex_t mutex_; + pthread_cond_t condition_; + pthread_t thread_; +}; + //------------------------------------------------------------------------------ -static THREADFN thread_loop(void *ptr) { // thread loop - VP9Worker* const worker = (VP9Worker*)ptr; +static void execute(VP9Worker *const worker); // Forward declaration. + +static THREADFN thread_loop(void *ptr) { + VP9Worker *const worker = (VP9Worker*)ptr; int done = 0; while (!done) { - pthread_mutex_lock(&worker->mutex_); + pthread_mutex_lock(&worker->impl_->mutex_); while (worker->status_ == OK) { // wait in idling mode - pthread_cond_wait(&worker->condition_, &worker->mutex_); + pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_); } if (worker->status_ == WORK) { - vp9_worker_execute(worker); + execute(worker); worker->status_ = OK; } else if (worker->status_ == NOT_OK) { // finish the worker done = 1; } - // signal to the main thread that we're done (for Sync()) - pthread_cond_signal(&worker->condition_); - pthread_mutex_unlock(&worker->mutex_); + // signal to the main thread that we're done (for sync()) + pthread_cond_signal(&worker->impl_->condition_); + pthread_mutex_unlock(&worker->impl_->mutex_); } return THREAD_RETURN(NULL); // Thread is finished } // main thread state control -static void change_state(VP9Worker* const worker, +static void change_state(VP9Worker *const worker, VP9WorkerStatus new_status) { - // no-op when attempting to change state on a thread that didn't come up - if (worker->status_ < OK) return; + // No-op when attempting to change state on a thread that didn't come up. + // Checking status_ without acquiring the lock first would result in a data + // race. + if (worker->impl_ == NULL) return; - pthread_mutex_lock(&worker->mutex_); - // wait for the worker to finish - while (worker->status_ != OK) { - pthread_cond_wait(&worker->condition_, &worker->mutex_); - } - // assign new status and release the working thread if needed - if (new_status != OK) { - worker->status_ = new_status; - pthread_cond_signal(&worker->condition_); + pthread_mutex_lock(&worker->impl_->mutex_); + if (worker->status_ >= OK) { + // wait for the worker to finish + while (worker->status_ != OK) { + pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_); + } + // assign new status and release the working thread if needed + if (new_status != OK) { + worker->status_ = new_status; + pthread_cond_signal(&worker->impl_->condition_); + } } - pthread_mutex_unlock(&worker->mutex_); + pthread_mutex_unlock(&worker->impl_->mutex_); } #endif // CONFIG_MULTITHREAD //------------------------------------------------------------------------------ -void vp9_worker_init(VP9Worker* const worker) { +static void init(VP9Worker *const worker) { memset(worker, 0, sizeof(*worker)); worker->status_ = NOT_OK; } -int vp9_worker_sync(VP9Worker* const worker) { +static int sync(VP9Worker *const worker) { #if CONFIG_MULTITHREAD change_state(worker, OK); #endif @@ -83,59 +91,93 @@ int vp9_worker_sync(VP9Worker* const worker) { return !worker->had_error; } -int vp9_worker_reset(VP9Worker* const worker) { +static int reset(VP9Worker *const worker) { int ok = 1; worker->had_error = 0; if (worker->status_ < OK) { #if CONFIG_MULTITHREAD - if (pthread_mutex_init(&worker->mutex_, NULL) || - pthread_cond_init(&worker->condition_, NULL)) { + worker->impl_ = (VP9WorkerImpl*)vpx_calloc(1, sizeof(*worker->impl_)); + if (worker->impl_ == NULL) { return 0; } - pthread_mutex_lock(&worker->mutex_); - ok = !pthread_create(&worker->thread_, NULL, thread_loop, worker); + if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) { + goto Error; + } + if (pthread_cond_init(&worker->impl_->condition_, NULL)) { + pthread_mutex_destroy(&worker->impl_->mutex_); + goto Error; + } + pthread_mutex_lock(&worker->impl_->mutex_); + ok = !pthread_create(&worker->impl_->thread_, NULL, thread_loop, worker); if (ok) worker->status_ = OK; - pthread_mutex_unlock(&worker->mutex_); + pthread_mutex_unlock(&worker->impl_->mutex_); + if (!ok) { + pthread_mutex_destroy(&worker->impl_->mutex_); + pthread_cond_destroy(&worker->impl_->condition_); + Error: + vpx_free(worker->impl_); + worker->impl_ = NULL; + return 0; + } #else worker->status_ = OK; #endif } else if (worker->status_ > OK) { - ok = vp9_worker_sync(worker); + ok = sync(worker); } assert(!ok || (worker->status_ == OK)); return ok; } -void vp9_worker_execute(VP9Worker* const worker) { +static void execute(VP9Worker *const worker) { if (worker->hook != NULL) { worker->had_error |= !worker->hook(worker->data1, worker->data2); } } -void vp9_worker_launch(VP9Worker* const worker) { +static void launch(VP9Worker *const worker) { #if CONFIG_MULTITHREAD change_state(worker, WORK); #else - vp9_worker_execute(worker); + execute(worker); #endif } -void vp9_worker_end(VP9Worker* const worker) { +static void end(VP9Worker *const worker) { if (worker->status_ >= OK) { #if CONFIG_MULTITHREAD change_state(worker, NOT_OK); - pthread_join(worker->thread_, NULL); - pthread_mutex_destroy(&worker->mutex_); - pthread_cond_destroy(&worker->condition_); + pthread_join(worker->impl_->thread_, NULL); + pthread_mutex_destroy(&worker->impl_->mutex_); + pthread_cond_destroy(&worker->impl_->condition_); #else worker->status_ = NOT_OK; #endif } + vpx_free(worker->impl_); + worker->impl_ = NULL; assert(worker->status_ == NOT_OK); } //------------------------------------------------------------------------------ -#if defined(__cplusplus) || defined(c_plusplus) -} // extern "C" -#endif +static VP9WorkerInterface g_worker_interface = { + init, reset, sync, launch, execute, end +}; + +int vp9_set_worker_interface(const VP9WorkerInterface* const winterface) { + if (winterface == NULL || + winterface->init == NULL || winterface->reset == NULL || + winterface->sync == NULL || winterface->launch == NULL || + winterface->execute == NULL || winterface->end == NULL) { + return 0; + } + g_worker_interface = *winterface; + return 1; +} + +const VP9WorkerInterface *vp9_get_worker_interface(void) { + return &g_worker_interface; +} + +//------------------------------------------------------------------------------ |