Merge commit 'origin/gallium-master-merge'
[mesa.git] / src / mesa / glapi / glthread.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.1
4 *
5 * Copyright (C) 1999-2006 Brian Paul 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 * XXX There's probably some work to do in order to make this file
28 * truly reusable outside of Mesa. First, the glheader.h include must go.
29 */
30
31 #ifdef HAVE_DIX_CONFIG_H
32 #include <dix-config.h>
33 #endif
34
35 #include "main/glheader.h"
36 #include "glthread.h"
37
38
39 /*
40 * This file should still compile even when THREADS is not defined.
41 * This is to make things easier to deal with on the makefile scene..
42 */
43 #ifdef THREADS
44 #include <errno.h>
45
46 /*
47 * Error messages
48 */
49 #define INIT_TSD_ERROR "_glthread_: failed to allocate key for thread specific data"
50 #define GET_TSD_ERROR "_glthread_: failed to get thread specific data"
51 #define SET_TSD_ERROR "_glthread_: thread failed to set thread specific data"
52
53
54 /*
55 * Magic number to determine if a TSD object has been initialized.
56 * Kind of a hack but there doesn't appear to be a better cross-platform
57 * solution.
58 */
59 #define INIT_MAGIC 0xff8adc98
60
61
62
63 /*
64 * POSIX Threads -- The best way to go if your platform supports them.
65 * Solaris >= 2.5 have POSIX threads, IRIX >= 6.4 reportedly
66 * has them, and many of the free Unixes now have them.
67 * Be sure to use appropriate -mt or -D_REENTRANT type
68 * compile flags when building.
69 */
70 #ifdef PTHREADS
71
72 unsigned long
73 _glthread_GetID(void)
74 {
75 return (unsigned long) pthread_self();
76 }
77
78
79 void
80 _glthread_InitTSD(_glthread_TSD *tsd)
81 {
82 if (pthread_key_create(&tsd->key, NULL/*free*/) != 0) {
83 perror(INIT_TSD_ERROR);
84 exit(-1);
85 }
86 tsd->initMagic = INIT_MAGIC;
87 }
88
89
90 void *
91 _glthread_GetTSD(_glthread_TSD *tsd)
92 {
93 if (tsd->initMagic != (int) INIT_MAGIC) {
94 _glthread_InitTSD(tsd);
95 }
96 return pthread_getspecific(tsd->key);
97 }
98
99
100 void
101 _glthread_SetTSD(_glthread_TSD *tsd, void *ptr)
102 {
103 if (tsd->initMagic != (int) INIT_MAGIC) {
104 _glthread_InitTSD(tsd);
105 }
106 if (pthread_setspecific(tsd->key, ptr) != 0) {
107 perror(SET_TSD_ERROR);
108 exit(-1);
109 }
110 }
111
112 #endif /* PTHREADS */
113
114
115
116 /*
117 * Solaris/Unix International Threads -- Use only if POSIX threads
118 * aren't available on your Unix platform. Solaris 2.[34] are examples
119 * of platforms where this is the case. Be sure to use -mt and/or
120 * -D_REENTRANT when compiling.
121 */
122 #ifdef SOLARIS_THREADS
123 #define USE_LOCK_FOR_KEY /* undef this to try a version without
124 lock for the global key... */
125
126 unsigned long
127 _glthread_GetID(void)
128 {
129 abort(); /* XXX not implemented yet */
130 return (unsigned long) 0;
131 }
132
133
134 void
135 _glthread_InitTSD(_glthread_TSD *tsd)
136 {
137 if ((errno = mutex_init(&tsd->keylock, 0, NULL)) != 0 ||
138 (errno = thr_keycreate(&(tsd->key), free)) != 0) {
139 perror(INIT_TSD_ERROR);
140 exit(-1);
141 }
142 tsd->initMagic = INIT_MAGIC;
143 }
144
145
146 void *
147 _glthread_GetTSD(_glthread_TSD *tsd)
148 {
149 void* ret;
150 if (tsd->initMagic != INIT_MAGIC) {
151 _glthread_InitTSD(tsd);
152 }
153 #ifdef USE_LOCK_FOR_KEY
154 mutex_lock(&tsd->keylock);
155 thr_getspecific(tsd->key, &ret);
156 mutex_unlock(&tsd->keylock);
157 #else
158 if ((errno = thr_getspecific(tsd->key, &ret)) != 0) {
159 perror(GET_TSD_ERROR);
160 exit(-1);
161 }
162 #endif
163 return ret;
164 }
165
166
167 void
168 _glthread_SetTSD(_glthread_TSD *tsd, void *ptr)
169 {
170 if (tsd->initMagic != INIT_MAGIC) {
171 _glthread_InitTSD(tsd);
172 }
173 if ((errno = thr_setspecific(tsd->key, ptr)) != 0) {
174 perror(SET_TSD_ERROR);
175 exit(-1);
176 }
177 }
178
179 #undef USE_LOCK_FOR_KEY
180 #endif /* SOLARIS_THREADS */
181
182
183
184 /*
185 * Win32 Threads. The only available option for Windows 95/NT.
186 * Be sure that you compile using the Multithreaded runtime, otherwise
187 * bad things will happen.
188 */
189 #ifdef WIN32_THREADS
190
191 void FreeTSD(_glthread_TSD *p)
192 {
193 if (p->initMagic==INIT_MAGIC) {
194 TlsFree(p->key);
195 p->initMagic=0;
196 }
197 }
198
199 void InsteadOf_exit(int nCode)
200 {
201 DWORD dwErr=GetLastError();
202 }
203
204 unsigned long
205 _glthread_GetID(void)
206 {
207 return GetCurrentThreadId();
208 }
209
210
211 void
212 _glthread_InitTSD(_glthread_TSD *tsd)
213 {
214 tsd->key = TlsAlloc();
215 if (tsd->key == TLS_OUT_OF_INDEXES) {
216 perror("Mesa:_glthread_InitTSD");
217 InsteadOf_exit(-1);
218 }
219 tsd->initMagic = INIT_MAGIC;
220 }
221
222
223 void *
224 _glthread_GetTSD(_glthread_TSD *tsd)
225 {
226 if (tsd->initMagic != INIT_MAGIC) {
227 _glthread_InitTSD(tsd);
228 }
229 return TlsGetValue(tsd->key);
230 }
231
232
233 void
234 _glthread_SetTSD(_glthread_TSD *tsd, void *ptr)
235 {
236 /* the following code assumes that the _glthread_TSD has been initialized
237 to zero at creation */
238 if (tsd->initMagic != INIT_MAGIC) {
239 _glthread_InitTSD(tsd);
240 }
241 if (TlsSetValue(tsd->key, ptr) == 0) {
242 perror("Mesa:_glthread_SetTSD");
243 InsteadOf_exit(-1);
244 }
245 }
246
247 #endif /* WIN32_THREADS */
248
249
250
251 /*
252 * XFree86 has its own thread wrapper, Xthreads.h
253 * We wrap it again for GL.
254 */
255 #ifdef USE_XTHREADS
256
257 unsigned long
258 _glthread_GetID(void)
259 {
260 return (unsigned long) xthread_self();
261 }
262
263
264 void
265 _glthread_InitTSD(_glthread_TSD *tsd)
266 {
267 if (xthread_key_create(&tsd->key, NULL) != 0) {
268 perror(INIT_TSD_ERROR);
269 exit(-1);
270 }
271 tsd->initMagic = INIT_MAGIC;
272 }
273
274
275 void *
276 _glthread_GetTSD(_glthread_TSD *tsd)
277 {
278 void *ptr;
279 if (tsd->initMagic != INIT_MAGIC) {
280 _glthread_InitTSD(tsd);
281 }
282 xthread_get_specific(tsd->key, &ptr);
283 return ptr;
284 }
285
286
287 void
288 _glthread_SetTSD(_glthread_TSD *tsd, void *ptr)
289 {
290 if (tsd->initMagic != INIT_MAGIC) {
291 _glthread_InitTSD(tsd);
292 }
293 xthread_set_specific(tsd->key, ptr);
294 }
295
296 #endif /* XTHREAD */
297
298
299
300 /*
301 * BeOS threads
302 */
303 #ifdef BEOS_THREADS
304
305 unsigned long
306 _glthread_GetID(void)
307 {
308 return (unsigned long) find_thread(NULL);
309 }
310
311 void
312 _glthread_InitTSD(_glthread_TSD *tsd)
313 {
314 tsd->key = tls_allocate();
315 tsd->initMagic = INIT_MAGIC;
316 }
317
318 void *
319 _glthread_GetTSD(_glthread_TSD *tsd)
320 {
321 if (tsd->initMagic != (int) INIT_MAGIC) {
322 _glthread_InitTSD(tsd);
323 }
324 return tls_get(tsd->key);
325 }
326
327 void
328 _glthread_SetTSD(_glthread_TSD *tsd, void *ptr)
329 {
330 if (tsd->initMagic != (int) INIT_MAGIC) {
331 _glthread_InitTSD(tsd);
332 }
333 tls_set(tsd->key, ptr);
334 }
335
336 #endif /* BEOS_THREADS */
337
338
339
340 #else /* THREADS */
341
342
343 /*
344 * no-op functions
345 */
346
347 unsigned long
348 _glthread_GetID(void)
349 {
350 return 0;
351 }
352
353
354 void
355 _glthread_InitTSD(_glthread_TSD *tsd)
356 {
357 (void) tsd;
358 }
359
360
361 void *
362 _glthread_GetTSD(_glthread_TSD *tsd)
363 {
364 (void) tsd;
365 return NULL;
366 }
367
368
369 void
370 _glthread_SetTSD(_glthread_TSD *tsd, void *ptr)
371 {
372 (void) tsd;
373 (void) ptr;
374 }
375
376
377 #endif /* THREADS */