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