Home | History | Annotate | Download | only in os
      1 /**************************************************************************
      2  *
      3  * Copyright 1999-2006 Brian Paul
      4  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      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  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  **************************************************************************/
     25 
     26 
     27 /**
     28  * @file
     29  *
     30  * Thread, mutex, condition variable, barrier, semaphore and
     31  * thread-specific data functions.
     32  */
     33 
     34 
     35 #ifndef OS_THREAD_H_
     36 #define OS_THREAD_H_
     37 
     38 
     39 #include "pipe/p_compiler.h"
     40 #include "util/u_debug.h" /* for assert */
     41 
     42 
     43 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN)
     44 
     45 #include <pthread.h> /* POSIX threads headers */
     46 #include <stdio.h> /* for perror() */
     47 #include <signal.h>
     48 
     49 
     50 /* pipe_thread
     51  */
     52 typedef pthread_t pipe_thread;
     53 
     54 #define PIPE_THREAD_ROUTINE( name, param ) \
     55    void *name( void *param )
     56 
     57 static INLINE pipe_thread pipe_thread_create( void *(* routine)( void *), void *param )
     58 {
     59    pipe_thread thread;
     60    sigset_t saved_set, new_set;
     61    int ret;
     62 
     63    sigfillset(&new_set);
     64    pthread_sigmask(SIG_SETMASK, &new_set, &saved_set);
     65    ret = pthread_create( &thread, NULL, routine, param );
     66    pthread_sigmask(SIG_SETMASK, &saved_set, NULL);
     67    if (ret)
     68       return 0;
     69    return thread;
     70 }
     71 
     72 static INLINE int pipe_thread_wait( pipe_thread thread )
     73 {
     74    return pthread_join( thread, NULL );
     75 }
     76 
     77 static INLINE int pipe_thread_destroy( pipe_thread thread )
     78 {
     79    return pthread_detach( thread );
     80 }
     81 
     82 
     83 /* pipe_mutex
     84  */
     85 typedef pthread_mutex_t pipe_mutex;
     86 
     87 #define pipe_static_mutex(mutex) \
     88    static pipe_mutex mutex = PTHREAD_MUTEX_INITIALIZER
     89 
     90 #define pipe_mutex_init(mutex) \
     91    (void) pthread_mutex_init(&(mutex), NULL)
     92 
     93 #define pipe_mutex_destroy(mutex) \
     94    pthread_mutex_destroy(&(mutex))
     95 
     96 #define pipe_mutex_lock(mutex) \
     97    (void) pthread_mutex_lock(&(mutex))
     98 
     99 #define pipe_mutex_unlock(mutex) \
    100    (void) pthread_mutex_unlock(&(mutex))
    101 
    102 
    103 /* pipe_condvar
    104  */
    105 typedef pthread_cond_t pipe_condvar;
    106 
    107 #define pipe_static_condvar(mutex) \
    108    static pipe_condvar mutex = PTHREAD_COND_INITIALIZER
    109 
    110 #define pipe_condvar_init(cond)	\
    111    pthread_cond_init(&(cond), NULL)
    112 
    113 #define pipe_condvar_destroy(cond) \
    114    pthread_cond_destroy(&(cond))
    115 
    116 #define pipe_condvar_wait(cond, mutex) \
    117   pthread_cond_wait(&(cond), &(mutex))
    118 
    119 #define pipe_condvar_signal(cond) \
    120   pthread_cond_signal(&(cond))
    121 
    122 #define pipe_condvar_broadcast(cond) \
    123   pthread_cond_broadcast(&(cond))
    124 
    125 
    126 
    127 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
    128 
    129 #include <windows.h>
    130 
    131 /* pipe_thread
    132  */
    133 typedef HANDLE pipe_thread;
    134 
    135 #define PIPE_THREAD_ROUTINE( name, param ) \
    136    void * WINAPI name( void *param )
    137 
    138 static INLINE pipe_thread pipe_thread_create( void *(WINAPI * routine)( void *), void *param )
    139 {
    140    DWORD id;
    141    return CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) routine, param, 0, &id );
    142 }
    143 
    144 static INLINE int pipe_thread_wait( pipe_thread thread )
    145 {
    146    if (WaitForSingleObject( thread, INFINITE ) == WAIT_OBJECT_0)
    147       return 0;
    148    return -1;
    149 }
    150 
    151 static INLINE int pipe_thread_destroy( pipe_thread thread )
    152 {
    153    if (CloseHandle( thread ))
    154       return 0;
    155    return -1;
    156 }
    157 
    158 
    159 /* pipe_mutex
    160  */
    161 typedef CRITICAL_SECTION pipe_mutex;
    162 
    163 /* http://locklessinc.com/articles/pthreads_on_windows/ */
    164 #define pipe_static_mutex(mutex) \
    165    static pipe_mutex mutex = {(PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0}
    166 
    167 #define pipe_mutex_init(mutex) \
    168    InitializeCriticalSection(&mutex)
    169 
    170 #define pipe_mutex_destroy(mutex) \
    171    DeleteCriticalSection(&mutex)
    172 
    173 #define pipe_mutex_lock(mutex) \
    174    EnterCriticalSection(&mutex)
    175 
    176 #define pipe_mutex_unlock(mutex) \
    177    LeaveCriticalSection(&mutex)
    178 
    179 /* TODO: Need a macro to declare "I don't care about WinXP compatibilty" */
    180 #if 0 && defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
    181 /* CONDITION_VARIABLE is only available on newer versions of Windows
    182  * (Server 2008/Vista or later).
    183  * http://msdn.microsoft.com/en-us/library/ms682052(VS.85).aspx
    184  *
    185  * pipe_condvar
    186  */
    187 typedef CONDITION_VARIABLE pipe_condvar;
    188 
    189 #define pipe_static_condvar(cond) \
    190    /*static*/ pipe_condvar cond = CONDITION_VARIABLE_INIT
    191 
    192 #define pipe_condvar_init(cond) \
    193    InitializeConditionVariable(&(cond))
    194 
    195 #define pipe_condvar_destroy(cond) \
    196    (void) cond /* nothing to do */
    197 
    198 #define pipe_condvar_wait(cond, mutex) \
    199    SleepConditionVariableCS(&(cond), &(mutex), INFINITE)
    200 
    201 #define pipe_condvar_signal(cond) \
    202    WakeConditionVariable(&(cond))
    203 
    204 #define pipe_condvar_broadcast(cond) \
    205    WakeAllConditionVariable(&(cond))
    206 
    207 #else /* need compatibility with pre-Vista Win32 */
    208 
    209 /* pipe_condvar (XXX FIX THIS)
    210  * See http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
    211  * for potential pitfalls in implementation.
    212  */
    213 typedef DWORD pipe_condvar;
    214 
    215 #define pipe_static_condvar(cond) \
    216    /*static*/ pipe_condvar cond = 1
    217 
    218 #define pipe_condvar_init(cond) \
    219    (void) (cond = 1)
    220 
    221 #define pipe_condvar_destroy(cond) \
    222    (void) cond
    223 
    224 /* Poor man's pthread_cond_wait():
    225    Just release the mutex and sleep for one millisecond.
    226    The caller's while() loop does all the work. */
    227 #define pipe_condvar_wait(cond, mutex) \
    228    do { pipe_mutex_unlock(mutex); \
    229         Sleep(cond); \
    230         pipe_mutex_lock(mutex); \
    231    } while (0)
    232 
    233 #define pipe_condvar_signal(cond) \
    234    (void) cond
    235 
    236 #define pipe_condvar_broadcast(cond) \
    237    (void) cond
    238 
    239 #endif /* pre-Vista win32 */
    240 
    241 #else
    242 
    243 #include "os/os_time.h"
    244 
    245 /** Dummy definitions */
    246 
    247 typedef unsigned pipe_thread;
    248 
    249 #define PIPE_THREAD_ROUTINE( name, param ) \
    250    void * name( void *param )
    251 
    252 static INLINE pipe_thread pipe_thread_create( void *(* routine)( void *), void *param )
    253 {
    254    return 0;
    255 }
    256 
    257 static INLINE int pipe_thread_wait( pipe_thread thread )
    258 {
    259    return -1;
    260 }
    261 
    262 static INLINE int pipe_thread_destroy( pipe_thread thread )
    263 {
    264    return -1;
    265 }
    266 
    267 typedef unsigned pipe_mutex;
    268 
    269 #define pipe_static_mutex(mutex) \
    270    static pipe_mutex mutex = 0
    271 
    272 #define pipe_mutex_init(mutex) \
    273    (void) mutex
    274 
    275 #define pipe_mutex_destroy(mutex) \
    276    (void) mutex
    277 
    278 #define pipe_mutex_lock(mutex) \
    279    (void) mutex
    280 
    281 #define pipe_mutex_unlock(mutex) \
    282    (void) mutex
    283 
    284 typedef int64_t pipe_condvar;
    285 
    286 #define pipe_static_condvar(condvar) \
    287    static pipe_condvar condvar = 1000
    288 
    289 #define pipe_condvar_init(condvar) \
    290    (void) (condvar = 1000)
    291 
    292 #define pipe_condvar_destroy(condvar) \
    293    (void) condvar
    294 
    295 /* Poor man's pthread_cond_wait():
    296    Just release the mutex and sleep for one millisecond.
    297    The caller's while() loop does all the work. */
    298 #define pipe_condvar_wait(condvar, mutex) \
    299    do { pipe_mutex_unlock(mutex); \
    300         os_time_sleep(condvar); \
    301         pipe_mutex_lock(mutex); \
    302    } while (0)
    303 
    304 #define pipe_condvar_signal(condvar) \
    305    (void) condvar
    306 
    307 #define pipe_condvar_broadcast(condvar) \
    308    (void) condvar
    309 
    310 
    311 #endif  /* PIPE_OS_? */
    312 
    313 
    314 /*
    315  * pipe_barrier
    316  */
    317 
    318 #if (defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS)) && !defined(PIPE_OS_ANDROID)
    319 
    320 typedef pthread_barrier_t pipe_barrier;
    321 
    322 static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
    323 {
    324    pthread_barrier_init(barrier, NULL, count);
    325 }
    326 
    327 static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
    328 {
    329    pthread_barrier_destroy(barrier);
    330 }
    331 
    332 static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
    333 {
    334    pthread_barrier_wait(barrier);
    335 }
    336 
    337 
    338 #else /* If the OS doesn't have its own, implement barriers using a mutex and a condvar */
    339 
    340 typedef struct {
    341    unsigned count;
    342    unsigned waiters;
    343    uint64_t sequence;
    344    pipe_mutex mutex;
    345    pipe_condvar condvar;
    346 } pipe_barrier;
    347 
    348 static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
    349 {
    350    barrier->count = count;
    351    barrier->waiters = 0;
    352    barrier->sequence = 0;
    353    pipe_mutex_init(barrier->mutex);
    354    pipe_condvar_init(barrier->condvar);
    355 }
    356 
    357 static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
    358 {
    359    assert(barrier->waiters == 0);
    360    pipe_mutex_destroy(barrier->mutex);
    361    pipe_condvar_destroy(barrier->condvar);
    362 }
    363 
    364 static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
    365 {
    366    pipe_mutex_lock(barrier->mutex);
    367 
    368    assert(barrier->waiters < barrier->count);
    369    barrier->waiters++;
    370 
    371    if (barrier->waiters < barrier->count) {
    372       uint64_t sequence = barrier->sequence;
    373 
    374       do {
    375          pipe_condvar_wait(barrier->condvar, barrier->mutex);
    376       } while (sequence == barrier->sequence);
    377    } else {
    378       barrier->waiters = 0;
    379       barrier->sequence++;
    380       pipe_condvar_broadcast(barrier->condvar);
    381    }
    382 
    383    pipe_mutex_unlock(barrier->mutex);
    384 }
    385 
    386 
    387 #endif
    388 
    389 
    390 /*
    391  * Semaphores
    392  */
    393 
    394 typedef struct
    395 {
    396    pipe_mutex mutex;
    397    pipe_condvar cond;
    398    int counter;
    399 } pipe_semaphore;
    400 
    401 
    402 static INLINE void
    403 pipe_semaphore_init(pipe_semaphore *sema, int init_val)
    404 {
    405    pipe_mutex_init(sema->mutex);
    406    pipe_condvar_init(sema->cond);
    407    sema->counter = init_val;
    408 }
    409 
    410 static INLINE void
    411 pipe_semaphore_destroy(pipe_semaphore *sema)
    412 {
    413    pipe_mutex_destroy(sema->mutex);
    414    pipe_condvar_destroy(sema->cond);
    415 }
    416 
    417 /** Signal/increment semaphore counter */
    418 static INLINE void
    419 pipe_semaphore_signal(pipe_semaphore *sema)
    420 {
    421    pipe_mutex_lock(sema->mutex);
    422    sema->counter++;
    423    pipe_condvar_signal(sema->cond);
    424    pipe_mutex_unlock(sema->mutex);
    425 }
    426 
    427 /** Wait for semaphore counter to be greater than zero */
    428 static INLINE void
    429 pipe_semaphore_wait(pipe_semaphore *sema)
    430 {
    431    pipe_mutex_lock(sema->mutex);
    432    while (sema->counter <= 0) {
    433       pipe_condvar_wait(sema->cond, sema->mutex);
    434    }
    435    sema->counter--;
    436    pipe_mutex_unlock(sema->mutex);
    437 }
    438 
    439 
    440 
    441 /*
    442  * Thread-specific data.
    443  */
    444 
    445 typedef struct {
    446 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN)
    447    pthread_key_t key;
    448 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
    449    DWORD key;
    450 #endif
    451    int initMagic;
    452 } pipe_tsd;
    453 
    454 
    455 #define PIPE_TSD_INIT_MAGIC 0xff8adc98
    456 
    457 
    458 static INLINE void
    459 pipe_tsd_init(pipe_tsd *tsd)
    460 {
    461 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN)
    462    if (pthread_key_create(&tsd->key, NULL/*free*/) != 0) {
    463       perror("pthread_key_create(): failed to allocate key for thread specific data");
    464       exit(-1);
    465    }
    466 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
    467    assert(0);
    468 #endif
    469    tsd->initMagic = PIPE_TSD_INIT_MAGIC;
    470 }
    471 
    472 static INLINE void *
    473 pipe_tsd_get(pipe_tsd *tsd)
    474 {
    475    if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) {
    476       pipe_tsd_init(tsd);
    477    }
    478 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN)
    479    return pthread_getspecific(tsd->key);
    480 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
    481    assert(0);
    482    return NULL;
    483 #else
    484    assert(0);
    485    return NULL;
    486 #endif
    487 }
    488 
    489 static INLINE void
    490 pipe_tsd_set(pipe_tsd *tsd, void *value)
    491 {
    492    if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) {
    493       pipe_tsd_init(tsd);
    494    }
    495 #if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU) || defined(PIPE_OS_CYGWIN)
    496    if (pthread_setspecific(tsd->key, value) != 0) {
    497       perror("pthread_set_specific() failed");
    498       exit(-1);
    499    }
    500 #elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
    501    assert(0);
    502 #else
    503    assert(0);
    504 #endif
    505 }
    506 
    507 
    508 
    509 #endif /* OS_THREAD_H_ */
    510