Line data Source code
1 : /*
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 : */
11 : //
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()
19 : #include "./aom_thread.h"
20 : #include "aom_mem/aom_mem.h"
21 :
22 : #if CONFIG_MULTITHREAD
23 :
24 : struct AVxWorkerImpl {
25 : pthread_mutex_t mutex_;
26 : pthread_cond_t condition_;
27 : pthread_t thread_;
28 : };
29 :
30 : //------------------------------------------------------------------------------
31 :
32 : static void execute(AVxWorker *const worker); // Forward declaration.
33 :
34 0 : static THREADFN thread_loop(void *ptr) {
35 0 : AVxWorker *const worker = (AVxWorker *)ptr;
36 0 : int done = 0;
37 0 : while (!done) {
38 0 : pthread_mutex_lock(&worker->impl_->mutex_);
39 0 : while (worker->status_ == OK) { // wait in idling mode
40 0 : pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
41 : }
42 0 : if (worker->status_ == WORK) {
43 0 : execute(worker);
44 0 : worker->status_ = OK;
45 0 : } else if (worker->status_ == NOT_OK) { // finish the worker
46 0 : done = 1;
47 : }
48 : // signal to the main thread that we're done (for sync())
49 0 : pthread_cond_signal(&worker->impl_->condition_);
50 0 : pthread_mutex_unlock(&worker->impl_->mutex_);
51 : }
52 0 : return THREAD_RETURN(NULL); // Thread is finished
53 : }
54 :
55 : // main thread state control
56 0 : static void change_state(AVxWorker *const worker, AVxWorkerStatus new_status) {
57 : // 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 0 : if (worker->impl_ == NULL) return;
61 :
62 0 : pthread_mutex_lock(&worker->impl_->mutex_);
63 0 : if (worker->status_ >= OK) {
64 : // wait for the worker to finish
65 0 : while (worker->status_ != OK) {
66 0 : pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
67 : }
68 : // assign new status and release the working thread if needed
69 0 : if (new_status != OK) {
70 0 : worker->status_ = new_status;
71 0 : pthread_cond_signal(&worker->impl_->condition_);
72 : }
73 : }
74 0 : pthread_mutex_unlock(&worker->impl_->mutex_);
75 : }
76 :
77 : #endif // CONFIG_MULTITHREAD
78 :
79 : //------------------------------------------------------------------------------
80 :
81 0 : static void init(AVxWorker *const worker) {
82 0 : memset(worker, 0, sizeof(*worker));
83 0 : worker->status_ = NOT_OK;
84 0 : }
85 :
86 0 : static int sync(AVxWorker *const worker) {
87 : #if CONFIG_MULTITHREAD
88 0 : change_state(worker, OK);
89 : #endif
90 0 : assert(worker->status_ <= OK);
91 0 : return !worker->had_error;
92 : }
93 :
94 0 : static int reset(AVxWorker *const worker) {
95 0 : int ok = 1;
96 0 : worker->had_error = 0;
97 0 : if (worker->status_ < OK) {
98 : #if CONFIG_MULTITHREAD
99 0 : worker->impl_ = (AVxWorkerImpl *)aom_calloc(1, sizeof(*worker->impl_));
100 0 : if (worker->impl_ == NULL) {
101 0 : return 0;
102 : }
103 0 : if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) {
104 0 : goto Error;
105 : }
106 0 : if (pthread_cond_init(&worker->impl_->condition_, NULL)) {
107 0 : pthread_mutex_destroy(&worker->impl_->mutex_);
108 0 : goto Error;
109 : }
110 0 : pthread_mutex_lock(&worker->impl_->mutex_);
111 0 : ok = !pthread_create(&worker->impl_->thread_, NULL, thread_loop, worker);
112 0 : if (ok) worker->status_ = OK;
113 0 : pthread_mutex_unlock(&worker->impl_->mutex_);
114 0 : if (!ok) {
115 0 : pthread_mutex_destroy(&worker->impl_->mutex_);
116 0 : pthread_cond_destroy(&worker->impl_->condition_);
117 : Error:
118 0 : aom_free(worker->impl_);
119 0 : worker->impl_ = NULL;
120 0 : return 0;
121 : }
122 : #else
123 : worker->status_ = OK;
124 : #endif
125 0 : } else if (worker->status_ > OK) {
126 0 : ok = sync(worker);
127 : }
128 0 : assert(!ok || (worker->status_ == OK));
129 0 : return ok;
130 : }
131 :
132 0 : static void execute(AVxWorker *const worker) {
133 0 : if (worker->hook != NULL) {
134 0 : worker->had_error |= !worker->hook(worker->data1, worker->data2);
135 : }
136 0 : }
137 :
138 0 : static void launch(AVxWorker *const worker) {
139 : #if CONFIG_MULTITHREAD
140 0 : change_state(worker, WORK);
141 : #else
142 : execute(worker);
143 : #endif
144 0 : }
145 :
146 0 : static void end(AVxWorker *const worker) {
147 : #if CONFIG_MULTITHREAD
148 0 : if (worker->impl_ != NULL) {
149 0 : change_state(worker, NOT_OK);
150 0 : pthread_join(worker->impl_->thread_, NULL);
151 0 : pthread_mutex_destroy(&worker->impl_->mutex_);
152 0 : pthread_cond_destroy(&worker->impl_->condition_);
153 0 : aom_free(worker->impl_);
154 0 : worker->impl_ = NULL;
155 : }
156 : #else
157 : worker->status_ = NOT_OK;
158 : assert(worker->impl_ == NULL);
159 : #endif
160 0 : assert(worker->status_ == NOT_OK);
161 0 : }
162 :
163 : //------------------------------------------------------------------------------
164 :
165 : static AVxWorkerInterface g_worker_interface = { init, reset, sync,
166 : launch, execute, end };
167 :
168 0 : int aom_set_worker_interface(const AVxWorkerInterface *const winterface) {
169 0 : if (winterface == NULL || winterface->init == NULL ||
170 0 : winterface->reset == NULL || winterface->sync == NULL ||
171 0 : winterface->launch == NULL || winterface->execute == NULL ||
172 0 : winterface->end == NULL) {
173 0 : return 0;
174 : }
175 0 : g_worker_interface = *winterface;
176 0 : return 1;
177 : }
178 :
179 0 : const AVxWorkerInterface *aom_get_worker_interface(void) {
180 0 : return &g_worker_interface;
181 : }
182 :
183 : //------------------------------------------------------------------------------
|