OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 Google Inc. All Rights Reserved. |
| 2 // |
| 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 |
| 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 // ----------------------------------------------------------------------------- |
| 9 // |
| 10 // Multi-threaded worker |
| 11 // |
| 12 // Original source: |
| 13 // http://git.chromium.org/webm/libwebp.git |
| 14 // 100644 blob eff8f2a8c20095aade3c292b0e9292dac6cb3587 src/utils/thread.c |
| 15 |
| 16 |
| 17 #include <assert.h> |
| 18 #include <string.h> // for memset() |
| 19 #include "./vp9_thread.h" |
| 20 |
| 21 #if defined(__cplusplus) || defined(c_plusplus) |
| 22 extern "C" { |
| 23 #endif |
| 24 |
| 25 #if CONFIG_MULTITHREAD |
| 26 |
| 27 #if defined(_WIN32) |
| 28 |
| 29 //------------------------------------------------------------------------------ |
| 30 // simplistic pthread emulation layer |
| 31 |
| 32 #include <process.h> |
| 33 |
| 34 // _beginthreadex requires __stdcall |
| 35 #define THREADFN unsigned int __stdcall |
| 36 #define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val) |
| 37 |
| 38 static int pthread_create(pthread_t* const thread, const void* attr, |
| 39 unsigned int (__stdcall *start)(void*), void* arg) { |
| 40 (void)attr; |
| 41 *thread = (pthread_t)_beginthreadex(NULL, /* void *security */ |
| 42 0, /* unsigned stack_size */ |
| 43 start, |
| 44 arg, |
| 45 0, /* unsigned initflag */ |
| 46 NULL); /* unsigned *thrdaddr */ |
| 47 if (*thread == NULL) return 1; |
| 48 SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL); |
| 49 return 0; |
| 50 } |
| 51 |
| 52 static int pthread_join(pthread_t thread, void** value_ptr) { |
| 53 (void)value_ptr; |
| 54 return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 || |
| 55 CloseHandle(thread) == 0); |
| 56 } |
| 57 |
| 58 // Mutex |
| 59 static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) { |
| 60 (void)mutexattr; |
| 61 InitializeCriticalSection(mutex); |
| 62 return 0; |
| 63 } |
| 64 |
| 65 static int pthread_mutex_lock(pthread_mutex_t* const mutex) { |
| 66 EnterCriticalSection(mutex); |
| 67 return 0; |
| 68 } |
| 69 |
| 70 static int pthread_mutex_unlock(pthread_mutex_t* const mutex) { |
| 71 LeaveCriticalSection(mutex); |
| 72 return 0; |
| 73 } |
| 74 |
| 75 static int pthread_mutex_destroy(pthread_mutex_t* const mutex) { |
| 76 DeleteCriticalSection(mutex); |
| 77 return 0; |
| 78 } |
| 79 |
| 80 // Condition |
| 81 static int pthread_cond_destroy(pthread_cond_t* const condition) { |
| 82 int ok = 1; |
| 83 ok &= (CloseHandle(condition->waiting_sem_) != 0); |
| 84 ok &= (CloseHandle(condition->received_sem_) != 0); |
| 85 ok &= (CloseHandle(condition->signal_event_) != 0); |
| 86 return !ok; |
| 87 } |
| 88 |
| 89 static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) { |
| 90 (void)cond_attr; |
| 91 condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL); |
| 92 condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL); |
| 93 condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); |
| 94 if (condition->waiting_sem_ == NULL || |
| 95 condition->received_sem_ == NULL || |
| 96 condition->signal_event_ == NULL) { |
| 97 pthread_cond_destroy(condition); |
| 98 return 1; |
| 99 } |
| 100 return 0; |
| 101 } |
| 102 |
| 103 static int pthread_cond_signal(pthread_cond_t* const condition) { |
| 104 int ok = 1; |
| 105 if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { |
| 106 // a thread is waiting in pthread_cond_wait: allow it to be notified |
| 107 ok = SetEvent(condition->signal_event_); |
| 108 // wait until the event is consumed so the signaler cannot consume |
| 109 // the event via its own pthread_cond_wait. |
| 110 ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != |
| 111 WAIT_OBJECT_0); |
| 112 } |
| 113 return !ok; |
| 114 } |
| 115 |
| 116 static int pthread_cond_wait(pthread_cond_t* const condition, |
| 117 pthread_mutex_t* const mutex) { |
| 118 int ok; |
| 119 // note that there is a consumer available so the signal isn't dropped in |
| 120 // pthread_cond_signal |
| 121 if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) |
| 122 return 1; |
| 123 // now unlock the mutex so pthread_cond_signal may be issued |
| 124 pthread_mutex_unlock(mutex); |
| 125 ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == |
| 126 WAIT_OBJECT_0); |
| 127 ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); |
| 128 pthread_mutex_lock(mutex); |
| 129 return !ok; |
| 130 } |
| 131 |
| 132 #else // _WIN32 |
| 133 # define THREADFN void* |
| 134 # define THREAD_RETURN(val) val |
| 135 #endif |
| 136 |
| 137 //------------------------------------------------------------------------------ |
| 138 |
| 139 static THREADFN thread_loop(void *ptr) { // thread loop |
| 140 VP9Worker* const worker = (VP9Worker*)ptr; |
| 141 int done = 0; |
| 142 while (!done) { |
| 143 pthread_mutex_lock(&worker->mutex_); |
| 144 while (worker->status_ == OK) { // wait in idling mode |
| 145 pthread_cond_wait(&worker->condition_, &worker->mutex_); |
| 146 } |
| 147 if (worker->status_ == WORK) { |
| 148 if (worker->hook) { |
| 149 worker->had_error |= !worker->hook(worker->data1, worker->data2); |
| 150 } |
| 151 worker->status_ = OK; |
| 152 } else if (worker->status_ == NOT_OK) { // finish the worker |
| 153 done = 1; |
| 154 } |
| 155 // signal to the main thread that we're done (for Sync()) |
| 156 pthread_cond_signal(&worker->condition_); |
| 157 pthread_mutex_unlock(&worker->mutex_); |
| 158 } |
| 159 return THREAD_RETURN(NULL); // Thread is finished |
| 160 } |
| 161 |
| 162 // main thread state control |
| 163 static void change_state(VP9Worker* const worker, |
| 164 VP9WorkerStatus new_status) { |
| 165 // no-op when attempting to change state on a thread that didn't come up |
| 166 if (worker->status_ < OK) return; |
| 167 |
| 168 pthread_mutex_lock(&worker->mutex_); |
| 169 // wait for the worker to finish |
| 170 while (worker->status_ != OK) { |
| 171 pthread_cond_wait(&worker->condition_, &worker->mutex_); |
| 172 } |
| 173 // assign new status and release the working thread if needed |
| 174 if (new_status != OK) { |
| 175 worker->status_ = new_status; |
| 176 pthread_cond_signal(&worker->condition_); |
| 177 } |
| 178 pthread_mutex_unlock(&worker->mutex_); |
| 179 } |
| 180 |
| 181 #endif |
| 182 |
| 183 //------------------------------------------------------------------------------ |
| 184 |
| 185 void vp9_worker_init(VP9Worker* const worker) { |
| 186 memset(worker, 0, sizeof(*worker)); |
| 187 worker->status_ = NOT_OK; |
| 188 } |
| 189 |
| 190 int vp9_worker_sync(VP9Worker* const worker) { |
| 191 #if CONFIG_MULTITHREAD |
| 192 change_state(worker, OK); |
| 193 #endif |
| 194 assert(worker->status_ <= OK); |
| 195 return !worker->had_error; |
| 196 } |
| 197 |
| 198 int vp9_worker_reset(VP9Worker* const worker) { |
| 199 int ok = 1; |
| 200 worker->had_error = 0; |
| 201 if (worker->status_ < OK) { |
| 202 #if CONFIG_MULTITHREAD |
| 203 if (pthread_mutex_init(&worker->mutex_, NULL) || |
| 204 pthread_cond_init(&worker->condition_, NULL)) { |
| 205 return 0; |
| 206 } |
| 207 pthread_mutex_lock(&worker->mutex_); |
| 208 ok = !pthread_create(&worker->thread_, NULL, thread_loop, worker); |
| 209 if (ok) worker->status_ = OK; |
| 210 pthread_mutex_unlock(&worker->mutex_); |
| 211 #else |
| 212 worker->status_ = OK; |
| 213 #endif |
| 214 } else if (worker->status_ > OK) { |
| 215 ok = vp9_worker_sync(worker); |
| 216 } |
| 217 assert(!ok || (worker->status_ == OK)); |
| 218 return ok; |
| 219 } |
| 220 |
| 221 void vp9_worker_launch(VP9Worker* const worker) { |
| 222 #if CONFIG_MULTITHREAD |
| 223 change_state(worker, WORK); |
| 224 #else |
| 225 if (worker->hook) |
| 226 worker->had_error |= !worker->hook(worker->data1, worker->data2); |
| 227 #endif |
| 228 } |
| 229 |
| 230 void vp9_worker_end(VP9Worker* const worker) { |
| 231 if (worker->status_ >= OK) { |
| 232 #if CONFIG_MULTITHREAD |
| 233 change_state(worker, NOT_OK); |
| 234 pthread_join(worker->thread_, NULL); |
| 235 pthread_mutex_destroy(&worker->mutex_); |
| 236 pthread_cond_destroy(&worker->condition_); |
| 237 #else |
| 238 worker->status_ = NOT_OK; |
| 239 #endif |
| 240 } |
| 241 assert(worker->status_ == NOT_OK); |
| 242 } |
| 243 |
| 244 //------------------------------------------------------------------------------ |
| 245 |
| 246 #if defined(__cplusplus) || defined(c_plusplus) |
| 247 } // extern "C" |
| 248 #endif |
OLD | NEW |