blob: 954b8f99c3986073781ba23a0b938922880a0624 [file] [log] [blame]
Yaowu Xu9c01aa12016-09-01 14:32:49 -07001/*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
Yaowu Xuc27fc142016-08-22 16:08:15 -070011//
12// Multi-threaded worker
13//
14// Original source:
15// https://chromium.googlesource.com/webm/libwebp
16
17#include <assert.h>
18#include <string.h> // for memset()
Yaowu Xuf883b422016-08-30 14:01:10 -070019#include "./aom_thread.h"
20#include "aom_mem/aom_mem.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070021
22#if CONFIG_MULTITHREAD
23
Yaowu Xuf883b422016-08-30 14:01:10 -070024struct AVxWorkerImpl {
Yaowu Xuc27fc142016-08-22 16:08:15 -070025 pthread_mutex_t mutex_;
26 pthread_cond_t condition_;
27 pthread_t thread_;
28};
29
30//------------------------------------------------------------------------------
31
Yaowu Xuf883b422016-08-30 14:01:10 -070032static void execute(AVxWorker *const worker); // Forward declaration.
Yaowu Xuc27fc142016-08-22 16:08:15 -070033
34static THREADFN thread_loop(void *ptr) {
Yaowu Xuf883b422016-08-30 14:01:10 -070035 AVxWorker *const worker = (AVxWorker *)ptr;
Yaowu Xuc27fc142016-08-22 16:08:15 -070036 int done = 0;
37 while (!done) {
38 pthread_mutex_lock(&worker->impl_->mutex_);
39 while (worker->status_ == OK) { // wait in idling mode
40 pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
41 }
42 if (worker->status_ == WORK) {
43 execute(worker);
44 worker->status_ = OK;
45 } else if (worker->status_ == NOT_OK) { // finish the worker
46 done = 1;
47 }
48 // signal to the main thread that we're done (for sync())
49 pthread_cond_signal(&worker->impl_->condition_);
50 pthread_mutex_unlock(&worker->impl_->mutex_);
51 }
52 return THREAD_RETURN(NULL); // Thread is finished
53}
54
55// main thread state control
Yaowu Xuf883b422016-08-30 14:01:10 -070056static void change_state(AVxWorker *const worker, AVxWorkerStatus new_status) {
Yaowu Xuc27fc142016-08-22 16:08:15 -070057 // No-op when attempting to change state on a thread that didn't come up.
58 // Checking status_ without acquiring the lock first would result in a data
59 // race.
60 if (worker->impl_ == NULL) return;
61
62 pthread_mutex_lock(&worker->impl_->mutex_);
63 if (worker->status_ >= OK) {
64 // wait for the worker to finish
65 while (worker->status_ != OK) {
66 pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
67 }
68 // assign new status and release the working thread if needed
69 if (new_status != OK) {
70 worker->status_ = new_status;
71 pthread_cond_signal(&worker->impl_->condition_);
72 }
73 }
74 pthread_mutex_unlock(&worker->impl_->mutex_);
75}
76
77#endif // CONFIG_MULTITHREAD
78
79//------------------------------------------------------------------------------
80
Yaowu Xuf883b422016-08-30 14:01:10 -070081static void init(AVxWorker *const worker) {
Yaowu Xuc27fc142016-08-22 16:08:15 -070082 memset(worker, 0, sizeof(*worker));
83 worker->status_ = NOT_OK;
84}
85
Yaowu Xuf883b422016-08-30 14:01:10 -070086static int sync(AVxWorker *const worker) {
Yaowu Xuc27fc142016-08-22 16:08:15 -070087#if CONFIG_MULTITHREAD
88 change_state(worker, OK);
89#endif
90 assert(worker->status_ <= OK);
91 return !worker->had_error;
92}
93
Yaowu Xuf883b422016-08-30 14:01:10 -070094static int reset(AVxWorker *const worker) {
Yaowu Xuc27fc142016-08-22 16:08:15 -070095 int ok = 1;
96 worker->had_error = 0;
97 if (worker->status_ < OK) {
98#if CONFIG_MULTITHREAD
Yaowu Xuf883b422016-08-30 14:01:10 -070099 worker->impl_ = (AVxWorkerImpl *)aom_calloc(1, sizeof(*worker->impl_));
Yaowu Xuc27fc142016-08-22 16:08:15 -0700100 if (worker->impl_ == NULL) {
101 return 0;
102 }
103 if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) {
104 goto Error;
105 }
106 if (pthread_cond_init(&worker->impl_->condition_, NULL)) {
107 pthread_mutex_destroy(&worker->impl_->mutex_);
108 goto Error;
109 }
110 pthread_mutex_lock(&worker->impl_->mutex_);
111 ok = !pthread_create(&worker->impl_->thread_, NULL, thread_loop, worker);
112 if (ok) worker->status_ = OK;
113 pthread_mutex_unlock(&worker->impl_->mutex_);
114 if (!ok) {
115 pthread_mutex_destroy(&worker->impl_->mutex_);
116 pthread_cond_destroy(&worker->impl_->condition_);
117 Error:
Yaowu Xuf883b422016-08-30 14:01:10 -0700118 aom_free(worker->impl_);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700119 worker->impl_ = NULL;
120 return 0;
121 }
122#else
123 worker->status_ = OK;
124#endif
125 } else if (worker->status_ > OK) {
126 ok = sync(worker);
127 }
128 assert(!ok || (worker->status_ == OK));
129 return ok;
130}
131
Yaowu Xuf883b422016-08-30 14:01:10 -0700132static void execute(AVxWorker *const worker) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700133 if (worker->hook != NULL) {
134 worker->had_error |= !worker->hook(worker->data1, worker->data2);
135 }
136}
137
Yaowu Xuf883b422016-08-30 14:01:10 -0700138static void launch(AVxWorker *const worker) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700139#if CONFIG_MULTITHREAD
140 change_state(worker, WORK);
141#else
142 execute(worker);
143#endif
144}
145
Yaowu Xuf883b422016-08-30 14:01:10 -0700146static void end(AVxWorker *const worker) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700147#if CONFIG_MULTITHREAD
148 if (worker->impl_ != NULL) {
149 change_state(worker, NOT_OK);
150 pthread_join(worker->impl_->thread_, NULL);
151 pthread_mutex_destroy(&worker->impl_->mutex_);
152 pthread_cond_destroy(&worker->impl_->condition_);
Yaowu Xuf883b422016-08-30 14:01:10 -0700153 aom_free(worker->impl_);
Yaowu Xuc27fc142016-08-22 16:08:15 -0700154 worker->impl_ = NULL;
155 }
156#else
157 worker->status_ = NOT_OK;
158 assert(worker->impl_ == NULL);
159#endif
160 assert(worker->status_ == NOT_OK);
161}
162
163//------------------------------------------------------------------------------
164
Yaowu Xuf883b422016-08-30 14:01:10 -0700165static AVxWorkerInterface g_worker_interface = { init, reset, sync,
Yaowu Xuc27fc142016-08-22 16:08:15 -0700166 launch, execute, end };
167
Yaowu Xuf883b422016-08-30 14:01:10 -0700168int aom_set_worker_interface(const AVxWorkerInterface *const winterface) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700169 if (winterface == NULL || winterface->init == NULL ||
170 winterface->reset == NULL || winterface->sync == NULL ||
171 winterface->launch == NULL || winterface->execute == NULL ||
172 winterface->end == NULL) {
173 return 0;
174 }
175 g_worker_interface = *winterface;
176 return 1;
177}
178
Yaowu Xuf883b422016-08-30 14:01:10 -0700179const AVxWorkerInterface *aom_get_worker_interface(void) {
Yaowu Xuc27fc142016-08-22 16:08:15 -0700180 return &g_worker_interface;
181}
182
183//------------------------------------------------------------------------------