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