OLD | NEW |
1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 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 | 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 | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 // | 9 // |
10 // Multi-threaded worker | 10 // Multi-threaded worker |
11 // | 11 // |
12 // Author: Skal (pascal.massimino@gmail.com) | 12 // Author: Skal (pascal.massimino@gmail.com) |
13 | 13 |
14 #include <assert.h> | 14 #include <assert.h> |
15 #include <string.h> // for memset() | 15 #include <string.h> // for memset() |
16 #include "./thread.h" | 16 #include "./thread.h" |
17 | 17 |
18 #if defined(__cplusplus) || defined(c_plusplus) | |
19 extern "C" { | |
20 #endif | |
21 | |
22 #ifdef WEBP_USE_THREAD | 18 #ifdef WEBP_USE_THREAD |
23 | 19 |
24 #if defined(_WIN32) | 20 #if defined(_WIN32) |
25 | 21 |
26 //------------------------------------------------------------------------------ | 22 //------------------------------------------------------------------------------ |
27 // simplistic pthread emulation layer | 23 // simplistic pthread emulation layer |
28 | 24 |
29 #include <process.h> | 25 #include <process.h> |
30 | 26 |
31 // _beginthreadex requires __stdcall | 27 // _beginthreadex requires __stdcall |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 return 1; | 115 return 1; |
120 // now unlock the mutex so pthread_cond_signal may be issued | 116 // now unlock the mutex so pthread_cond_signal may be issued |
121 pthread_mutex_unlock(mutex); | 117 pthread_mutex_unlock(mutex); |
122 ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == | 118 ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == |
123 WAIT_OBJECT_0); | 119 WAIT_OBJECT_0); |
124 ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); | 120 ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); |
125 pthread_mutex_lock(mutex); | 121 pthread_mutex_lock(mutex); |
126 return !ok; | 122 return !ok; |
127 } | 123 } |
128 | 124 |
129 #else // _WIN32 | 125 #else // !_WIN32 |
130 # define THREADFN void* | 126 # define THREADFN void* |
131 # define THREAD_RETURN(val) val | 127 # define THREAD_RETURN(val) val |
132 #endif | 128 #endif // _WIN32 |
133 | 129 |
134 //------------------------------------------------------------------------------ | 130 //------------------------------------------------------------------------------ |
135 | 131 |
136 static THREADFN WebPWorkerThreadLoop(void *ptr) { // thread loop | 132 static THREADFN ThreadLoop(void* ptr) { |
137 WebPWorker* const worker = (WebPWorker*)ptr; | 133 WebPWorker* const worker = (WebPWorker*)ptr; |
138 int done = 0; | 134 int done = 0; |
139 while (!done) { | 135 while (!done) { |
140 pthread_mutex_lock(&worker->mutex_); | 136 pthread_mutex_lock(&worker->mutex_); |
141 while (worker->status_ == OK) { // wait in idling mode | 137 while (worker->status_ == OK) { // wait in idling mode |
142 pthread_cond_wait(&worker->condition_, &worker->mutex_); | 138 pthread_cond_wait(&worker->condition_, &worker->mutex_); |
143 } | 139 } |
144 if (worker->status_ == WORK) { | 140 if (worker->status_ == WORK) { |
145 if (worker->hook) { | 141 WebPWorkerExecute(worker); |
146 worker->had_error |= !worker->hook(worker->data1, worker->data2); | |
147 } | |
148 worker->status_ = OK; | 142 worker->status_ = OK; |
149 } else if (worker->status_ == NOT_OK) { // finish the worker | 143 } else if (worker->status_ == NOT_OK) { // finish the worker |
150 done = 1; | 144 done = 1; |
151 } | 145 } |
152 // signal to the main thread that we're done (for Sync()) | 146 // signal to the main thread that we're done (for Sync()) |
153 pthread_cond_signal(&worker->condition_); | 147 pthread_cond_signal(&worker->condition_); |
154 pthread_mutex_unlock(&worker->mutex_); | 148 pthread_mutex_unlock(&worker->mutex_); |
155 } | 149 } |
156 return THREAD_RETURN(NULL); // Thread is finished | 150 return THREAD_RETURN(NULL); // Thread is finished |
157 } | 151 } |
158 | 152 |
159 // main thread state control | 153 // main thread state control |
160 static void WebPWorkerChangeState(WebPWorker* const worker, | 154 static void ChangeState(WebPWorker* const worker, |
161 WebPWorkerStatus new_status) { | 155 WebPWorkerStatus new_status) { |
162 // no-op when attempting to change state on a thread that didn't come up | 156 // no-op when attempting to change state on a thread that didn't come up |
163 if (worker->status_ < OK) return; | 157 if (worker->status_ < OK) return; |
164 | 158 |
165 pthread_mutex_lock(&worker->mutex_); | 159 pthread_mutex_lock(&worker->mutex_); |
166 // wait for the worker to finish | 160 // wait for the worker to finish |
167 while (worker->status_ != OK) { | 161 while (worker->status_ != OK) { |
168 pthread_cond_wait(&worker->condition_, &worker->mutex_); | 162 pthread_cond_wait(&worker->condition_, &worker->mutex_); |
169 } | 163 } |
170 // assign new status and release the working thread if needed | 164 // assign new status and release the working thread if needed |
171 if (new_status != OK) { | 165 if (new_status != OK) { |
172 worker->status_ = new_status; | 166 worker->status_ = new_status; |
173 pthread_cond_signal(&worker->condition_); | 167 pthread_cond_signal(&worker->condition_); |
174 } | 168 } |
175 pthread_mutex_unlock(&worker->mutex_); | 169 pthread_mutex_unlock(&worker->mutex_); |
176 } | 170 } |
177 | 171 |
178 #endif | 172 #endif // WEBP_USE_THREAD |
179 | 173 |
180 //------------------------------------------------------------------------------ | 174 //------------------------------------------------------------------------------ |
181 | 175 |
182 void WebPWorkerInit(WebPWorker* const worker) { | 176 void WebPWorkerInit(WebPWorker* const worker) { |
183 memset(worker, 0, sizeof(*worker)); | 177 memset(worker, 0, sizeof(*worker)); |
184 worker->status_ = NOT_OK; | 178 worker->status_ = NOT_OK; |
185 } | 179 } |
186 | 180 |
187 int WebPWorkerSync(WebPWorker* const worker) { | 181 int WebPWorkerSync(WebPWorker* const worker) { |
188 #ifdef WEBP_USE_THREAD | 182 #ifdef WEBP_USE_THREAD |
189 WebPWorkerChangeState(worker, OK); | 183 ChangeState(worker, OK); |
190 #endif | 184 #endif |
191 assert(worker->status_ <= OK); | 185 assert(worker->status_ <= OK); |
192 return !worker->had_error; | 186 return !worker->had_error; |
193 } | 187 } |
194 | 188 |
195 int WebPWorkerReset(WebPWorker* const worker) { | 189 int WebPWorkerReset(WebPWorker* const worker) { |
196 int ok = 1; | 190 int ok = 1; |
197 worker->had_error = 0; | 191 worker->had_error = 0; |
198 if (worker->status_ < OK) { | 192 if (worker->status_ < OK) { |
199 #ifdef WEBP_USE_THREAD | 193 #ifdef WEBP_USE_THREAD |
200 if (pthread_mutex_init(&worker->mutex_, NULL) || | 194 if (pthread_mutex_init(&worker->mutex_, NULL) || |
201 pthread_cond_init(&worker->condition_, NULL)) { | 195 pthread_cond_init(&worker->condition_, NULL)) { |
202 return 0; | 196 return 0; |
203 } | 197 } |
204 pthread_mutex_lock(&worker->mutex_); | 198 pthread_mutex_lock(&worker->mutex_); |
205 ok = !pthread_create(&worker->thread_, NULL, WebPWorkerThreadLoop, worker); | 199 ok = !pthread_create(&worker->thread_, NULL, ThreadLoop, worker); |
206 if (ok) worker->status_ = OK; | 200 if (ok) worker->status_ = OK; |
207 pthread_mutex_unlock(&worker->mutex_); | 201 pthread_mutex_unlock(&worker->mutex_); |
208 #else | 202 #else |
209 worker->status_ = OK; | 203 worker->status_ = OK; |
210 #endif | 204 #endif |
211 } else if (worker->status_ > OK) { | 205 } else if (worker->status_ > OK) { |
212 ok = WebPWorkerSync(worker); | 206 ok = WebPWorkerSync(worker); |
213 } | 207 } |
214 assert(!ok || (worker->status_ == OK)); | 208 assert(!ok || (worker->status_ == OK)); |
215 return ok; | 209 return ok; |
216 } | 210 } |
217 | 211 |
| 212 void WebPWorkerExecute(WebPWorker* const worker) { |
| 213 if (worker->hook != NULL) { |
| 214 worker->had_error |= !worker->hook(worker->data1, worker->data2); |
| 215 } |
| 216 } |
| 217 |
218 void WebPWorkerLaunch(WebPWorker* const worker) { | 218 void WebPWorkerLaunch(WebPWorker* const worker) { |
219 #ifdef WEBP_USE_THREAD | 219 #ifdef WEBP_USE_THREAD |
220 WebPWorkerChangeState(worker, WORK); | 220 ChangeState(worker, WORK); |
221 #else | 221 #else |
222 if (worker->hook) | 222 WebPWorkerExecute(worker); |
223 worker->had_error |= !worker->hook(worker->data1, worker->data2); | |
224 #endif | 223 #endif |
225 } | 224 } |
226 | 225 |
227 void WebPWorkerEnd(WebPWorker* const worker) { | 226 void WebPWorkerEnd(WebPWorker* const worker) { |
228 if (worker->status_ >= OK) { | 227 if (worker->status_ >= OK) { |
229 #ifdef WEBP_USE_THREAD | 228 #ifdef WEBP_USE_THREAD |
230 WebPWorkerChangeState(worker, NOT_OK); | 229 ChangeState(worker, NOT_OK); |
231 pthread_join(worker->thread_, NULL); | 230 pthread_join(worker->thread_, NULL); |
232 pthread_mutex_destroy(&worker->mutex_); | 231 pthread_mutex_destroy(&worker->mutex_); |
233 pthread_cond_destroy(&worker->condition_); | 232 pthread_cond_destroy(&worker->condition_); |
234 #else | 233 #else |
235 worker->status_ = NOT_OK; | 234 worker->status_ = NOT_OK; |
236 #endif | 235 #endif |
237 } | 236 } |
238 assert(worker->status_ == NOT_OK); | 237 assert(worker->status_ == NOT_OK); |
239 } | 238 } |
240 | 239 |
241 //------------------------------------------------------------------------------ | 240 //------------------------------------------------------------------------------ |
242 | 241 |
243 #if defined(__cplusplus) || defined(c_plusplus) | |
244 } // extern "C" | |
245 #endif | |
OLD | NEW |