1f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Copyright 2013 Google Inc. All Rights Reserved.
2f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//
3f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Use of this source code is governed by a BSD-style license
4f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// that can be found in the COPYING file in the root of the source
5f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// tree. An additional intellectual property rights grant can be found
6f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// in the file PATENTS. All contributing project authors may
7f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// be found in the AUTHORS file in the root of the source tree.
8f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// -----------------------------------------------------------------------------
9f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//
10f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Multi-threaded worker
11f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//
12f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Original source:
137bc9febe8749e98a3812a0dc4380ceae75c29450Johann//  https://chromium.googlesource.com/webm/libwebp
14f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
157ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#ifndef VPX_THREAD_H_
167ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#define VPX_THREAD_H_
17f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include "./vpx_config.h"
19f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
202ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#ifdef __cplusplus
21f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangextern "C" {
22f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#endif
23f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
247ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian// Set maximum decode threads to be 8 due to the limit of frame buffers
257ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian// and not enough semaphores in the emulation layer on windows.
267ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#define MAX_DECODE_THREADS 8
277ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian
28f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#if CONFIG_MULTITHREAD
29f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
307ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#if defined(_WIN32) && !HAVE_PTHREAD_H
317bc9febe8749e98a3812a0dc4380ceae75c29450Johann#include <errno.h>    // NOLINT
322ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include <process.h>  // NOLINT
335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include <windows.h>  // NOLINT
34f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef HANDLE pthread_t;
35f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef CRITICAL_SECTION pthread_mutex_t;
367bc9febe8749e98a3812a0dc4380ceae75c29450Johann
377bc9febe8749e98a3812a0dc4380ceae75c29450Johann#if _WIN32_WINNT >= 0x0600  // Windows Vista / Server 2008 or greater
387bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define USE_WINDOWS_CONDITION_VARIABLE
397bc9febe8749e98a3812a0dc4380ceae75c29450Johanntypedef CONDITION_VARIABLE pthread_cond_t;
407bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
41f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef struct {
42f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  HANDLE waiting_sem_;
43f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  HANDLE received_sem_;
44f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang  HANDLE signal_event_;
45f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang} pthread_cond_t;
467bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif  // _WIN32_WINNT >= 0x600
477bc9febe8749e98a3812a0dc4380ceae75c29450Johann
487bc9febe8749e98a3812a0dc4380ceae75c29450Johann#ifndef WINAPI_FAMILY_PARTITION
497bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define WINAPI_PARTITION_DESKTOP 1
507bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define WINAPI_FAMILY_PARTITION(x) x
517bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
527bc9febe8749e98a3812a0dc4380ceae75c29450Johann
537bc9febe8749e98a3812a0dc4380ceae75c29450Johann#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
547bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define USE_CREATE_THREAD
557bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
56f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
572ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian//------------------------------------------------------------------------------
582ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian// simplistic pthread emulation layer
592ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
602ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian// _beginthreadex requires __stdcall
617bc9febe8749e98a3812a0dc4380ceae75c29450Johann#if defined(__GNUC__) && \
627bc9febe8749e98a3812a0dc4380ceae75c29450Johann    (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
637bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define THREADFN __attribute__((force_align_arg_pointer)) unsigned int __stdcall
647bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
652ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#define THREADFN unsigned int __stdcall
667bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
672ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
682ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
697bc9febe8749e98a3812a0dc4380ceae75c29450Johann#if _WIN32_WINNT >= 0x0501  // Windows XP or greater
707bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define WaitForSingleObject(obj, timeout) \
717bc9febe8749e98a3812a0dc4380ceae75c29450Johann  WaitForSingleObjectEx(obj, timeout, FALSE /*bAlertable*/)
727bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
737bc9febe8749e98a3812a0dc4380ceae75c29450Johann
747bc9febe8749e98a3812a0dc4380ceae75c29450Johannstatic INLINE int pthread_create(pthread_t *const thread, const void *attr,
757bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                 unsigned int(__stdcall *start)(void *),
767bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                 void *arg) {
772ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  (void)attr;
787bc9febe8749e98a3812a0dc4380ceae75c29450Johann#ifdef USE_CREATE_THREAD
797bc9febe8749e98a3812a0dc4380ceae75c29450Johann  *thread = CreateThread(NULL,          /* lpThreadAttributes */
807bc9febe8749e98a3812a0dc4380ceae75c29450Johann                         0,             /* dwStackSize */
817bc9febe8749e98a3812a0dc4380ceae75c29450Johann                         start, arg, 0, /* dwStackSize */
827bc9febe8749e98a3812a0dc4380ceae75c29450Johann                         NULL);         /* lpThreadId */
837bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
847bc9febe8749e98a3812a0dc4380ceae75c29450Johann  *thread = (pthread_t)_beginthreadex(NULL,          /* void *security */
857bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                      0,             /* unsigned stack_size */
867bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                      start, arg, 0, /* unsigned initflag */
877bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                      NULL);         /* unsigned *thrdaddr */
887bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
892ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  if (*thread == NULL) return 1;
902ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
912ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return 0;
922ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
932ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
947bc9febe8749e98a3812a0dc4380ceae75c29450Johannstatic INLINE int pthread_join(pthread_t thread, void **value_ptr) {
952ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  (void)value_ptr;
962ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 ||
972ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian          CloseHandle(thread) == 0);
982ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
992ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1002ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian// Mutex
1012ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_init(pthread_mutex_t *const mutex,
1027bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                     void *mutexattr) {
1032ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  (void)mutexattr;
1047bc9febe8749e98a3812a0dc4380ceae75c29450Johann#if _WIN32_WINNT >= 0x0600  // Windows Vista / Server 2008 or greater
1057bc9febe8749e98a3812a0dc4380ceae75c29450Johann  InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/);
1067bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
1072ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  InitializeCriticalSection(mutex);
1087bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
1092ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return 0;
1102ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1112ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1122ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_trylock(pthread_mutex_t *const mutex) {
1132ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return TryEnterCriticalSection(mutex) ? 0 : EBUSY;
1142ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1152ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1162ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_lock(pthread_mutex_t *const mutex) {
1172ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  EnterCriticalSection(mutex);
1182ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return 0;
1192ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1202ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1212ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_unlock(pthread_mutex_t *const mutex) {
1222ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  LeaveCriticalSection(mutex);
1232ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return 0;
1242ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1252ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1262ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_mutex_destroy(pthread_mutex_t *const mutex) {
1272ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  DeleteCriticalSection(mutex);
1282ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return 0;
1292ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1302ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1312ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian// Condition
1322ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_cond_destroy(pthread_cond_t *const condition) {
1332ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  int ok = 1;
1347bc9febe8749e98a3812a0dc4380ceae75c29450Johann#ifdef USE_WINDOWS_CONDITION_VARIABLE
1357bc9febe8749e98a3812a0dc4380ceae75c29450Johann  (void)condition;
1367bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
1372ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  ok &= (CloseHandle(condition->waiting_sem_) != 0);
1382ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  ok &= (CloseHandle(condition->received_sem_) != 0);
1392ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  ok &= (CloseHandle(condition->signal_event_) != 0);
1407bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
1412ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return !ok;
1422ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1432ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1442ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_cond_init(pthread_cond_t *const condition,
1457bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                    void *cond_attr) {
1462ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  (void)cond_attr;
1477bc9febe8749e98a3812a0dc4380ceae75c29450Johann#ifdef USE_WINDOWS_CONDITION_VARIABLE
1487bc9febe8749e98a3812a0dc4380ceae75c29450Johann  InitializeConditionVariable(condition);
1497bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
1507ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  condition->waiting_sem_ = CreateSemaphore(NULL, 0, MAX_DECODE_THREADS, NULL);
1517ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  condition->received_sem_ = CreateSemaphore(NULL, 0, MAX_DECODE_THREADS, NULL);
1522ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
1537bc9febe8749e98a3812a0dc4380ceae75c29450Johann  if (condition->waiting_sem_ == NULL || condition->received_sem_ == NULL ||
1542ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian      condition->signal_event_ == NULL) {
1552ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    pthread_cond_destroy(condition);
1562ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    return 1;
1572ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  }
1587bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
1592ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return 0;
1602ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1612ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1622ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_cond_signal(pthread_cond_t *const condition) {
1632ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  int ok = 1;
1647bc9febe8749e98a3812a0dc4380ceae75c29450Johann#ifdef USE_WINDOWS_CONDITION_VARIABLE
1657bc9febe8749e98a3812a0dc4380ceae75c29450Johann  WakeConditionVariable(condition);
1667bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
1672ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
1682ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    // a thread is waiting in pthread_cond_wait: allow it to be notified
1692ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    ok = SetEvent(condition->signal_event_);
1702ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    // wait until the event is consumed so the signaler cannot consume
1712ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    // the event via its own pthread_cond_wait.
1722ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian    ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
1732ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian           WAIT_OBJECT_0);
1742ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  }
1757bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
1762ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return !ok;
1772ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
1782ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian
1792ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianstatic INLINE int pthread_cond_wait(pthread_cond_t *const condition,
1802ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian                                    pthread_mutex_t *const mutex) {
1812ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  int ok;
1827bc9febe8749e98a3812a0dc4380ceae75c29450Johann#ifdef USE_WINDOWS_CONDITION_VARIABLE
1837bc9febe8749e98a3812a0dc4380ceae75c29450Johann  ok = SleepConditionVariableCS(condition, mutex, INFINITE);
1847bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else
1852ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  // note that there is a consumer available so the signal isn't dropped in
1862ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  // pthread_cond_signal
1877bc9febe8749e98a3812a0dc4380ceae75c29450Johann  if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL)) return 1;
1882ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  // now unlock the mutex so pthread_cond_signal may be issued
1892ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  pthread_mutex_unlock(mutex);
1902ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  ok = (WaitForSingleObject(condition->signal_event_, INFINITE) ==
1912ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian        WAIT_OBJECT_0);
1922ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
1932ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  pthread_mutex_lock(mutex);
1947bc9febe8749e98a3812a0dc4380ceae75c29450Johann#endif
1952ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian  return !ok;
1962ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian}
19768e1c830ade592be74773e249bf94e2bbfb50de7Johann#elif defined(__OS2__)
19868e1c830ade592be74773e249bf94e2bbfb50de7Johann#define INCL_DOS
1997bc9febe8749e98a3812a0dc4380ceae75c29450Johann#include <os2.h>  // NOLINT
20068e1c830ade592be74773e249bf94e2bbfb50de7Johann
2017bc9febe8749e98a3812a0dc4380ceae75c29450Johann#include <errno.h>        // NOLINT
2027bc9febe8749e98a3812a0dc4380ceae75c29450Johann#include <stdlib.h>       // NOLINT
2037bc9febe8749e98a3812a0dc4380ceae75c29450Johann#include <sys/builtin.h>  // NOLINT
20468e1c830ade592be74773e249bf94e2bbfb50de7Johann
20568e1c830ade592be74773e249bf94e2bbfb50de7Johann#define pthread_t TID
20668e1c830ade592be74773e249bf94e2bbfb50de7Johann#define pthread_mutex_t HMTX
20768e1c830ade592be74773e249bf94e2bbfb50de7Johann
20868e1c830ade592be74773e249bf94e2bbfb50de7Johanntypedef struct {
20968e1c830ade592be74773e249bf94e2bbfb50de7Johann  HEV event_sem_;
21068e1c830ade592be74773e249bf94e2bbfb50de7Johann  HEV ack_sem_;
21168e1c830ade592be74773e249bf94e2bbfb50de7Johann  volatile unsigned wait_count_;
21268e1c830ade592be74773e249bf94e2bbfb50de7Johann} pthread_cond_t;
21368e1c830ade592be74773e249bf94e2bbfb50de7Johann
21468e1c830ade592be74773e249bf94e2bbfb50de7Johann//------------------------------------------------------------------------------
21568e1c830ade592be74773e249bf94e2bbfb50de7Johann// simplistic pthread emulation layer
21668e1c830ade592be74773e249bf94e2bbfb50de7Johann
21768e1c830ade592be74773e249bf94e2bbfb50de7Johann#define THREADFN void *
21868e1c830ade592be74773e249bf94e2bbfb50de7Johann#define THREAD_RETURN(val) (val)
21968e1c830ade592be74773e249bf94e2bbfb50de7Johann
22068e1c830ade592be74773e249bf94e2bbfb50de7Johanntypedef struct {
2217bc9febe8749e98a3812a0dc4380ceae75c29450Johann  void *(*start_)(void *);
2227bc9febe8749e98a3812a0dc4380ceae75c29450Johann  void *arg_;
22368e1c830ade592be74773e249bf94e2bbfb50de7Johann} thread_arg;
22468e1c830ade592be74773e249bf94e2bbfb50de7Johann
2257bc9febe8749e98a3812a0dc4380ceae75c29450Johannstatic void thread_start(void *arg) {
22668e1c830ade592be74773e249bf94e2bbfb50de7Johann  thread_arg targ = *(thread_arg *)arg;
22768e1c830ade592be74773e249bf94e2bbfb50de7Johann  free(arg);
22868e1c830ade592be74773e249bf94e2bbfb50de7Johann
22968e1c830ade592be74773e249bf94e2bbfb50de7Johann  targ.start_(targ.arg_);
23068e1c830ade592be74773e249bf94e2bbfb50de7Johann}
23168e1c830ade592be74773e249bf94e2bbfb50de7Johann
2327bc9febe8749e98a3812a0dc4380ceae75c29450Johannstatic INLINE int pthread_create(pthread_t *const thread, const void *attr,
2337bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                 void *(*start)(void *), void *arg) {
23468e1c830ade592be74773e249bf94e2bbfb50de7Johann  int tid;
23568e1c830ade592be74773e249bf94e2bbfb50de7Johann  thread_arg *targ = (thread_arg *)malloc(sizeof(*targ));
23668e1c830ade592be74773e249bf94e2bbfb50de7Johann  if (targ == NULL) return 1;
23768e1c830ade592be74773e249bf94e2bbfb50de7Johann
23868e1c830ade592be74773e249bf94e2bbfb50de7Johann  (void)attr;
23968e1c830ade592be74773e249bf94e2bbfb50de7Johann
24068e1c830ade592be74773e249bf94e2bbfb50de7Johann  targ->start_ = start;
24168e1c830ade592be74773e249bf94e2bbfb50de7Johann  targ->arg_ = arg;
24268e1c830ade592be74773e249bf94e2bbfb50de7Johann  tid = (pthread_t)_beginthread(thread_start, NULL, 1024 * 1024, targ);
24368e1c830ade592be74773e249bf94e2bbfb50de7Johann  if (tid == -1) {
24468e1c830ade592be74773e249bf94e2bbfb50de7Johann    free(targ);
24568e1c830ade592be74773e249bf94e2bbfb50de7Johann    return 1;
24668e1c830ade592be74773e249bf94e2bbfb50de7Johann  }
24768e1c830ade592be74773e249bf94e2bbfb50de7Johann
24868e1c830ade592be74773e249bf94e2bbfb50de7Johann  *thread = tid;
24968e1c830ade592be74773e249bf94e2bbfb50de7Johann  return 0;
25068e1c830ade592be74773e249bf94e2bbfb50de7Johann}
25168e1c830ade592be74773e249bf94e2bbfb50de7Johann
2527bc9febe8749e98a3812a0dc4380ceae75c29450Johannstatic INLINE int pthread_join(pthread_t thread, void **value_ptr) {
25368e1c830ade592be74773e249bf94e2bbfb50de7Johann  (void)value_ptr;
25468e1c830ade592be74773e249bf94e2bbfb50de7Johann  return DosWaitThread(&thread, DCWW_WAIT) != 0;
25568e1c830ade592be74773e249bf94e2bbfb50de7Johann}
25668e1c830ade592be74773e249bf94e2bbfb50de7Johann
25768e1c830ade592be74773e249bf94e2bbfb50de7Johann// Mutex
25868e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_mutex_init(pthread_mutex_t *const mutex,
2597bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                     void *mutexattr) {
26068e1c830ade592be74773e249bf94e2bbfb50de7Johann  (void)mutexattr;
26168e1c830ade592be74773e249bf94e2bbfb50de7Johann  return DosCreateMutexSem(NULL, mutex, 0, FALSE) != 0;
26268e1c830ade592be74773e249bf94e2bbfb50de7Johann}
26368e1c830ade592be74773e249bf94e2bbfb50de7Johann
26468e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_mutex_trylock(pthread_mutex_t *const mutex) {
26568e1c830ade592be74773e249bf94e2bbfb50de7Johann  return DosRequestMutexSem(*mutex, SEM_IMMEDIATE_RETURN) == 0 ? 0 : EBUSY;
26668e1c830ade592be74773e249bf94e2bbfb50de7Johann}
26768e1c830ade592be74773e249bf94e2bbfb50de7Johann
26868e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_mutex_lock(pthread_mutex_t *const mutex) {
26968e1c830ade592be74773e249bf94e2bbfb50de7Johann  return DosRequestMutexSem(*mutex, SEM_INDEFINITE_WAIT) != 0;
27068e1c830ade592be74773e249bf94e2bbfb50de7Johann}
27168e1c830ade592be74773e249bf94e2bbfb50de7Johann
27268e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_mutex_unlock(pthread_mutex_t *const mutex) {
27368e1c830ade592be74773e249bf94e2bbfb50de7Johann  return DosReleaseMutexSem(*mutex) != 0;
27468e1c830ade592be74773e249bf94e2bbfb50de7Johann}
27568e1c830ade592be74773e249bf94e2bbfb50de7Johann
27668e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_mutex_destroy(pthread_mutex_t *const mutex) {
27768e1c830ade592be74773e249bf94e2bbfb50de7Johann  return DosCloseMutexSem(*mutex) != 0;
27868e1c830ade592be74773e249bf94e2bbfb50de7Johann}
27968e1c830ade592be74773e249bf94e2bbfb50de7Johann
28068e1c830ade592be74773e249bf94e2bbfb50de7Johann// Condition
28168e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_cond_destroy(pthread_cond_t *const condition) {
28268e1c830ade592be74773e249bf94e2bbfb50de7Johann  int ok = 1;
28368e1c830ade592be74773e249bf94e2bbfb50de7Johann  ok &= DosCloseEventSem(condition->event_sem_) == 0;
28468e1c830ade592be74773e249bf94e2bbfb50de7Johann  ok &= DosCloseEventSem(condition->ack_sem_) == 0;
28568e1c830ade592be74773e249bf94e2bbfb50de7Johann  return !ok;
28668e1c830ade592be74773e249bf94e2bbfb50de7Johann}
28768e1c830ade592be74773e249bf94e2bbfb50de7Johann
28868e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_cond_init(pthread_cond_t *const condition,
2897bc9febe8749e98a3812a0dc4380ceae75c29450Johann                                    void *cond_attr) {
29068e1c830ade592be74773e249bf94e2bbfb50de7Johann  int ok = 1;
29168e1c830ade592be74773e249bf94e2bbfb50de7Johann  (void)cond_attr;
29268e1c830ade592be74773e249bf94e2bbfb50de7Johann
2937bc9febe8749e98a3812a0dc4380ceae75c29450Johann  ok &=
2947bc9febe8749e98a3812a0dc4380ceae75c29450Johann      DosCreateEventSem(NULL, &condition->event_sem_, DCE_POSTONE, FALSE) == 0;
29568e1c830ade592be74773e249bf94e2bbfb50de7Johann  ok &= DosCreateEventSem(NULL, &condition->ack_sem_, DCE_POSTONE, FALSE) == 0;
29668e1c830ade592be74773e249bf94e2bbfb50de7Johann  if (!ok) {
29768e1c830ade592be74773e249bf94e2bbfb50de7Johann    pthread_cond_destroy(condition);
29868e1c830ade592be74773e249bf94e2bbfb50de7Johann    return 1;
29968e1c830ade592be74773e249bf94e2bbfb50de7Johann  }
30068e1c830ade592be74773e249bf94e2bbfb50de7Johann  condition->wait_count_ = 0;
30168e1c830ade592be74773e249bf94e2bbfb50de7Johann  return 0;
30268e1c830ade592be74773e249bf94e2bbfb50de7Johann}
30368e1c830ade592be74773e249bf94e2bbfb50de7Johann
30468e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_cond_signal(pthread_cond_t *const condition) {
30568e1c830ade592be74773e249bf94e2bbfb50de7Johann  int ok = 1;
30668e1c830ade592be74773e249bf94e2bbfb50de7Johann
30768e1c830ade592be74773e249bf94e2bbfb50de7Johann  if (!__atomic_cmpxchg32(&condition->wait_count_, 0, 0)) {
30868e1c830ade592be74773e249bf94e2bbfb50de7Johann    ok &= DosPostEventSem(condition->event_sem_) == 0;
30968e1c830ade592be74773e249bf94e2bbfb50de7Johann    ok &= DosWaitEventSem(condition->ack_sem_, SEM_INDEFINITE_WAIT) == 0;
31068e1c830ade592be74773e249bf94e2bbfb50de7Johann  }
31168e1c830ade592be74773e249bf94e2bbfb50de7Johann
31268e1c830ade592be74773e249bf94e2bbfb50de7Johann  return !ok;
31368e1c830ade592be74773e249bf94e2bbfb50de7Johann}
31468e1c830ade592be74773e249bf94e2bbfb50de7Johann
31568e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_cond_broadcast(pthread_cond_t *const condition) {
31668e1c830ade592be74773e249bf94e2bbfb50de7Johann  int ok = 1;
31768e1c830ade592be74773e249bf94e2bbfb50de7Johann
31868e1c830ade592be74773e249bf94e2bbfb50de7Johann  while (!__atomic_cmpxchg32(&condition->wait_count_, 0, 0))
3197bc9febe8749e98a3812a0dc4380ceae75c29450Johann    ok &= pthread_cond_signal(condition) == 0;
32068e1c830ade592be74773e249bf94e2bbfb50de7Johann
32168e1c830ade592be74773e249bf94e2bbfb50de7Johann  return !ok;
32268e1c830ade592be74773e249bf94e2bbfb50de7Johann}
32368e1c830ade592be74773e249bf94e2bbfb50de7Johann
32468e1c830ade592be74773e249bf94e2bbfb50de7Johannstatic INLINE int pthread_cond_wait(pthread_cond_t *const condition,
32568e1c830ade592be74773e249bf94e2bbfb50de7Johann                                    pthread_mutex_t *const mutex) {
32668e1c830ade592be74773e249bf94e2bbfb50de7Johann  int ok = 1;
32768e1c830ade592be74773e249bf94e2bbfb50de7Johann
32868e1c830ade592be74773e249bf94e2bbfb50de7Johann  __atomic_increment(&condition->wait_count_);
32968e1c830ade592be74773e249bf94e2bbfb50de7Johann
33068e1c830ade592be74773e249bf94e2bbfb50de7Johann  ok &= pthread_mutex_unlock(mutex) == 0;
33168e1c830ade592be74773e249bf94e2bbfb50de7Johann
33268e1c830ade592be74773e249bf94e2bbfb50de7Johann  ok &= DosWaitEventSem(condition->event_sem_, SEM_INDEFINITE_WAIT) == 0;
33368e1c830ade592be74773e249bf94e2bbfb50de7Johann
33468e1c830ade592be74773e249bf94e2bbfb50de7Johann  __atomic_decrement(&condition->wait_count_);
33568e1c830ade592be74773e249bf94e2bbfb50de7Johann
33668e1c830ade592be74773e249bf94e2bbfb50de7Johann  ok &= DosPostEventSem(condition->ack_sem_) == 0;
33768e1c830ade592be74773e249bf94e2bbfb50de7Johann
33868e1c830ade592be74773e249bf94e2bbfb50de7Johann  pthread_mutex_lock(mutex);
33968e1c830ade592be74773e249bf94e2bbfb50de7Johann
34068e1c830ade592be74773e249bf94e2bbfb50de7Johann  return !ok;
34168e1c830ade592be74773e249bf94e2bbfb50de7Johann}
3427bc9febe8749e98a3812a0dc4380ceae75c29450Johann#else                 // _WIN32
3437bc9febe8749e98a3812a0dc4380ceae75c29450Johann#include <pthread.h>  // NOLINT
3447bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define THREADFN void *
3457bc9febe8749e98a3812a0dc4380ceae75c29450Johann#define THREAD_RETURN(val) val
3462ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#endif
347f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
3482ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#endif  // CONFIG_MULTITHREAD
349f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
350f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// State of the worker thread object
351f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef enum {
3527bc9febe8749e98a3812a0dc4380ceae75c29450Johann  NOT_OK = 0,  // object is unusable
3537bc9febe8749e98a3812a0dc4380ceae75c29450Johann  OK,          // ready to work
3547bc9febe8749e98a3812a0dc4380ceae75c29450Johann  WORK         // busy finishing the current task
3557ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian} VPxWorkerStatus;
356f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
357f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// Function to be called by the worker thread. Takes two opaque pointers as
358f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang// arguments (data1 and data2), and should return false in case of error.
3597bc9febe8749e98a3812a0dc4380ceae75c29450Johanntypedef int (*VPxWorkerHook)(void *, void *);
360f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
361ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// Platform-dependent implementation details for the worker.
3627ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramaniantypedef struct VPxWorkerImpl VPxWorkerImpl;
363ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
364ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// Synchronization object used to launch job in the worker thread
365f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangtypedef struct {
3667ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  VPxWorkerImpl *impl_;
3677ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  VPxWorkerStatus status_;
3687bc9febe8749e98a3812a0dc4380ceae75c29450Johann  VPxWorkerHook hook;  // hook to call
3697bc9febe8749e98a3812a0dc4380ceae75c29450Johann  void *data1;         // first argument passed to 'hook'
3707bc9febe8749e98a3812a0dc4380ceae75c29450Johann  void *data2;         // second argument passed to 'hook'
3717bc9febe8749e98a3812a0dc4380ceae75c29450Johann  int had_error;       // return value of the last call to 'hook'
3727ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian} VPxWorker;
373f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
374ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// The interface for all thread-worker related functions. All these functions
375ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// must be implemented.
376ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramaniantypedef struct {
377ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // Must be called first, before any other method.
3787ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  void (*init)(VPxWorker *const worker);
379ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // Must be called to initialize the object and spawn the thread. Re-entrant.
380ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // Will potentially launch the thread. Returns false in case of error.
3817ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  int (*reset)(VPxWorker *const worker);
382ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // Makes sure the previous work is finished. Returns true if worker->had_error
383ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // was not set and no error condition was triggered by the working thread.
3847ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  int (*sync)(VPxWorker *const worker);
385ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // Triggers the thread to call hook() with data1 and data2 arguments. These
386ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // hook/data1/data2 values can be changed at any time before calling this
387ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // function, but not be changed afterward until the next call to Sync().
3887ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  void (*launch)(VPxWorker *const worker);
389ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // This function is similar to launch() except that it calls the
390ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // hook directly instead of using a thread. Convenient to bypass the thread
3917ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  // mechanism while still using the VPxWorker structs. sync() must
392ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // still be called afterward (for error reporting).
3937ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  void (*execute)(VPxWorker *const worker);
394ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // Kill the thread and terminate the object. To use the object again, one
395ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian  // must call reset() again.
3967ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian  void (*end)(VPxWorker *const worker);
3977ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian} VPxWorkerInterface;
398ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
399ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// Install a new set of threading functions, overriding the defaults. This
400ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// should be done before any workers are started, i.e., before any encoding or
401ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// decoding takes place. The contents of the interface struct are copied, it
402ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// is safe to free the corresponding memory after this call. This function is
403ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// not thread-safe. Return false in case of invalid pointer or methods.
4047ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanianint vpx_set_worker_interface(const VPxWorkerInterface *const winterface);
405ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian
406ba6c59e9d7d7013b3906b6f4230b663422681848Vignesh Venkatasubramanian// Retrieve the currently set thread worker interface.
4077ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanianconst VPxWorkerInterface *vpx_get_worker_interface(void);
408f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
409f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang//------------------------------------------------------------------------------
410f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
4112ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#ifdef __cplusplus
4127bc9febe8749e98a3812a0dc4380ceae75c29450Johann}  // extern "C"
413f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang#endif
414f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang
4157ce0a1d1337c01056ba24006efab21f00e179e04Vignesh Venkatasubramanian#endif  // VPX_THREAD_H_
416