summaryrefslogtreecommitdiffstats
path: root/src/common/thread.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/thread.h')
-rw-r--r--src/common/thread.h115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/common/thread.h b/src/common/thread.h
new file mode 100644
index 0000000..64d8478
--- /dev/null
+++ b/src/common/thread.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#include "fastfetch.h"
+
+#ifdef FF_HAVE_THREADS
+ #if defined(_WIN32)
+ #include <winternl.h>
+ #include <synchapi.h>
+ #include <process.h>
+ #include <processthreadsapi.h>
+ #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 <pthread.h>
+ #include <signal.h>
+ #if FF_HAVE_PTHREAD_NP
+ #include <pthread_np.h>
+ #endif
+typedef pthread_t FFThreadType;
+ #if __APPLE__
+ #include <os/lock.h>
+ #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