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