summaryrefslogtreecommitdiff
path: root/src/util/u_thread.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/u_thread.h')
-rw-r--r--src/util/u_thread.h338
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_ */