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