| 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 |