Home | History | Annotate | Download | only in os
      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