1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 1999-2006 Brian Paul
3*61046927SAndroid Build Coastguard Worker * Copyright 2008 VMware, Inc.
4*61046927SAndroid Build Coastguard Worker * Copyright 2022 Yonggang Luo
5*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
6*61046927SAndroid Build Coastguard Worker */
7*61046927SAndroid Build Coastguard Worker
8*61046927SAndroid Build Coastguard Worker #include "util/u_thread.h"
9*61046927SAndroid Build Coastguard Worker
10*61046927SAndroid Build Coastguard Worker #include "macros.h"
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
13*61046927SAndroid Build Coastguard Worker #include <signal.h>
14*61046927SAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD_NP_H
15*61046927SAndroid Build Coastguard Worker #include <pthread_np.h>
16*61046927SAndroid Build Coastguard Worker #endif
17*61046927SAndroid Build Coastguard Worker #endif
18*61046927SAndroid Build Coastguard Worker
19*61046927SAndroid Build Coastguard Worker #ifdef __HAIKU__
20*61046927SAndroid Build Coastguard Worker #include <OS.h>
21*61046927SAndroid Build Coastguard Worker #endif
22*61046927SAndroid Build Coastguard Worker
23*61046927SAndroid Build Coastguard Worker #if DETECT_OS_LINUX && !DETECT_OS_ANDROID
24*61046927SAndroid Build Coastguard Worker #include <sched.h>
25*61046927SAndroid Build Coastguard Worker #elif defined(_WIN32) && !defined(HAVE_PTHREAD)
26*61046927SAndroid Build Coastguard Worker #include <windows.h>
27*61046927SAndroid Build Coastguard Worker #endif
28*61046927SAndroid Build Coastguard Worker
29*61046927SAndroid Build Coastguard Worker #ifdef __FreeBSD__
30*61046927SAndroid Build Coastguard Worker /* pthread_np.h -> sys/param.h -> machine/param.h
31*61046927SAndroid Build Coastguard Worker * - defines ALIGN which clashes with our ALIGN
32*61046927SAndroid Build Coastguard Worker */
33*61046927SAndroid Build Coastguard Worker #undef ALIGN
34*61046927SAndroid Build Coastguard Worker #define cpu_set_t cpuset_t
35*61046927SAndroid Build Coastguard Worker #endif
36*61046927SAndroid Build Coastguard Worker
37*61046927SAndroid Build Coastguard Worker int
util_get_current_cpu(void)38*61046927SAndroid Build Coastguard Worker util_get_current_cpu(void)
39*61046927SAndroid Build Coastguard Worker {
40*61046927SAndroid Build Coastguard Worker #if DETECT_OS_LINUX && !DETECT_OS_ANDROID
41*61046927SAndroid Build Coastguard Worker return sched_getcpu();
42*61046927SAndroid Build Coastguard Worker
43*61046927SAndroid Build Coastguard Worker #elif defined(_WIN32) && !defined(HAVE_PTHREAD)
44*61046927SAndroid Build Coastguard Worker return GetCurrentProcessorNumber();
45*61046927SAndroid Build Coastguard Worker
46*61046927SAndroid Build Coastguard Worker #else
47*61046927SAndroid Build Coastguard Worker return -1;
48*61046927SAndroid Build Coastguard Worker #endif
49*61046927SAndroid Build Coastguard Worker }
50*61046927SAndroid Build Coastguard Worker
u_thread_create(thrd_t * thrd,int (* routine)(void *),void * param)51*61046927SAndroid Build Coastguard Worker int u_thread_create(thrd_t *thrd, int (*routine)(void *), void *param)
52*61046927SAndroid Build Coastguard Worker {
53*61046927SAndroid Build Coastguard Worker int ret = thrd_error;
54*61046927SAndroid Build Coastguard Worker #if defined(HAVE_PTHREAD) && !DETECT_OS_FUCHIA
55*61046927SAndroid Build Coastguard Worker sigset_t saved_set, new_set;
56*61046927SAndroid Build Coastguard Worker
57*61046927SAndroid Build Coastguard Worker sigfillset(&new_set);
58*61046927SAndroid Build Coastguard Worker sigdelset(&new_set, SIGSYS);
59*61046927SAndroid Build Coastguard Worker
60*61046927SAndroid Build Coastguard Worker /* SIGSEGV is commonly used by Vulkan API tracing layers in order to track
61*61046927SAndroid Build Coastguard Worker * accesses in device memory mapped to user space. Blocking the signal hinders
62*61046927SAndroid Build Coastguard Worker * that tracking mechanism.
63*61046927SAndroid Build Coastguard Worker */
64*61046927SAndroid Build Coastguard Worker sigdelset(&new_set, SIGSEGV);
65*61046927SAndroid Build Coastguard Worker pthread_sigmask(SIG_BLOCK, &new_set, &saved_set);
66*61046927SAndroid Build Coastguard Worker ret = thrd_create(thrd, routine, param);
67*61046927SAndroid Build Coastguard Worker pthread_sigmask(SIG_SETMASK, &saved_set, NULL);
68*61046927SAndroid Build Coastguard Worker #else
69*61046927SAndroid Build Coastguard Worker ret = thrd_create(thrd, routine, param);
70*61046927SAndroid Build Coastguard Worker #endif
71*61046927SAndroid Build Coastguard Worker
72*61046927SAndroid Build Coastguard Worker return ret;
73*61046927SAndroid Build Coastguard Worker }
74*61046927SAndroid Build Coastguard Worker
u_thread_setname(const char * name)75*61046927SAndroid Build Coastguard Worker void u_thread_setname( const char *name )
76*61046927SAndroid Build Coastguard Worker {
77*61046927SAndroid Build Coastguard Worker #if defined(HAVE_PTHREAD)
78*61046927SAndroid Build Coastguard Worker #if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || defined(__GLIBC__) || DETECT_OS_MANAGARM || DETECT_OS_FUCHSIA
79*61046927SAndroid Build Coastguard Worker int ret = pthread_setname_np(pthread_self(), name);
80*61046927SAndroid Build Coastguard Worker if (ret == ERANGE) {
81*61046927SAndroid Build Coastguard Worker char buf[16];
82*61046927SAndroid Build Coastguard Worker const size_t len = MIN2(strlen(name), ARRAY_SIZE(buf) - 1);
83*61046927SAndroid Build Coastguard Worker memcpy(buf, name, len);
84*61046927SAndroid Build Coastguard Worker buf[len] = '\0';
85*61046927SAndroid Build Coastguard Worker pthread_setname_np(pthread_self(), buf);
86*61046927SAndroid Build Coastguard Worker }
87*61046927SAndroid Build Coastguard Worker #elif DETECT_OS_FREEBSD || DETECT_OS_OPENBSD
88*61046927SAndroid Build Coastguard Worker pthread_set_name_np(pthread_self(), name);
89*61046927SAndroid Build Coastguard Worker #elif DETECT_OS_NETBSD
90*61046927SAndroid Build Coastguard Worker pthread_setname_np(pthread_self(), "%s", (void *)name);
91*61046927SAndroid Build Coastguard Worker #elif DETECT_OS_APPLE
92*61046927SAndroid Build Coastguard Worker pthread_setname_np(name);
93*61046927SAndroid Build Coastguard Worker #elif DETECT_OS_HAIKU
94*61046927SAndroid Build Coastguard Worker rename_thread(find_thread(NULL), name);
95*61046927SAndroid Build Coastguard Worker #else
96*61046927SAndroid Build Coastguard Worker #warning Not sure how to call pthread_setname_np
97*61046927SAndroid Build Coastguard Worker #endif
98*61046927SAndroid Build Coastguard Worker #endif
99*61046927SAndroid Build Coastguard Worker (void)name;
100*61046927SAndroid Build Coastguard Worker }
101*61046927SAndroid Build Coastguard Worker
102*61046927SAndroid Build Coastguard Worker bool
util_set_thread_affinity(thrd_t thread,const uint32_t * mask,uint32_t * old_mask,unsigned num_mask_bits)103*61046927SAndroid Build Coastguard Worker util_set_thread_affinity(thrd_t thread,
104*61046927SAndroid Build Coastguard Worker const uint32_t *mask,
105*61046927SAndroid Build Coastguard Worker uint32_t *old_mask,
106*61046927SAndroid Build Coastguard Worker unsigned num_mask_bits)
107*61046927SAndroid Build Coastguard Worker {
108*61046927SAndroid Build Coastguard Worker #if defined(HAVE_PTHREAD_SETAFFINITY)
109*61046927SAndroid Build Coastguard Worker cpu_set_t cpuset;
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker if (old_mask) {
112*61046927SAndroid Build Coastguard Worker if (pthread_getaffinity_np(thread, sizeof(cpuset), &cpuset) != 0)
113*61046927SAndroid Build Coastguard Worker return false;
114*61046927SAndroid Build Coastguard Worker
115*61046927SAndroid Build Coastguard Worker memset(old_mask, 0, num_mask_bits / 8);
116*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_mask_bits && i < CPU_SETSIZE; i++) {
117*61046927SAndroid Build Coastguard Worker if (CPU_ISSET(i, &cpuset))
118*61046927SAndroid Build Coastguard Worker old_mask[i / 32] |= 1u << (i % 32);
119*61046927SAndroid Build Coastguard Worker }
120*61046927SAndroid Build Coastguard Worker }
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker CPU_ZERO(&cpuset);
123*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_mask_bits && i < CPU_SETSIZE; i++) {
124*61046927SAndroid Build Coastguard Worker if (mask[i / 32] & (1u << (i % 32)))
125*61046927SAndroid Build Coastguard Worker CPU_SET(i, &cpuset);
126*61046927SAndroid Build Coastguard Worker }
127*61046927SAndroid Build Coastguard Worker return pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset) == 0;
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker #elif defined(_WIN32) && !defined(HAVE_PTHREAD)
130*61046927SAndroid Build Coastguard Worker DWORD_PTR m = mask[0];
131*61046927SAndroid Build Coastguard Worker
132*61046927SAndroid Build Coastguard Worker if (sizeof(m) > 4 && num_mask_bits > 32)
133*61046927SAndroid Build Coastguard Worker m |= (uint64_t)mask[1] << 32;
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker m = SetThreadAffinityMask(thread.handle, m);
136*61046927SAndroid Build Coastguard Worker if (!m)
137*61046927SAndroid Build Coastguard Worker return false;
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker if (old_mask) {
140*61046927SAndroid Build Coastguard Worker memset(old_mask, 0, num_mask_bits / 8);
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker old_mask[0] = m;
143*61046927SAndroid Build Coastguard Worker #ifdef _WIN64
144*61046927SAndroid Build Coastguard Worker old_mask[1] = m >> 32;
145*61046927SAndroid Build Coastguard Worker #endif
146*61046927SAndroid Build Coastguard Worker }
147*61046927SAndroid Build Coastguard Worker
148*61046927SAndroid Build Coastguard Worker return true;
149*61046927SAndroid Build Coastguard Worker #else
150*61046927SAndroid Build Coastguard Worker return false;
151*61046927SAndroid Build Coastguard Worker #endif
152*61046927SAndroid Build Coastguard Worker }
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker int64_t
util_thread_get_time_nano(thrd_t thread)155*61046927SAndroid Build Coastguard Worker util_thread_get_time_nano(thrd_t thread)
156*61046927SAndroid Build Coastguard Worker {
157*61046927SAndroid Build Coastguard Worker #if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__) && !defined(__managarm__)
158*61046927SAndroid Build Coastguard Worker struct timespec ts;
159*61046927SAndroid Build Coastguard Worker clockid_t cid;
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker pthread_getcpuclockid(thread, &cid);
162*61046927SAndroid Build Coastguard Worker clock_gettime(cid, &ts);
163*61046927SAndroid Build Coastguard Worker return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
164*61046927SAndroid Build Coastguard Worker #elif defined(_WIN32)
165*61046927SAndroid Build Coastguard Worker union {
166*61046927SAndroid Build Coastguard Worker FILETIME time;
167*61046927SAndroid Build Coastguard Worker ULONGLONG value;
168*61046927SAndroid Build Coastguard Worker } kernel_time, user_time;
169*61046927SAndroid Build Coastguard Worker GetThreadTimes((HANDLE)thread.handle, NULL, NULL, &kernel_time.time, &user_time.time);
170*61046927SAndroid Build Coastguard Worker return (kernel_time.value + user_time.value) * 100;
171*61046927SAndroid Build Coastguard Worker #else
172*61046927SAndroid Build Coastguard Worker (void)thread;
173*61046927SAndroid Build Coastguard Worker return 0;
174*61046927SAndroid Build Coastguard Worker #endif
175*61046927SAndroid Build Coastguard Worker }
176*61046927SAndroid Build Coastguard Worker
177*61046927SAndroid Build Coastguard Worker #if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__)
178*61046927SAndroid Build Coastguard Worker
util_barrier_init(util_barrier * barrier,unsigned count)179*61046927SAndroid Build Coastguard Worker void util_barrier_init(util_barrier *barrier, unsigned count)
180*61046927SAndroid Build Coastguard Worker {
181*61046927SAndroid Build Coastguard Worker pthread_barrier_init(barrier, NULL, count);
182*61046927SAndroid Build Coastguard Worker }
183*61046927SAndroid Build Coastguard Worker
util_barrier_destroy(util_barrier * barrier)184*61046927SAndroid Build Coastguard Worker void util_barrier_destroy(util_barrier *barrier)
185*61046927SAndroid Build Coastguard Worker {
186*61046927SAndroid Build Coastguard Worker pthread_barrier_destroy(barrier);
187*61046927SAndroid Build Coastguard Worker }
188*61046927SAndroid Build Coastguard Worker
util_barrier_wait(util_barrier * barrier)189*61046927SAndroid Build Coastguard Worker bool util_barrier_wait(util_barrier *barrier)
190*61046927SAndroid Build Coastguard Worker {
191*61046927SAndroid Build Coastguard Worker return pthread_barrier_wait(barrier) == PTHREAD_BARRIER_SERIAL_THREAD;
192*61046927SAndroid Build Coastguard Worker }
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker #else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */
195*61046927SAndroid Build Coastguard Worker
util_barrier_init(util_barrier * barrier,unsigned count)196*61046927SAndroid Build Coastguard Worker void util_barrier_init(util_barrier *barrier, unsigned count)
197*61046927SAndroid Build Coastguard Worker {
198*61046927SAndroid Build Coastguard Worker barrier->count = count;
199*61046927SAndroid Build Coastguard Worker barrier->waiters = 0;
200*61046927SAndroid Build Coastguard Worker barrier->sequence = 0;
201*61046927SAndroid Build Coastguard Worker (void) mtx_init(&barrier->mutex, mtx_plain);
202*61046927SAndroid Build Coastguard Worker cnd_init(&barrier->condvar);
203*61046927SAndroid Build Coastguard Worker }
204*61046927SAndroid Build Coastguard Worker
util_barrier_destroy(util_barrier * barrier)205*61046927SAndroid Build Coastguard Worker void util_barrier_destroy(util_barrier *barrier)
206*61046927SAndroid Build Coastguard Worker {
207*61046927SAndroid Build Coastguard Worker assert(barrier->waiters == 0);
208*61046927SAndroid Build Coastguard Worker mtx_destroy(&barrier->mutex);
209*61046927SAndroid Build Coastguard Worker cnd_destroy(&barrier->condvar);
210*61046927SAndroid Build Coastguard Worker }
211*61046927SAndroid Build Coastguard Worker
util_barrier_wait(util_barrier * barrier)212*61046927SAndroid Build Coastguard Worker bool util_barrier_wait(util_barrier *barrier)
213*61046927SAndroid Build Coastguard Worker {
214*61046927SAndroid Build Coastguard Worker mtx_lock(&barrier->mutex);
215*61046927SAndroid Build Coastguard Worker
216*61046927SAndroid Build Coastguard Worker assert(barrier->waiters < barrier->count);
217*61046927SAndroid Build Coastguard Worker barrier->waiters++;
218*61046927SAndroid Build Coastguard Worker
219*61046927SAndroid Build Coastguard Worker if (barrier->waiters < barrier->count) {
220*61046927SAndroid Build Coastguard Worker uint64_t sequence = barrier->sequence;
221*61046927SAndroid Build Coastguard Worker
222*61046927SAndroid Build Coastguard Worker do {
223*61046927SAndroid Build Coastguard Worker cnd_wait(&barrier->condvar, &barrier->mutex);
224*61046927SAndroid Build Coastguard Worker } while (sequence == barrier->sequence);
225*61046927SAndroid Build Coastguard Worker } else {
226*61046927SAndroid Build Coastguard Worker barrier->waiters = 0;
227*61046927SAndroid Build Coastguard Worker barrier->sequence++;
228*61046927SAndroid Build Coastguard Worker cnd_broadcast(&barrier->condvar);
229*61046927SAndroid Build Coastguard Worker }
230*61046927SAndroid Build Coastguard Worker
231*61046927SAndroid Build Coastguard Worker mtx_unlock(&barrier->mutex);
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Worker return true;
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Worker #endif
237