15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2011 Google Inc. All Rights Reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// that can be found in the COPYING file in the root of the source 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// tree. An additional intellectual property rights grant can be found 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// in the file PATENTS. All contributing project authors may 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// be found in the AUTHORS file in the root of the source tree. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Multi-threaded worker 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Skal (pascal.massimino@gmail.com) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> // for memset() 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "./thread.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "./utils.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WEBP_USE_THREAD 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(_WIN32) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <windows.h> 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)typedef HANDLE pthread_t; 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)typedef CRITICAL_SECTION pthread_mutex_t; 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)typedef struct { 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HANDLE waiting_sem_; 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HANDLE received_sem_; 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) HANDLE signal_event_; 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} pthread_cond_t; 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#else // !_WIN32 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <pthread.h> 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif // _WIN32 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)struct WebPWorkerImpl { 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_t mutex_; 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_cond_t condition_; 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_t thread_; 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if defined(_WIN32) 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------ 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// simplistic pthread emulation layer 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <process.h> 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// _beginthreadex requires __stdcall 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define THREADFN unsigned int __stdcall 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_create(pthread_t* const thread, const void* attr, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int (__stdcall *start)(void*), void* arg) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void)attr; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *thread = (pthread_t)_beginthreadex(NULL, /* void *security */ 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* unsigned stack_size */ 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arg, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, /* unsigned initflag */ 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); /* unsigned *thrdaddr */ 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*thread == NULL) return 1; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_join(pthread_t thread, void** value_ptr) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void)value_ptr; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 || 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CloseHandle(thread) == 0); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mutex 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void)mutexattr; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeCriticalSection(mutex); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_lock(pthread_mutex_t* const mutex) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnterCriticalSection(mutex); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_unlock(pthread_mutex_t* const mutex) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LeaveCriticalSection(mutex); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_mutex_destroy(pthread_mutex_t* const mutex) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteCriticalSection(mutex); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Condition 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_destroy(pthread_cond_t* const condition) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ok = 1; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok &= (CloseHandle(condition->waiting_sem_) != 0); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok &= (CloseHandle(condition->received_sem_) != 0); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok &= (CloseHandle(condition->signal_event_) != 0); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !ok; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (void)cond_attr; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (condition->waiting_sem_ == NULL || 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition->received_sem_ == NULL || 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) condition->signal_event_ == NULL) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_cond_destroy(condition); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_signal(pthread_cond_t* const condition) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ok = 1; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a thread is waiting in pthread_cond_wait: allow it to be notified 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = SetEvent(condition->signal_event_); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // wait until the event is consumed so the signaler cannot consume 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the event via its own pthread_cond_wait. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) != 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WAIT_OBJECT_0); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !ok; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int pthread_cond_wait(pthread_cond_t* const condition, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_mutex_t* const mutex) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ok; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // note that there is a consumer available so the signal isn't dropped in 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pthread_cond_signal 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // now unlock the mutex so pthread_cond_signal may be issued 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_mutex_unlock(mutex); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = (WaitForSingleObject(condition->signal_event_, INFINITE) == 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WAIT_OBJECT_0); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_mutex_lock(mutex); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !ok; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else // !_WIN32 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define THREADFN void* 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define THREAD_RETURN(val) val 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif // _WIN32 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------ 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void Execute(WebPWorker* const worker); // Forward declaration. 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static THREADFN ThreadLoop(void* ptr) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebPWorker* const worker = (WebPWorker*)ptr; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int done = 0; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!done) { 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_lock(&worker->impl_->mutex_); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (worker->status_ == OK) { // wait in idling mode 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (worker->status_ == WORK) { 1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Execute(worker); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) worker->status_ = OK; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (worker->status_ == NOT_OK) { // finish the worker 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done = 1; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // signal to the main thread that we're done (for Sync()) 1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_cond_signal(&worker->impl_->condition_); 1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_unlock(&worker->impl_->mutex_); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return THREAD_RETURN(NULL); // Thread is finished 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// main thread state control 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static void ChangeState(WebPWorker* const worker, 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) WebPWorkerStatus new_status) { 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // No-op when attempting to change state on a thread that didn't come up. 1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Checking status_ without acquiring the lock first would result in a data 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // race. 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (worker->impl_ == NULL) return; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_lock(&worker->impl_->mutex_); 1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (worker->status_ >= OK) { 1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // wait for the worker to finish 1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (worker->status_ != OK) { 1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_); 1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // assign new status and release the working thread if needed 1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (new_status != OK) { 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) worker->status_ = new_status; 1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_cond_signal(&worker->impl_->condition_); 1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_unlock(&worker->impl_->mutex_); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif // WEBP_USE_THREAD 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------ 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void Init(WebPWorker* const worker) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(worker, 0, sizeof(*worker)); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) worker->status_ = NOT_OK; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static int Sync(WebPWorker* const worker) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WEBP_USE_THREAD 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ChangeState(worker, OK); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(worker->status_ <= OK); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !worker->had_error; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static int Reset(WebPWorker* const worker) { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ok = 1; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) worker->had_error = 0; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (worker->status_ < OK) { 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WEBP_USE_THREAD 2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) worker->impl_ = (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(*worker->impl_)); 2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (worker->impl_ == NULL) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) { 2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) goto Error; 2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (pthread_cond_init(&worker->impl_->condition_, NULL)) { 2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_destroy(&worker->impl_->mutex_); 2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) goto Error; 2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_lock(&worker->impl_->mutex_); 2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ok = !pthread_create(&worker->impl_->thread_, NULL, ThreadLoop, worker); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ok) worker->status_ = OK; 2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_unlock(&worker->impl_->mutex_); 2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!ok) { 2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_destroy(&worker->impl_->mutex_); 2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_cond_destroy(&worker->impl_->condition_); 2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Error: 2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(worker->impl_); 2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) worker->impl_ = NULL; 2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 0; 2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) worker->status_ = OK; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (worker->status_ > OK) { 2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ok = Sync(worker); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(!ok || (worker->status_ == OK)); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void Execute(WebPWorker* const worker) { 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (worker->hook != NULL) { 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) worker->had_error |= !worker->hook(worker->data1, worker->data2); 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void Launch(WebPWorker* const worker) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WEBP_USE_THREAD 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ChangeState(worker, WORK); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Execute(worker); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static void End(WebPWorker* const worker) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WEBP_USE_THREAD 2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (worker->impl_ != NULL) { 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ChangeState(worker, NOT_OK); 2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_join(worker->impl_->thread_, NULL); 2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_mutex_destroy(&worker->impl_->mutex_); 2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) pthread_cond_destroy(&worker->impl_->condition_); 2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) WebPSafeFree(worker->impl_); 2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) worker->impl_ = NULL; 2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) worker->status_ = NOT_OK; 2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) assert(worker->impl_ == NULL); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(worker->status_ == NOT_OK); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------ 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static WebPWorkerInterface g_worker_interface = { 2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Init, Reset, Sync, Launch, Execute, End 2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int WebPSetWorkerInterface(const WebPWorkerInterface* const winterface) { 2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (winterface == NULL || 2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) winterface->Init == NULL || winterface->Reset == NULL || 2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) winterface->Sync == NULL || winterface->Launch == NULL || 2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) winterface->Execute == NULL || winterface->End == NULL) { 2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 0; 3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) g_worker_interface = *winterface; 3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 1; 3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const WebPWorkerInterface* WebPGetWorkerInterface(void) { 3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return &g_worker_interface; 3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//------------------------------------------------------------------------------ 310