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