1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 1999-2006 Brian Paul 4bf215546Sopenharmony_ci * Copyright 2008 VMware, Inc. 5bf215546Sopenharmony_ci * All Rights Reserved. 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 10bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 12bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included 15bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 16bf215546Sopenharmony_ci * 17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 24bf215546Sopenharmony_ci * 25bf215546Sopenharmony_ci **************************************************************************/ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#ifndef U_THREAD_H_ 28bf215546Sopenharmony_ci#define U_THREAD_H_ 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include <errno.h> 31bf215546Sopenharmony_ci#include <stdint.h> 32bf215546Sopenharmony_ci#include <stdbool.h> 33bf215546Sopenharmony_ci#include <string.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include "c11/threads.h" 36bf215546Sopenharmony_ci#include "detect_os.h" 37bf215546Sopenharmony_ci#include "macros.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#ifdef HAVE_PTHREAD 40bf215546Sopenharmony_ci#include <signal.h> 41bf215546Sopenharmony_ci#ifdef HAVE_PTHREAD_NP_H 42bf215546Sopenharmony_ci#include <pthread_np.h> 43bf215546Sopenharmony_ci#endif 44bf215546Sopenharmony_ci#endif 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci#ifdef __HAIKU__ 47bf215546Sopenharmony_ci#include <OS.h> 48bf215546Sopenharmony_ci#endif 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci#if DETECT_OS_LINUX && !defined(ANDROID) 51bf215546Sopenharmony_ci#include <sched.h> 52bf215546Sopenharmony_ci#elif defined(_WIN32) && !defined(__CYGWIN__) && _WIN32_WINNT >= 0x0600 53bf215546Sopenharmony_ci#ifndef WIN32_LEAN_AND_MEAN 54bf215546Sopenharmony_ci#define WIN32_LEAN_AND_MEAN 1 55bf215546Sopenharmony_ci#endif 56bf215546Sopenharmony_ci#include <windows.h> 57bf215546Sopenharmony_ci#endif 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci#ifdef __FreeBSD__ 60bf215546Sopenharmony_ci/* pthread_np.h -> sys/param.h -> machine/param.h 61bf215546Sopenharmony_ci * - defines ALIGN which clashes with our ALIGN 62bf215546Sopenharmony_ci */ 63bf215546Sopenharmony_ci#undef ALIGN 64bf215546Sopenharmony_ci#define cpu_set_t cpuset_t 65bf215546Sopenharmony_ci#endif 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci/* For util_set_thread_affinity to size the mask. */ 68bf215546Sopenharmony_ci#define UTIL_MAX_CPUS 1024 /* this should be enough */ 69bf215546Sopenharmony_ci#define UTIL_MAX_L3_CACHES UTIL_MAX_CPUS 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci/* Some highly performance-sensitive thread-local variables like the current GL 72bf215546Sopenharmony_ci * context are declared with the initial-exec model on Linux. glibc allocates a 73bf215546Sopenharmony_ci * fixed number of extra slots for initial-exec TLS variables at startup, and 74bf215546Sopenharmony_ci * Mesa relies on (even if it's dlopen()ed after init) being able to fit into 75bf215546Sopenharmony_ci * those. This model saves the call to look up the address of the TLS variable. 76bf215546Sopenharmony_ci * 77bf215546Sopenharmony_ci * However, if we don't have this TLS model available on the platform, then we 78bf215546Sopenharmony_ci * still want to use normal TLS (which involves a function call, but not the 79bf215546Sopenharmony_ci * expensive pthread_getspecific() or its equivalent). 80bf215546Sopenharmony_ci */ 81bf215546Sopenharmony_ci#if DETECT_OS_APPLE 82bf215546Sopenharmony_ci/* Apple Clang emits wrappers when using thread_local that break module linkage, 83bf215546Sopenharmony_ci * but not with __thread 84bf215546Sopenharmony_ci */ 85bf215546Sopenharmony_ci#define __THREAD_INITIAL_EXEC __thread 86bf215546Sopenharmony_ci#elif defined(__GLIBC__) 87bf215546Sopenharmony_ci#define __THREAD_INITIAL_EXEC thread_local __attribute__((tls_model("initial-exec"))) 88bf215546Sopenharmony_ci#define REALLY_INITIAL_EXEC 89bf215546Sopenharmony_ci#else 90bf215546Sopenharmony_ci#define __THREAD_INITIAL_EXEC thread_local 91bf215546Sopenharmony_ci#endif 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_cistatic inline int 94bf215546Sopenharmony_ciutil_get_current_cpu(void) 95bf215546Sopenharmony_ci{ 96bf215546Sopenharmony_ci#if DETECT_OS_LINUX && !defined(ANDROID) 97bf215546Sopenharmony_ci return sched_getcpu(); 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci#elif defined(_WIN32) && !defined(__CYGWIN__) && _WIN32_WINNT >= 0x0600 100bf215546Sopenharmony_ci return GetCurrentProcessorNumber(); 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci#else 103bf215546Sopenharmony_ci return -1; 104bf215546Sopenharmony_ci#endif 105bf215546Sopenharmony_ci} 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_cistatic inline int u_thread_create(thrd_t *thrd, int (*routine)(void *), void *param) 108bf215546Sopenharmony_ci{ 109bf215546Sopenharmony_ci int ret = thrd_error; 110bf215546Sopenharmony_ci#ifdef HAVE_PTHREAD 111bf215546Sopenharmony_ci sigset_t saved_set, new_set; 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci sigfillset(&new_set); 114bf215546Sopenharmony_ci sigdelset(&new_set, SIGSYS); 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci /* SIGSEGV is commonly used by Vulkan API tracing layers in order to track 117bf215546Sopenharmony_ci * accesses in device memory mapped to user space. Blocking the signal hinders 118bf215546Sopenharmony_ci * that tracking mechanism. 119bf215546Sopenharmony_ci */ 120bf215546Sopenharmony_ci sigdelset(&new_set, SIGSEGV); 121bf215546Sopenharmony_ci pthread_sigmask(SIG_BLOCK, &new_set, &saved_set); 122bf215546Sopenharmony_ci ret = thrd_create(thrd, routine, param); 123bf215546Sopenharmony_ci pthread_sigmask(SIG_SETMASK, &saved_set, NULL); 124bf215546Sopenharmony_ci#else 125bf215546Sopenharmony_ci ret = thrd_create(thrd, routine, param); 126bf215546Sopenharmony_ci#endif 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci return ret; 129bf215546Sopenharmony_ci} 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_cistatic inline void u_thread_setname( const char *name ) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci#if defined(HAVE_PTHREAD) 134bf215546Sopenharmony_ci#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS 135bf215546Sopenharmony_ci int ret = pthread_setname_np(pthread_self(), name); 136bf215546Sopenharmony_ci if (ret == ERANGE) { 137bf215546Sopenharmony_ci char buf[16]; 138bf215546Sopenharmony_ci const size_t len = MIN2(strlen(name), ARRAY_SIZE(buf) - 1); 139bf215546Sopenharmony_ci memcpy(buf, name, len); 140bf215546Sopenharmony_ci buf[len] = '\0'; 141bf215546Sopenharmony_ci pthread_setname_np(pthread_self(), buf); 142bf215546Sopenharmony_ci } 143bf215546Sopenharmony_ci#elif DETECT_OS_FREEBSD || DETECT_OS_OPENBSD 144bf215546Sopenharmony_ci pthread_set_name_np(pthread_self(), name); 145bf215546Sopenharmony_ci#elif DETECT_OS_NETBSD 146bf215546Sopenharmony_ci pthread_setname_np(pthread_self(), "%s", (void *)name); 147bf215546Sopenharmony_ci#elif DETECT_OS_APPLE 148bf215546Sopenharmony_ci pthread_setname_np(name); 149bf215546Sopenharmony_ci#elif DETECT_OS_HAIKU 150bf215546Sopenharmony_ci rename_thread(find_thread(NULL), name); 151bf215546Sopenharmony_ci#else 152bf215546Sopenharmony_ci#warning Not sure how to call pthread_setname_np 153bf215546Sopenharmony_ci#endif 154bf215546Sopenharmony_ci#endif 155bf215546Sopenharmony_ci (void)name; 156bf215546Sopenharmony_ci} 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci/** 159bf215546Sopenharmony_ci * Set thread affinity. 160bf215546Sopenharmony_ci * 161bf215546Sopenharmony_ci * \param thread Thread 162bf215546Sopenharmony_ci * \param mask Set this affinity mask 163bf215546Sopenharmony_ci * \param old_mask Previous affinity mask returned if not NULL 164bf215546Sopenharmony_ci * \param num_mask_bits Number of bits in both masks 165bf215546Sopenharmony_ci * \return true on success 166bf215546Sopenharmony_ci */ 167bf215546Sopenharmony_cistatic inline bool 168bf215546Sopenharmony_ciutil_set_thread_affinity(thrd_t thread, 169bf215546Sopenharmony_ci const uint32_t *mask, 170bf215546Sopenharmony_ci uint32_t *old_mask, 171bf215546Sopenharmony_ci unsigned num_mask_bits) 172bf215546Sopenharmony_ci{ 173bf215546Sopenharmony_ci#if defined(HAVE_PTHREAD_SETAFFINITY) 174bf215546Sopenharmony_ci cpu_set_t cpuset; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci if (old_mask) { 177bf215546Sopenharmony_ci if (pthread_getaffinity_np(thread, sizeof(cpuset), &cpuset) != 0) 178bf215546Sopenharmony_ci return false; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci memset(old_mask, 0, num_mask_bits / 8); 181bf215546Sopenharmony_ci for (unsigned i = 0; i < num_mask_bits && i < CPU_SETSIZE; i++) { 182bf215546Sopenharmony_ci if (CPU_ISSET(i, &cpuset)) 183bf215546Sopenharmony_ci old_mask[i / 32] |= 1u << (i % 32); 184bf215546Sopenharmony_ci } 185bf215546Sopenharmony_ci } 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci CPU_ZERO(&cpuset); 188bf215546Sopenharmony_ci for (unsigned i = 0; i < num_mask_bits && i < CPU_SETSIZE; i++) { 189bf215546Sopenharmony_ci if (mask[i / 32] & (1u << (i % 32))) 190bf215546Sopenharmony_ci CPU_SET(i, &cpuset); 191bf215546Sopenharmony_ci } 192bf215546Sopenharmony_ci return pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset) == 0; 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci#elif defined(_WIN32) && !defined(__CYGWIN__) 195bf215546Sopenharmony_ci DWORD_PTR m = mask[0]; 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci if (sizeof(m) > 4 && num_mask_bits > 32) 198bf215546Sopenharmony_ci m |= (uint64_t)mask[1] << 32; 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci m = SetThreadAffinityMask(thread, m); 201bf215546Sopenharmony_ci if (!m) 202bf215546Sopenharmony_ci return false; 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci if (old_mask) { 205bf215546Sopenharmony_ci memset(old_mask, 0, num_mask_bits / 8); 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci old_mask[0] = m; 208bf215546Sopenharmony_ci#ifdef _WIN64 209bf215546Sopenharmony_ci old_mask[1] = m >> 32; 210bf215546Sopenharmony_ci#endif 211bf215546Sopenharmony_ci } 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci return true; 214bf215546Sopenharmony_ci#else 215bf215546Sopenharmony_ci return false; 216bf215546Sopenharmony_ci#endif 217bf215546Sopenharmony_ci} 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_cistatic inline bool 220bf215546Sopenharmony_ciutil_set_current_thread_affinity(const uint32_t *mask, 221bf215546Sopenharmony_ci uint32_t *old_mask, 222bf215546Sopenharmony_ci unsigned num_mask_bits) 223bf215546Sopenharmony_ci{ 224bf215546Sopenharmony_ci#if defined(HAVE_PTHREAD_SETAFFINITY) 225bf215546Sopenharmony_ci return util_set_thread_affinity(pthread_self(), mask, old_mask, 226bf215546Sopenharmony_ci num_mask_bits); 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci#elif defined(_WIN32) && !defined(__CYGWIN__) 229bf215546Sopenharmony_ci /* The GetCurrentThreadId() handle is only valid within the current thread. */ 230bf215546Sopenharmony_ci return util_set_thread_affinity(GetCurrentThread(), mask, old_mask, 231bf215546Sopenharmony_ci num_mask_bits); 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci#else 234bf215546Sopenharmony_ci return false; 235bf215546Sopenharmony_ci#endif 236bf215546Sopenharmony_ci} 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci/* 240bf215546Sopenharmony_ci * Thread statistics. 241bf215546Sopenharmony_ci */ 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci/* Return the time of a thread's CPU time clock. */ 244bf215546Sopenharmony_cistatic inline int64_t 245bf215546Sopenharmony_ciutil_thread_get_time_nano(thrd_t thread) 246bf215546Sopenharmony_ci{ 247bf215546Sopenharmony_ci#if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__) 248bf215546Sopenharmony_ci struct timespec ts; 249bf215546Sopenharmony_ci clockid_t cid; 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci pthread_getcpuclockid(thread, &cid); 252bf215546Sopenharmony_ci clock_gettime(cid, &ts); 253bf215546Sopenharmony_ci return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; 254bf215546Sopenharmony_ci#else 255bf215546Sopenharmony_ci (void)thread; 256bf215546Sopenharmony_ci return 0; 257bf215546Sopenharmony_ci#endif 258bf215546Sopenharmony_ci} 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci/* Return the time of the current thread's CPU time clock. */ 261bf215546Sopenharmony_cistatic inline int64_t 262bf215546Sopenharmony_ciutil_current_thread_get_time_nano(void) 263bf215546Sopenharmony_ci{ 264bf215546Sopenharmony_ci#if defined(HAVE_PTHREAD) 265bf215546Sopenharmony_ci return util_thread_get_time_nano(pthread_self()); 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci#elif defined(_WIN32) && !defined(__CYGWIN__) 268bf215546Sopenharmony_ci /* The GetCurrentThreadId() handle is only valid within the current thread. */ 269bf215546Sopenharmony_ci return util_thread_get_time_nano(GetCurrentThread()); 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci#else 272bf215546Sopenharmony_ci return 0; 273bf215546Sopenharmony_ci#endif 274bf215546Sopenharmony_ci} 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_cistatic inline bool u_thread_is_self(thrd_t thread) 277bf215546Sopenharmony_ci{ 278bf215546Sopenharmony_ci#if defined(HAVE_PTHREAD) 279bf215546Sopenharmony_ci return pthread_equal(pthread_self(), thread); 280bf215546Sopenharmony_ci#endif 281bf215546Sopenharmony_ci return false; 282bf215546Sopenharmony_ci} 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci/* 285bf215546Sopenharmony_ci * util_barrier 286bf215546Sopenharmony_ci */ 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci#if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__) 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_citypedef pthread_barrier_t util_barrier; 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_cistatic inline void util_barrier_init(util_barrier *barrier, unsigned count) 293bf215546Sopenharmony_ci{ 294bf215546Sopenharmony_ci pthread_barrier_init(barrier, NULL, count); 295bf215546Sopenharmony_ci} 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_cistatic inline void util_barrier_destroy(util_barrier *barrier) 298bf215546Sopenharmony_ci{ 299bf215546Sopenharmony_ci pthread_barrier_destroy(barrier); 300bf215546Sopenharmony_ci} 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_cistatic inline bool util_barrier_wait(util_barrier *barrier) 303bf215546Sopenharmony_ci{ 304bf215546Sopenharmony_ci return pthread_barrier_wait(barrier) == PTHREAD_BARRIER_SERIAL_THREAD; 305bf215546Sopenharmony_ci} 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci#else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */ 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_citypedef struct { 311bf215546Sopenharmony_ci unsigned count; 312bf215546Sopenharmony_ci unsigned waiters; 313bf215546Sopenharmony_ci uint64_t sequence; 314bf215546Sopenharmony_ci mtx_t mutex; 315bf215546Sopenharmony_ci cnd_t condvar; 316bf215546Sopenharmony_ci} util_barrier; 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_cistatic inline void util_barrier_init(util_barrier *barrier, unsigned count) 319bf215546Sopenharmony_ci{ 320bf215546Sopenharmony_ci barrier->count = count; 321bf215546Sopenharmony_ci barrier->waiters = 0; 322bf215546Sopenharmony_ci barrier->sequence = 0; 323bf215546Sopenharmony_ci (void) mtx_init(&barrier->mutex, mtx_plain); 324bf215546Sopenharmony_ci cnd_init(&barrier->condvar); 325bf215546Sopenharmony_ci} 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_cistatic inline void util_barrier_destroy(util_barrier *barrier) 328bf215546Sopenharmony_ci{ 329bf215546Sopenharmony_ci assert(barrier->waiters == 0); 330bf215546Sopenharmony_ci mtx_destroy(&barrier->mutex); 331bf215546Sopenharmony_ci cnd_destroy(&barrier->condvar); 332bf215546Sopenharmony_ci} 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_cistatic inline bool util_barrier_wait(util_barrier *barrier) 335bf215546Sopenharmony_ci{ 336bf215546Sopenharmony_ci mtx_lock(&barrier->mutex); 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci assert(barrier->waiters < barrier->count); 339bf215546Sopenharmony_ci barrier->waiters++; 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci if (barrier->waiters < barrier->count) { 342bf215546Sopenharmony_ci uint64_t sequence = barrier->sequence; 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci do { 345bf215546Sopenharmony_ci cnd_wait(&barrier->condvar, &barrier->mutex); 346bf215546Sopenharmony_ci } while (sequence == barrier->sequence); 347bf215546Sopenharmony_ci } else { 348bf215546Sopenharmony_ci barrier->waiters = 0; 349bf215546Sopenharmony_ci barrier->sequence++; 350bf215546Sopenharmony_ci cnd_broadcast(&barrier->condvar); 351bf215546Sopenharmony_ci } 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci mtx_unlock(&barrier->mutex); 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci return true; 356bf215546Sopenharmony_ci} 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci#endif 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci/* 361bf215546Sopenharmony_ci * Thread-id's. 362bf215546Sopenharmony_ci * 363bf215546Sopenharmony_ci * thrd_current() is not portable to windows (or at least not in a desirable 364bf215546Sopenharmony_ci * way), so thread_id's provide an alternative mechanism 365bf215546Sopenharmony_ci */ 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci#ifdef _WIN32 368bf215546Sopenharmony_citypedef DWORD thread_id; 369bf215546Sopenharmony_ci#else 370bf215546Sopenharmony_citypedef thrd_t thread_id; 371bf215546Sopenharmony_ci#endif 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_cistatic inline thread_id 374bf215546Sopenharmony_ciutil_get_thread_id(void) 375bf215546Sopenharmony_ci{ 376bf215546Sopenharmony_ci /* 377bf215546Sopenharmony_ci * XXX: Callers of of this function assume it is a lightweight function. 378bf215546Sopenharmony_ci * But unfortunately C11's thrd_current() gives no such guarantees. In 379bf215546Sopenharmony_ci * fact, it's pretty hard to have a compliant implementation of 380bf215546Sopenharmony_ci * thrd_current() on Windows with such characteristics. So for now, we 381bf215546Sopenharmony_ci * side-step this mess and use Windows thread primitives directly here. 382bf215546Sopenharmony_ci */ 383bf215546Sopenharmony_ci#ifdef _WIN32 384bf215546Sopenharmony_ci return GetCurrentThreadId(); 385bf215546Sopenharmony_ci#else 386bf215546Sopenharmony_ci return thrd_current(); 387bf215546Sopenharmony_ci#endif 388bf215546Sopenharmony_ci} 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_cistatic inline int 392bf215546Sopenharmony_ciutil_thread_id_equal(thread_id t1, thread_id t2) 393bf215546Sopenharmony_ci{ 394bf215546Sopenharmony_ci#ifdef _WIN32 395bf215546Sopenharmony_ci return t1 == t2; 396bf215546Sopenharmony_ci#else 397bf215546Sopenharmony_ci return thrd_equal(t1, t2); 398bf215546Sopenharmony_ci#endif 399bf215546Sopenharmony_ci} 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci#endif /* U_THREAD_H_ */ 402