Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

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