diff options
Diffstat (limited to 'src/util/u_thread.h')
-rw-r--r-- | src/util/u_thread.h | 338 |
1 files changed, 68 insertions, 270 deletions
diff --git a/src/util/u_thread.h b/src/util/u_thread.h index 013e8be6a6e..b5c7667d3d0 100644 --- a/src/util/u_thread.h +++ b/src/util/u_thread.h @@ -1,9 +1,9 @@ /************************************************************************** - * + * * Copyright 1999-2006 Brian Paul * Copyright 2008 VMware, Inc. * All Rights Reserved. - * + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation @@ -34,36 +34,6 @@ #include "c11/threads.h" #include "detect_os.h" -#include "macros.h" - -#ifdef HAVE_PTHREAD -#include <signal.h> -#ifdef HAVE_PTHREAD_NP_H -#include <pthread_np.h> -#endif -#endif - -#ifdef __HAIKU__ -#include <OS.h> -#endif - -#if DETECT_OS_LINUX && !defined(ANDROID) -#include <sched.h> -#elif defined(_WIN32) && !defined(__CYGWIN__) && _WIN32_WINNT >= 0x0600 -#include <windows.h> -#endif - -#ifdef __FreeBSD__ -/* pthread_np.h -> sys/param.h -> machine/param.h - * - defines ALIGN which clashes with our ALIGN - */ -#undef ALIGN -#define cpu_set_t cpuset_t -#endif - -/* For util_set_thread_affinity to size the mask. */ -#define UTIL_MAX_CPUS 1024 /* this should be enough */ -#define UTIL_MAX_L3_CACHES UTIL_MAX_CPUS /* Some highly performance-sensitive thread-local variables like the current GL * context are declared with the initial-exec model on Linux. glibc allocates a @@ -75,83 +45,28 @@ * still want to use normal TLS (which involves a function call, but not the * expensive pthread_getspecific() or its equivalent). */ -#ifdef _MSC_VER -#define __THREAD_INITIAL_EXEC __declspec(thread) -#elif defined(ANDROID) -/* Android 29 gained ELF TLS support, but it doesn't support initial-exec and - * it will throw: - * - * dlopen failed: TLS symbol "(null)" in dlopened - * "/vendor/lib64/egl/libEGL_mesa.so" referenced from - * "/vendor/lib64/egl/libEGL_mesa.so" using IE access model. +#if DETECT_OS_APPLE +/* Apple Clang emits wrappers when using thread_local that break module linkage, + * but not with __thread */ #define __THREAD_INITIAL_EXEC __thread +#elif defined(__GLIBC__) +#define __THREAD_INITIAL_EXEC thread_local __attribute__((tls_model("initial-exec"))) +#define REALLY_INITIAL_EXEC #else -#define __THREAD_INITIAL_EXEC __thread __attribute__((tls_model("initial-exec"))) +#define __THREAD_INITIAL_EXEC thread_local #endif -static inline int -util_get_current_cpu(void) -{ -#if DETECT_OS_LINUX && !defined(ANDROID) - return sched_getcpu(); - -#elif defined(_WIN32) && !defined(__CYGWIN__) && _WIN32_WINNT >= 0x0600 - return GetCurrentProcessorNumber(); - -#else - return -1; +#ifdef __cplusplus +extern "C" { #endif -} -static inline thrd_t u_thread_create(int (*routine)(void *), void *param) -{ - thrd_t thread; -#ifdef HAVE_PTHREAD - sigset_t saved_set, new_set; - int ret; - - sigfillset(&new_set); - sigdelset(&new_set, SIGSYS); - pthread_sigmask(SIG_BLOCK, &new_set, &saved_set); - ret = thrd_create( &thread, routine, param ); - pthread_sigmask(SIG_SETMASK, &saved_set, NULL); -#else - int ret; - ret = thrd_create( &thread, routine, param ); -#endif - if (ret) - return 0; +int +util_get_current_cpu(void); - return thread; -} +int u_thread_create(thrd_t *thrd, int (*routine)(void *), void *param); -static inline void u_thread_setname( const char *name ) -{ -#if defined(HAVE_PTHREAD) -#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS - int ret = pthread_setname_np(pthread_self(), name); - if (ret == ERANGE) { - char buf[16]; - const size_t len = MIN2(strlen(name), ARRAY_SIZE(buf) - 1); - memcpy(buf, name, len); - buf[len] = '\0'; - pthread_setname_np(pthread_self(), buf); - } -#elif DETECT_OS_FREEBSD || DETECT_OS_OPENBSD - pthread_set_name_np(pthread_self(), name); -#elif DETECT_OS_NETBSD - pthread_setname_np(pthread_self(), "%s", (void *)name); -#elif DETECT_OS_APPLE - pthread_setname_np(name); -#elif DETECT_OS_HAIKU - rename_thread(find_thread(NULL), name); -#else -#warning Not sure how to call pthread_setname_np -#endif -#endif - (void)name; -} +void u_thread_setname( const char *name ); /** * Set thread affinity. @@ -162,120 +77,39 @@ static inline void u_thread_setname( const char *name ) * \param num_mask_bits Number of bits in both masks * \return true on success */ -static inline bool +bool util_set_thread_affinity(thrd_t thread, const uint32_t *mask, uint32_t *old_mask, - unsigned num_mask_bits) -{ -#if defined(HAVE_PTHREAD_SETAFFINITY) - cpu_set_t cpuset; - - if (old_mask) { - if (pthread_getaffinity_np(thread, sizeof(cpuset), &cpuset) != 0) - return false; - - memset(old_mask, 0, num_mask_bits / 8); - for (unsigned i = 0; i < num_mask_bits && i < CPU_SETSIZE; i++) { - if (CPU_ISSET(i, &cpuset)) - old_mask[i / 32] |= 1u << (i % 32); - } - } - - CPU_ZERO(&cpuset); - for (unsigned i = 0; i < num_mask_bits && i < CPU_SETSIZE; i++) { - if (mask[i / 32] & (1u << (i % 32))) - CPU_SET(i, &cpuset); - } - return pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset) == 0; - -#elif defined(_WIN32) && !defined(__CYGWIN__) - DWORD_PTR m = mask[0]; - - if (sizeof(m) > 4 && num_mask_bits > 32) - m |= (uint64_t)mask[1] << 32; - - m = SetThreadAffinityMask(thread, m); - if (!m) - return false; - - if (old_mask) { - memset(old_mask, 0, num_mask_bits / 8); - - old_mask[0] = m; -#ifdef _WIN64 - old_mask[1] = m >> 32; -#endif - } - - return true; -#else - return false; -#endif -} + unsigned num_mask_bits); static inline bool util_set_current_thread_affinity(const uint32_t *mask, uint32_t *old_mask, unsigned num_mask_bits) { -#if defined(HAVE_PTHREAD_SETAFFINITY) - return util_set_thread_affinity(pthread_self(), mask, old_mask, - num_mask_bits); - -#elif defined(_WIN32) && !defined(__CYGWIN__) - /* The GetCurrentThreadId() handle is only valid within the current thread. */ - return util_set_thread_affinity(GetCurrentThread(), mask, old_mask, + return util_set_thread_affinity(thrd_current(), mask, old_mask, num_mask_bits); - -#else - return false; -#endif } - /* * Thread statistics. */ /* Return the time of a thread's CPU time clock. */ -static inline int64_t -util_thread_get_time_nano(thrd_t thread) -{ -#if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__) - struct timespec ts; - clockid_t cid; - - pthread_getcpuclockid(thread, &cid); - clock_gettime(cid, &ts); - return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; -#else - return 0; -#endif -} +int64_t +util_thread_get_time_nano(thrd_t thread); /* Return the time of the current thread's CPU time clock. */ static inline int64_t util_current_thread_get_time_nano(void) { -#if defined(HAVE_PTHREAD) - return util_thread_get_time_nano(pthread_self()); - -#elif defined(_WIN32) && !defined(__CYGWIN__) - /* The GetCurrentThreadId() handle is only valid within the current thread. */ - return util_thread_get_time_nano(GetCurrentThread()); - -#else - return 0; -#endif + return util_thread_get_time_nano(thrd_current()); } static inline bool u_thread_is_self(thrd_t thread) { -#if defined(HAVE_PTHREAD) - return pthread_equal(pthread_self(), thread); -#endif - return false; + return thrd_equal(thrd_current(), thread); } /* @@ -286,22 +120,6 @@ static inline bool u_thread_is_self(thrd_t thread) typedef pthread_barrier_t util_barrier; -static inline void util_barrier_init(util_barrier *barrier, unsigned count) -{ - pthread_barrier_init(barrier, NULL, count); -} - -static inline void util_barrier_destroy(util_barrier *barrier) -{ - pthread_barrier_destroy(barrier); -} - -static inline void util_barrier_wait(util_barrier *barrier) -{ - pthread_barrier_wait(barrier); -} - - #else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */ typedef struct { @@ -312,85 +130,65 @@ typedef struct { cnd_t condvar; } util_barrier; -static inline void util_barrier_init(util_barrier *barrier, unsigned count) -{ - barrier->count = count; - barrier->waiters = 0; - barrier->sequence = 0; - (void) mtx_init(&barrier->mutex, mtx_plain); - cnd_init(&barrier->condvar); -} - -static inline void util_barrier_destroy(util_barrier *barrier) -{ - assert(barrier->waiters == 0); - mtx_destroy(&barrier->mutex); - cnd_destroy(&barrier->condvar); -} - -static inline void util_barrier_wait(util_barrier *barrier) -{ - mtx_lock(&barrier->mutex); - - assert(barrier->waiters < barrier->count); - barrier->waiters++; +#endif - if (barrier->waiters < barrier->count) { - uint64_t sequence = barrier->sequence; +void util_barrier_init(util_barrier *barrier, unsigned count); - do { - cnd_wait(&barrier->condvar, &barrier->mutex); - } while (sequence == barrier->sequence); - } else { - barrier->waiters = 0; - barrier->sequence++; - cnd_broadcast(&barrier->condvar); - } +void util_barrier_destroy(util_barrier *barrier); - mtx_unlock(&barrier->mutex); -} - -#endif +bool util_barrier_wait(util_barrier *barrier); /* - * Thread-id's. - * - * thrd_current() is not portable to windows (or at least not in a desirable - * way), so thread_id's provide an alternative mechanism + * Semaphores */ -#ifdef _WIN32 -typedef DWORD thread_id; -#else -typedef thrd_t thread_id; -#endif +typedef struct +{ + mtx_t mutex; + cnd_t cond; + int counter; +} util_semaphore; + -static inline thread_id -util_get_thread_id(void) +static inline void +util_semaphore_init(util_semaphore *sema, int init_val) { - /* - * XXX: Callers of of this function assume it is a lightweight function. - * But unfortunately C11's thrd_current() gives no such guarantees. In - * fact, it's pretty hard to have a compliant implementation of - * thrd_current() on Windows with such characteristics. So for now, we - * side-step this mess and use Windows thread primitives directly here. - */ -#ifdef _WIN32 - return GetCurrentThreadId(); -#else - return thrd_current(); -#endif + (void) mtx_init(&sema->mutex, mtx_plain); + cnd_init(&sema->cond); + sema->counter = init_val; } +static inline void +util_semaphore_destroy(util_semaphore *sema) +{ + mtx_destroy(&sema->mutex); + cnd_destroy(&sema->cond); +} -static inline int -util_thread_id_equal(thread_id t1, thread_id t2) +/** Signal/increment semaphore counter */ +static inline void +util_semaphore_signal(util_semaphore *sema) { -#ifdef _WIN32 - return t1 == t2; -#else - return thrd_equal(t1, t2); -#endif + mtx_lock(&sema->mutex); + sema->counter++; + cnd_signal(&sema->cond); + mtx_unlock(&sema->mutex); } +/** Wait for semaphore counter to be greater than zero */ +static inline void +util_semaphore_wait(util_semaphore *sema) +{ + mtx_lock(&sema->mutex); + while (sema->counter <= 0) { + cnd_wait(&sema->cond, &sema->mutex); + } + sema->counter--; + mtx_unlock(&sema->mutex); +} + +#ifdef __cplusplus +} +#endif + #endif /* U_THREAD_H_ */ |