#pragma once #include "fastfetch.h" #ifdef FF_HAVE_THREADS #if defined(_WIN32) #include #include #include #include #define FF_THREAD_MUTEX_INITIALIZER SRWLOCK_INIT typedef SRWLOCK FFThreadMutex; typedef HANDLE FFThreadType; static inline void ffThreadMutexLock(FFThreadMutex* mutex) { AcquireSRWLockExclusive(mutex); } static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) { ReleaseSRWLockExclusive(mutex); } static inline FFThreadType ffThreadCreate(unsigned(__stdcall* func)(void*), void* data) { return (FFThreadType) _beginthreadex(NULL, 0, func, data, 0, NULL); } #define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) \ static __stdcall unsigned fn##ThreadMain(void* data) { \ fn((paramType) data); \ return 0; \ } #define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) \ static __stdcall unsigned fn##ThreadMain() { \ fn(); \ return 0; \ } static inline void ffThreadDetach(FFThreadType thread) { NtClose(thread); } static inline bool ffThreadJoin(FFThreadType thread, uint32_t timeout) { if (NtWaitForSingleObject(thread, FALSE, timeout == 0 ? NULL : &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 }) != STATUS_WAIT_0) { TerminateThread(thread, (DWORD) -1); NtClose(thread); return false; } NtClose(thread); return true; } #else #include #include #if FF_HAVE_PTHREAD_NP #include #endif typedef pthread_t FFThreadType; #if __APPLE__ #include #define FF_THREAD_MUTEX_INITIALIZER OS_UNFAIR_LOCK_INIT typedef os_unfair_lock FFThreadMutex; static inline void ffThreadMutexLock(os_unfair_lock* mutex) { os_unfair_lock_lock(mutex); } static inline void ffThreadMutexUnlock(os_unfair_lock* mutex) { os_unfair_lock_unlock(mutex); } #else #define FF_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER typedef pthread_mutex_t FFThreadMutex; static inline void ffThreadMutexLock(FFThreadMutex* mutex) { pthread_mutex_lock(mutex); } static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) { pthread_mutex_unlock(mutex); } #endif static inline FFThreadType ffThreadCreate(void* (*func)(void*), void* data) { FFThreadType newThread = 0; pthread_create(&newThread, NULL, func, data); return newThread; } #define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) \ static void* fn##ThreadMain(void* data) { \ fn((paramType) data); \ return NULL; \ } #define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) \ static void* fn##ThreadMain() { \ fn(); \ return NULL; \ } static inline void ffThreadDetach(FFThreadType thread) { pthread_detach(thread); } static inline bool ffThreadJoin(FFThreadType thread, FF_A_UNUSED uint32_t timeout) { #if HAVE_TIMEDJOIN_NP if (timeout > 0) { struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { ts.tv_sec += timeout / 1000; ts.tv_nsec += (timeout % 1000) * 1000000; if (pthread_timedjoin_np(thread, NULL, &ts) != 0) { pthread_kill(thread, SIGTERM); return false; } return true; } } #endif pthread_join(thread, NULL); return true; } #endif #else // FF_HAVE_THREADS #define FF_THREAD_MUTEX_INITIALIZER 0 typedef char FFThreadMutex; static inline void ffThreadMutexLock(FF_A_UNUSED FFThreadMutex* mutex) {} static inline void ffThreadMutexUnlock(FF_A_UNUSED FFThreadMutex* mutex) {} #define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) #endif // FF_HAVE_THREADS