1 /************************************************************************** 2 * 3 * Copyright 1999-2006 Brian Paul 4 * Copyright 2008 VMware, Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27 28 /** 29 * @file 30 * 31 * Thread, mutex, condition variable, barrier, semaphore and 32 * thread-specific data functions. 33 */ 34 35 36 #ifndef OS_THREAD_H_ 37 #define OS_THREAD_H_ 38 39 40 #include "pipe/p_compiler.h" 41 #include "util/u_debug.h" /* for assert */ 42 43 #include "c11/threads.h" 44 45 #ifdef HAVE_PTHREAD 46 #include <signal.h> 47 #endif 48 49 50 /* pipe_thread 51 */ 52 typedef thrd_t pipe_thread; 53 54 #define PIPE_THREAD_ROUTINE( name, param ) \ 55 int name( void *param ) 56 57 static inline pipe_thread pipe_thread_create( PIPE_THREAD_ROUTINE((*routine), ), void *param ) 58 { 59 pipe_thread thread; 60 #ifdef HAVE_PTHREAD 61 sigset_t saved_set, new_set; 62 int ret; 63 64 sigfillset(&new_set); 65 pthread_sigmask(SIG_SETMASK, &new_set, &saved_set); 66 ret = thrd_create( &thread, routine, param ); 67 pthread_sigmask(SIG_SETMASK, &saved_set, NULL); 68 #else 69 int ret; 70 ret = thrd_create( &thread, routine, param ); 71 #endif 72 if (ret) 73 return 0; 74 75 return thread; 76 } 77 78 static inline int pipe_thread_wait( pipe_thread thread ) 79 { 80 return thrd_join( thread, NULL ); 81 } 82 83 static inline int pipe_thread_destroy( pipe_thread thread ) 84 { 85 return thrd_detach( thread ); 86 } 87 88 static inline void pipe_thread_setname( const char *name ) 89 { 90 #if defined(HAVE_PTHREAD) 91 # if defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && \ 92 (__GLIBC__ >= 3 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 12)) 93 pthread_setname_np(pthread_self(), name); 94 # endif 95 #endif 96 (void)name; 97 } 98 99 100 static inline int pipe_thread_is_self( pipe_thread thread ) 101 { 102 #if defined(HAVE_PTHREAD) 103 # if defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && \ 104 (__GLIBC__ >= 3 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 12)) 105 return pthread_equal(pthread_self(), thread); 106 # endif 107 #endif 108 return 0; 109 } 110 111 /* pipe_mutex 112 */ 113 typedef mtx_t pipe_mutex; 114 115 #define pipe_static_mutex(mutex) \ 116 static pipe_mutex mutex = _MTX_INITIALIZER_NP 117 118 #define pipe_mutex_init(mutex) \ 119 (void) mtx_init(&(mutex), mtx_plain) 120 121 #define pipe_mutex_destroy(mutex) \ 122 mtx_destroy(&(mutex)) 123 124 #define pipe_mutex_lock(mutex) \ 125 (void) mtx_lock(&(mutex)) 126 127 #define pipe_mutex_unlock(mutex) \ 128 (void) mtx_unlock(&(mutex)) 129 130 #define pipe_mutex_assert_locked(mutex) \ 131 __pipe_mutex_assert_locked(&(mutex)) 132 133 static inline void 134 __pipe_mutex_assert_locked(pipe_mutex *mutex) 135 { 136 #ifdef DEBUG 137 /* NOTE: this would not work for recursive mutexes, but 138 * pipe_mutex doesn't support those 139 */ 140 int ret = mtx_trylock(mutex); 141 assert(ret == thrd_busy); 142 if (ret == thrd_success) 143 mtx_unlock(mutex); 144 #endif 145 } 146 147 /* pipe_condvar 148 */ 149 typedef cnd_t pipe_condvar; 150 151 #define pipe_condvar_init(cond) \ 152 cnd_init(&(cond)) 153 154 #define pipe_condvar_destroy(cond) \ 155 cnd_destroy(&(cond)) 156 157 #define pipe_condvar_wait(cond, mutex) \ 158 cnd_wait(&(cond), &(mutex)) 159 160 #define pipe_condvar_signal(cond) \ 161 cnd_signal(&(cond)) 162 163 #define pipe_condvar_broadcast(cond) \ 164 cnd_broadcast(&(cond)) 165 166 167 /* 168 * pipe_barrier 169 */ 170 171 #if (defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_HURD)) && !defined(PIPE_OS_ANDROID) 172 173 typedef pthread_barrier_t pipe_barrier; 174 175 static inline void pipe_barrier_init(pipe_barrier *barrier, unsigned count) 176 { 177 pthread_barrier_init(barrier, NULL, count); 178 } 179 180 static inline void pipe_barrier_destroy(pipe_barrier *barrier) 181 { 182 pthread_barrier_destroy(barrier); 183 } 184 185 static inline void pipe_barrier_wait(pipe_barrier *barrier) 186 { 187 pthread_barrier_wait(barrier); 188 } 189 190 191 #else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */ 192 193 typedef struct { 194 unsigned count; 195 unsigned waiters; 196 uint64_t sequence; 197 pipe_mutex mutex; 198 pipe_condvar condvar; 199 } pipe_barrier; 200 201 static inline void pipe_barrier_init(pipe_barrier *barrier, unsigned count) 202 { 203 barrier->count = count; 204 barrier->waiters = 0; 205 barrier->sequence = 0; 206 pipe_mutex_init(barrier->mutex); 207 pipe_condvar_init(barrier->condvar); 208 } 209 210 static inline void pipe_barrier_destroy(pipe_barrier *barrier) 211 { 212 assert(barrier->waiters == 0); 213 pipe_mutex_destroy(barrier->mutex); 214 pipe_condvar_destroy(barrier->condvar); 215 } 216 217 static inline void pipe_barrier_wait(pipe_barrier *barrier) 218 { 219 pipe_mutex_lock(barrier->mutex); 220 221 assert(barrier->waiters < barrier->count); 222 barrier->waiters++; 223 224 if (barrier->waiters < barrier->count) { 225 uint64_t sequence = barrier->sequence; 226 227 do { 228 pipe_condvar_wait(barrier->condvar, barrier->mutex); 229 } while (sequence == barrier->sequence); 230 } else { 231 barrier->waiters = 0; 232 barrier->sequence++; 233 pipe_condvar_broadcast(barrier->condvar); 234 } 235 236 pipe_mutex_unlock(barrier->mutex); 237 } 238 239 240 #endif 241 242 243 /* 244 * Semaphores 245 */ 246 247 typedef struct 248 { 249 pipe_mutex mutex; 250 pipe_condvar cond; 251 int counter; 252 } pipe_semaphore; 253 254 255 static inline void 256 pipe_semaphore_init(pipe_semaphore *sema, int init_val) 257 { 258 pipe_mutex_init(sema->mutex); 259 pipe_condvar_init(sema->cond); 260 sema->counter = init_val; 261 } 262 263 static inline void 264 pipe_semaphore_destroy(pipe_semaphore *sema) 265 { 266 pipe_mutex_destroy(sema->mutex); 267 pipe_condvar_destroy(sema->cond); 268 } 269 270 /** Signal/increment semaphore counter */ 271 static inline void 272 pipe_semaphore_signal(pipe_semaphore *sema) 273 { 274 pipe_mutex_lock(sema->mutex); 275 sema->counter++; 276 pipe_condvar_signal(sema->cond); 277 pipe_mutex_unlock(sema->mutex); 278 } 279 280 /** Wait for semaphore counter to be greater than zero */ 281 static inline void 282 pipe_semaphore_wait(pipe_semaphore *sema) 283 { 284 pipe_mutex_lock(sema->mutex); 285 while (sema->counter <= 0) { 286 pipe_condvar_wait(sema->cond, sema->mutex); 287 } 288 sema->counter--; 289 pipe_mutex_unlock(sema->mutex); 290 } 291 292 293 294 /* 295 * Thread-specific data. 296 */ 297 298 typedef struct { 299 tss_t key; 300 int initMagic; 301 } pipe_tsd; 302 303 304 #define PIPE_TSD_INIT_MAGIC 0xff8adc98 305 306 307 static inline void 308 pipe_tsd_init(pipe_tsd *tsd) 309 { 310 if (tss_create(&tsd->key, NULL/*free*/) != 0) { 311 exit(-1); 312 } 313 tsd->initMagic = PIPE_TSD_INIT_MAGIC; 314 } 315 316 static inline void * 317 pipe_tsd_get(pipe_tsd *tsd) 318 { 319 if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) { 320 pipe_tsd_init(tsd); 321 } 322 return tss_get(tsd->key); 323 } 324 325 static inline void 326 pipe_tsd_set(pipe_tsd *tsd, void *value) 327 { 328 if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) { 329 pipe_tsd_init(tsd); 330 } 331 if (tss_set(tsd->key, value) != 0) { 332 exit(-1); 333 } 334 } 335 336 337 338 #endif /* OS_THREAD_H_ */ 339