os_thread.h revision cdc920a0
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)
44
45#include <pthread.h> /* POSIX threads headers */
46#include <stdio.h> /* for perror() */
47
48#define PIPE_THREAD_HAVE_CONDVAR
49
50/* pipe_thread
51 */
52typedef pthread_t pipe_thread;
53
54#define PIPE_THREAD_ROUTINE( name, param ) \
55   void *name( void *param )
56
57static INLINE pipe_thread pipe_thread_create( void *(* routine)( void *), void *param )
58{
59   pipe_thread thread;
60   if (pthread_create( &thread, NULL, routine, param ))
61      return 0;
62   return thread;
63}
64
65static INLINE int pipe_thread_wait( pipe_thread thread )
66{
67   return pthread_join( thread, NULL );
68}
69
70static INLINE int pipe_thread_destroy( pipe_thread thread )
71{
72   return pthread_detach( thread );
73}
74
75
76/* pipe_mutex
77 */
78typedef pthread_mutex_t pipe_mutex;
79
80#define pipe_static_mutex(mutex) \
81   static pipe_mutex mutex = PTHREAD_MUTEX_INITIALIZER
82
83#define pipe_mutex_init(mutex) \
84   (void) pthread_mutex_init(&(mutex), NULL)
85
86#define pipe_mutex_destroy(mutex) \
87   pthread_mutex_destroy(&(mutex))
88
89#define pipe_mutex_lock(mutex) \
90   (void) pthread_mutex_lock(&(mutex))
91
92#define pipe_mutex_unlock(mutex) \
93   (void) pthread_mutex_unlock(&(mutex))
94
95
96/* pipe_condvar
97 */
98typedef pthread_cond_t pipe_condvar;
99
100#define pipe_static_condvar(mutex) \
101   static pipe_condvar mutex = PTHREAD_COND_INITIALIZER
102
103#define pipe_condvar_init(cond)	\
104   pthread_cond_init(&(cond), NULL)
105
106#define pipe_condvar_destroy(cond) \
107   pthread_cond_destroy(&(cond))
108
109#define pipe_condvar_wait(cond, mutex) \
110  pthread_cond_wait(&(cond), &(mutex))
111
112#define pipe_condvar_signal(cond) \
113  pthread_cond_signal(&(cond))
114
115#define pipe_condvar_broadcast(cond) \
116  pthread_cond_broadcast(&(cond))
117
118
119
120#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
121
122#include <windows.h>
123
124/* pipe_thread
125 */
126typedef HANDLE pipe_thread;
127
128#define PIPE_THREAD_ROUTINE( name, param ) \
129   void * WINAPI name( void *param )
130
131static INLINE pipe_thread pipe_thread_create( void *(WINAPI * routine)( void *), void *param )
132{
133   DWORD id;
134   return CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) routine, param, 0, &id );
135}
136
137static INLINE int pipe_thread_wait( pipe_thread thread )
138{
139   if (WaitForSingleObject( thread, INFINITE ) == WAIT_OBJECT_0)
140      return 0;
141   return -1;
142}
143
144static INLINE int pipe_thread_destroy( pipe_thread thread )
145{
146   if (CloseHandle( thread ))
147      return 0;
148   return -1;
149}
150
151
152/* pipe_mutex
153 */
154typedef CRITICAL_SECTION pipe_mutex;
155
156#define pipe_static_mutex(mutex) \
157   /*static*/ pipe_mutex mutex = {0,0,0,0,0,0}
158
159#define pipe_mutex_init(mutex) \
160   InitializeCriticalSection(&mutex)
161
162#define pipe_mutex_destroy(mutex) \
163   DeleteCriticalSection(&mutex)
164
165#define pipe_mutex_lock(mutex) \
166   EnterCriticalSection(&mutex)
167
168#define pipe_mutex_unlock(mutex) \
169   LeaveCriticalSection(&mutex)
170
171
172/* pipe_condvar (XXX FIX THIS)
173 */
174typedef unsigned pipe_condvar;
175
176#define pipe_condvar_init(cond) \
177   (void) cond
178
179#define pipe_condvar_destroy(cond) \
180   (void) cond
181
182#define pipe_condvar_wait(cond, mutex) \
183   (void) cond; (void) mutex
184
185#define pipe_condvar_signal(cond) \
186   (void) cond
187
188#define pipe_condvar_broadcast(cond) \
189   (void) cond
190
191
192#else
193
194/** Dummy definitions */
195
196typedef unsigned pipe_thread;
197
198#define PIPE_THREAD_ROUTINE( name, param ) \
199   void * name( void *param )
200
201static INLINE pipe_thread pipe_thread_create( void *(* routine)( void *), void *param )
202{
203   return 0;
204}
205
206static INLINE int pipe_thread_wait( pipe_thread thread )
207{
208   return -1;
209}
210
211static INLINE int pipe_thread_destroy( pipe_thread thread )
212{
213   return -1;
214}
215
216typedef unsigned pipe_mutex;
217typedef unsigned pipe_condvar;
218
219#define pipe_static_mutex(mutex) \
220   static pipe_mutex mutex = 0
221
222#define pipe_mutex_init(mutex) \
223   (void) mutex
224
225#define pipe_mutex_destroy(mutex) \
226   (void) mutex
227
228#define pipe_mutex_lock(mutex) \
229   (void) mutex
230
231#define pipe_mutex_unlock(mutex) \
232   (void) mutex
233
234#define pipe_static_condvar(condvar) \
235   static unsigned condvar = 0
236
237#define pipe_condvar_init(condvar) \
238   (void) condvar
239
240#define pipe_condvar_destroy(condvar) \
241   (void) condvar
242
243#define pipe_condvar_wait(condvar, mutex) \
244   (void) condvar
245
246#define pipe_condvar_signal(condvar) \
247   (void) condvar
248
249#define pipe_condvar_broadcast(condvar) \
250   (void) condvar
251
252
253#endif  /* PIPE_OS_? */
254
255
256/*
257 * pipe_barrier
258 */
259
260#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_HAIKU)
261
262typedef pthread_barrier_t pipe_barrier;
263
264static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
265{
266   pthread_barrier_init(barrier, NULL, count);
267}
268
269static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
270{
271   pthread_barrier_destroy(barrier);
272}
273
274static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
275{
276   pthread_barrier_wait(barrier);
277}
278
279
280#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
281
282/* XXX FIX THIS */
283typedef unsigned pipe_barrier;
284
285static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
286{
287   /* XXX we could implement barriers with a mutex and condition var */
288}
289
290static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
291{
292}
293
294static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
295{
296   assert(0);
297}
298
299
300#else
301
302typedef unsigned pipe_barrier;
303
304static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
305{
306   /* XXX we could implement barriers with a mutex and condition var */
307   assert(0);
308}
309
310static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
311{
312   assert(0);
313}
314
315static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
316{
317   assert(0);
318}
319
320
321#endif
322
323
324/*
325 * Semaphores
326 */
327
328typedef struct
329{
330   pipe_mutex mutex;
331   pipe_condvar cond;
332   int counter;
333} pipe_semaphore;
334
335
336static INLINE void
337pipe_semaphore_init(pipe_semaphore *sema, int init_val)
338{
339   pipe_mutex_init(sema->mutex);
340   pipe_condvar_init(sema->cond);
341   sema->counter = init_val;
342}
343
344static INLINE void
345pipe_semaphore_destroy(pipe_semaphore *sema)
346{
347   pipe_mutex_destroy(sema->mutex);
348   pipe_condvar_destroy(sema->cond);
349}
350
351/** Signal/increment semaphore counter */
352static INLINE void
353pipe_semaphore_signal(pipe_semaphore *sema)
354{
355   pipe_mutex_lock(sema->mutex);
356   sema->counter++;
357   pipe_condvar_signal(sema->cond);
358   pipe_mutex_unlock(sema->mutex);
359}
360
361/** Wait for semaphore counter to be greater than zero */
362static INLINE void
363pipe_semaphore_wait(pipe_semaphore *sema)
364{
365   pipe_mutex_lock(sema->mutex);
366   while (sema->counter <= 0) {
367      pipe_condvar_wait(sema->cond, sema->mutex);
368   }
369   sema->counter--;
370   pipe_mutex_unlock(sema->mutex);
371}
372
373
374
375/*
376 * Thread-specific data.
377 */
378
379typedef struct {
380#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU)
381   pthread_key_t key;
382#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
383   DWORD key;
384#endif
385   int initMagic;
386} pipe_tsd;
387
388
389#define PIPE_TSD_INIT_MAGIC 0xff8adc98
390
391
392static INLINE void
393pipe_tsd_init(pipe_tsd *tsd)
394{
395#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU)
396   if (pthread_key_create(&tsd->key, NULL/*free*/) != 0) {
397      perror("pthread_key_create(): failed to allocate key for thread specific data");
398      exit(-1);
399   }
400#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
401   assert(0);
402#endif
403   tsd->initMagic = PIPE_TSD_INIT_MAGIC;
404}
405
406static INLINE void *
407pipe_tsd_get(pipe_tsd *tsd)
408{
409   if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) {
410      pipe_tsd_init(tsd);
411   }
412#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU)
413   return pthread_getspecific(tsd->key);
414#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
415   assert(0);
416   return NULL;
417#else
418   assert(0);
419   return NULL;
420#endif
421}
422
423static INLINE void
424pipe_tsd_set(pipe_tsd *tsd, void *value)
425{
426   if (tsd->initMagic != (int) PIPE_TSD_INIT_MAGIC) {
427      pipe_tsd_init(tsd);
428   }
429#if defined(PIPE_OS_LINUX) || defined(PIPE_OS_BSD) || defined(PIPE_OS_SOLARIS) || defined(PIPE_OS_APPLE) || defined(PIPE_OS_HAIKU)
430   if (pthread_setspecific(tsd->key, value) != 0) {
431      perror("pthread_set_specific() failed");
432      exit(-1);
433   }
434#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
435   assert(0);
436#else
437   assert(0);
438#endif
439}
440
441
442
443#endif /* OS_THREAD_H_ */
444