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