/* * This file is part of libplacebo. * * libplacebo is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * libplacebo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with libplacebo. If not, see . */ #pragma once #include #include #include #include #include typedef CRITICAL_SECTION pl_mutex; typedef CONDITION_VARIABLE pl_cond; static inline int pl_mutex_init_type_internal(pl_mutex *mutex, enum pl_mutex_type mtype) { (void) mtype; return !InitializeCriticalSectionEx(mutex, 0, 0); } #define pl_mutex_init_type(mutex, mtype) \ pl_assert(!pl_mutex_init_type_internal(mutex, mtype)) static inline int pl_mutex_destroy(pl_mutex *mutex) { DeleteCriticalSection(mutex); return 0; } static inline int pl_mutex_lock(pl_mutex *mutex) { EnterCriticalSection(mutex); return 0; } static inline int pl_mutex_unlock(pl_mutex *mutex) { LeaveCriticalSection(mutex); return 0; } static inline int pl_cond_init(pl_cond *cond) { InitializeConditionVariable(cond); return 0; } static inline int pl_cond_destroy(pl_cond *cond) { // condition variables are not destroyed (void) cond; return 0; } static inline int pl_cond_broadcast(pl_cond *cond) { WakeAllConditionVariable(cond); return 0; } static inline int pl_cond_signal(pl_cond *cond) { WakeConditionVariable(cond); return 0; } static inline int pl_cond_wait(pl_cond *cond, pl_mutex *mutex) { return !SleepConditionVariableCS(cond, mutex, INFINITE); } static inline int pl_cond_timedwait(pl_cond *cond, pl_mutex *mutex, uint64_t timeout) { if (timeout == UINT64_MAX) return pl_cond_wait(cond, mutex); timeout /= UINT64_C(1000000); if (timeout > INFINITE - 1) timeout = INFINITE - 1; BOOL bRet = SleepConditionVariableCS(cond, mutex, timeout); if (bRet == FALSE) { if (GetLastError() == ERROR_TIMEOUT) return ETIMEDOUT; else return EINVAL; } return 0; } typedef SRWLOCK pl_static_mutex; #define PL_STATIC_MUTEX_INITIALIZER SRWLOCK_INIT static inline int pl_static_mutex_lock(pl_static_mutex *mutex) { AcquireSRWLockExclusive(mutex); return 0; } static inline int pl_static_mutex_unlock(pl_static_mutex *mutex) { ReleaseSRWLockExclusive(mutex); return 0; } typedef HANDLE pl_thread; #define PL_THREAD_VOID unsigned __stdcall #define PL_THREAD_RETURN() return 0 static inline int pl_thread_create(pl_thread *thread, PL_THREAD_VOID (*fun)(void *), void *__restrict arg) { *thread = (HANDLE) _beginthreadex(NULL, 0, fun, arg, 0, NULL); return *thread ? 0 : -1; } static inline int pl_thread_join(pl_thread thread) { DWORD ret = WaitForSingleObject(thread, INFINITE); if (ret != WAIT_OBJECT_0) return ret == WAIT_ABANDONED ? EINVAL : EDEADLK; CloseHandle(thread); return 0; } static inline bool pl_thread_sleep(double t) { // Time is expected in 100 nanosecond intervals. // Negative values indicate relative time. LARGE_INTEGER time = { .QuadPart = -(LONGLONG) (t * 1e7) }; if (time.QuadPart >= 0) return true; bool ret = false; #ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION # define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x2 #endif HANDLE timer = CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is supported in Windows 10 1803+, // retry without it. if (!timer) timer = CreateWaitableTimerEx(NULL, NULL, 0, TIMER_ALL_ACCESS); if (!timer) goto end; if (!SetWaitableTimer(timer, &time, 0, NULL, NULL, 0)) goto end; if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) goto end; ret = true; end: if (timer) CloseHandle(timer); return ret; }