os_thread.h revision 848b8605
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 */ 52typedef thrd_t pipe_thread; 53 54#define PIPE_THREAD_ROUTINE( name, param ) \ 55 int name( void *param ) 56 57static 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 78static INLINE int pipe_thread_wait( pipe_thread thread ) 79{ 80 return thrd_join( thread, NULL ); 81} 82 83static INLINE int pipe_thread_destroy( pipe_thread thread ) 84{ 85 return thrd_detach( thread ); 86} 87 88 89/* pipe_mutex 90 */ 91typedef mtx_t pipe_mutex; 92 93#define pipe_static_mutex(mutex) \ 94 static pipe_mutex mutex = _MTX_INITIALIZER_NP 95 96#define pipe_mutex_init(mutex) \ 97 (void) mtx_init(&(mutex), mtx_plain) 98 99#define pipe_mutex_destroy(mutex) \ 100 mtx_destroy(&(mutex)) 101 102#define pipe_mutex_lock(mutex) \ 103 (void) mtx_lock(&(mutex)) 104 105#define pipe_mutex_unlock(mutex) \ 106 (void) mtx_unlock(&(mutex)) 107 108 109/* pipe_condvar 110 */ 111typedef cnd_t pipe_condvar; 112 113#define pipe_condvar_init(cond) \ 114 cnd_init(&(cond)) 115 116#define pipe_condvar_destroy(cond) \ 117 cnd_destroy(&(cond)) 118 119#define pipe_condvar_wait(cond, mutex) \ 120 cnd_wait(&(cond), &(mutex)) 121 122#define pipe_condvar_signal(cond) \ 123 cnd_signal(&(cond)) 124 125#define pipe_condvar_broadcast(cond) \ 126 cnd_broadcast(&(cond)) 127 128 129/* 130 * pipe_barrier 131 */ 132 133#if (defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_HURD)) && !defined(PIPE_OS_ANDROID) 134 135typedef pthread_barrier_t pipe_barrier; 136 137static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count) 138{ 139 pthread_barrier_init(barrier, NULL, count); 140} 141 142static INLINE void pipe_barrier_destroy(pipe_barrier *barrier) 143{ 144 pthread_barrier_destroy(barrier); 145} 146 147static INLINE void pipe_barrier_wait(pipe_barrier *barrier) 148{ 149 pthread_barrier_wait(barrier); 150} 151 152 153#else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */ 154 155typedef struct { 156 unsigned count; 157 unsigned waiters; 158 uint64_t sequence; 159 pipe_mutex mutex; 160 pipe_condvar condvar; 161} pipe_barrier; 162 163static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count) 164{ 165 barrier->count = count; 166 barrier->waiters = 0; 167 barrier->sequence = 0; 168 pipe_mutex_init(barrier->mutex); 169 pipe_condvar_init(barrier->condvar); 170} 171 172static INLINE void pipe_barrier_destroy(pipe_barrier *barrier) 173{ 174 assert(barrier->waiters == 0); 175 pipe_mutex_destroy(barrier->mutex); 176 pipe_condvar_destroy(barrier->condvar); 177} 178 179static INLINE void pipe_barrier_wait(pipe_barrier *barrier) 180{ 181 pipe_mutex_lock(barrier->mutex); 182 183 assert(barrier->waiters < barrier->count); 184 barrier->waiters++; 185 186 if (barrier->waiters < barrier->count) { 187 uint64_t sequence = barrier->sequence; 188 189 do { 190 pipe_condvar_wait(barrier->condvar, barrier->mutex); 191 } while (sequence == barrier->sequence); 192 } else { 193 barrier->waiters = 0; 194 barrier->sequence++; 195 pipe_condvar_broadcast(barrier->condvar); 196 } 197 198 pipe_mutex_unlock(barrier->mutex); 199} 200 201 202#endif 203 204 205/* 206 * Semaphores 207 */ 208 209typedef struct 210{ 211 pipe_mutex mutex; 212 pipe_condvar cond; 213 int counter; 214} pipe_semaphore; 215 216 217static INLINE void 218pipe_semaphore_init(pipe_semaphore *sema, int init_val) 219{ 220 pipe_mutex_init(sema->mutex); 221 pipe_condvar_init(sema->cond); 222 sema->counter = init_val; 223} 224 225static INLINE void 226pipe_semaphore_destroy(pipe_semaphore *sema) 227{ 228 pipe_mutex_destroy(sema->mutex); 229 pipe_condvar_destroy(sema->cond); 230} 231 232/** Signal/increment semaphore counter */ 233static INLINE void 234pipe_semaphore_signal(pipe_semaphore *sema) 235{ 236 pipe_mutex_lock(sema->mutex); 237 sema->counter++; 238 pipe_condvar_signal(sema->cond); 239 pipe_mutex_unlock(sema->mutex); 240} 241 242/** Wait for semaphore counter to be greater than zero */ 243static INLINE void 244pipe_semaphore_wait(pipe_semaphore *sema) 245{ 246 pipe_mutex_lock(sema->mutex); 247 while (sema->counter <= 0) { 248 pipe_condvar_wait(sema->cond, sema->mutex); 249 } 250 sema->counter--; 251 pipe_mutex_unlock(sema->mutex); 252} 253 254 255 256/* 257 * Thread-specific data. 258 */ 259 260typedef struct { 261 tss_t key; 262 int initMagic; 263} pipe_tsd; 264 265 266#define PIPE_TSD_INIT_MAGIC 0xff8adc98 267 268 269static INLINE void 270pipe_tsd_init(pipe_tsd *tsd) 271{ 272 if (tss_create(&tsd->key, NULL/*free*/) != 0) { 273 exit(-1); 274 } 275 tsd->initMagic = PIPE_TSD_INIT_MAGIC; 276} 277 278static INLINE void * 279pipe_tsd_get(pipe_tsd *tsd) 280{ 281 if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) { 282 pipe_tsd_init(tsd); 283 } 284 return tss_get(tsd->key); 285} 286 287static INLINE void 288pipe_tsd_set(pipe_tsd *tsd, void *value) 289{ 290 if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) { 291 pipe_tsd_init(tsd); 292 } 293 if (tss_set(tsd->key, value) != 0) { 294 exit(-1); 295 } 296} 297 298 299 300#endif /* OS_THREAD_H_ */ 301