1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg/*
27848b8605Smrg * This file manages the OpenGL API dispatch layer.
28848b8605Smrg * The dispatch table (struct _glapi_table) is basically just a list
29848b8605Smrg * of function pointers.
30848b8605Smrg * There are functions to set/get the current dispatch table for the
31848b8605Smrg * current thread and to manage registration/dispatch of dynamically
32848b8605Smrg * added extension functions.
33848b8605Smrg *
34848b8605Smrg * It's intended that this file and the other glapi*.[ch] files are
35848b8605Smrg * flexible enough to be reused in several places:  XFree86, DRI-
36848b8605Smrg * based libGL.so, and perhaps the SGI SI.
37848b8605Smrg *
38848b8605Smrg * NOTE: There are no dependencies on Mesa in this code.
39848b8605Smrg *
40848b8605Smrg * Versions (API changes):
41848b8605Smrg *   2000/02/23  - original version for Mesa 3.3 and XFree86 4.0
42848b8605Smrg *   2001/01/16  - added dispatch override feature for Mesa 3.5
43848b8605Smrg *   2002/06/28  - added _glapi_set_warning_func(), Mesa 4.1.
44848b8605Smrg *   2002/10/01  - _glapi_get_proc_address() will now generate new entrypoints
45848b8605Smrg *                 itself (using offset ~0).  _glapi_add_entrypoint() can be
46848b8605Smrg *                 called afterward and it'll fill in the correct dispatch
47848b8605Smrg *                 offset.  This allows DRI libGL to avoid probing for DRI
48848b8605Smrg *                 drivers!  No changes to the public glapi interface.
49848b8605Smrg */
50848b8605Smrg
51b8e80941Smrg#include "c11/threads.h"
52848b8605Smrg#include "u_current.h"
53848b8605Smrg
54848b8605Smrg#ifndef MAPI_MODE_UTIL
55848b8605Smrg
56848b8605Smrg#include "table.h"
57848b8605Smrg#include "stub.h"
58848b8605Smrg
59848b8605Smrg#else
60848b8605Smrg
61848b8605Smrgextern void init_glapi_relocs_once(void);
62848b8605Smrgextern void (*__glapi_noop_table[])(void);
63848b8605Smrg
64848b8605Smrg#define table_noop_array __glapi_noop_table
65848b8605Smrg#define stub_init_once() init_glapi_relocs_once()
66848b8605Smrg
67848b8605Smrg#endif
68848b8605Smrg
69848b8605Smrg/**
70848b8605Smrg * \name Current dispatch and current context control variables
71848b8605Smrg *
72848b8605Smrg * Depending on whether or not multithreading is support, and the type of
73848b8605Smrg * support available, several variables are used to store the current context
74848b8605Smrg * pointer and the current dispatch table pointer.  In the non-threaded case,
75848b8605Smrg * the variables \c _glapi_Dispatch and \c _glapi_Context are used for this
76848b8605Smrg * purpose.
77848b8605Smrg *
78848b8605Smrg * In the "normal" threaded case, the variables \c _glapi_Dispatch and
79848b8605Smrg * \c _glapi_Context will be \c NULL if an application is detected as being
80848b8605Smrg * multithreaded.  Single-threaded applications will use \c _glapi_Dispatch
81848b8605Smrg * and \c _glapi_Context just like the case without any threading support.
82848b8605Smrg * When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state
83848b8605Smrg * data \c _gl_DispatchTSD and \c ContextTSD are used.  Drivers and the
84848b8605Smrg * static dispatch functions access these variables via \c _glapi_get_dispatch
85848b8605Smrg * and \c _glapi_get_context.
86848b8605Smrg *
87848b8605Smrg * There is a race condition in setting \c _glapi_Dispatch to \c NULL.  It is
88848b8605Smrg * possible for the original thread to be setting it at the same instant a new
89848b8605Smrg * thread, perhaps running on a different processor, is clearing it.  Because
90848b8605Smrg * of that, \c ThreadSafe, which can only ever be changed to \c GL_TRUE, is
91848b8605Smrg * used to determine whether or not the application is multithreaded.
92848b8605Smrg *
93848b8605Smrg * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are
94848b8605Smrg * hardcoded to \c NULL.  Instead the TLS variables \c _glapi_tls_Dispatch and
95848b8605Smrg * \c _glapi_tls_Context are used.  Having \c _glapi_Dispatch and
96848b8605Smrg * \c _glapi_Context be hardcoded to \c NULL maintains binary compatability
97848b8605Smrg * between TLS enabled loaders and non-TLS DRI drivers.
98848b8605Smrg */
99848b8605Smrg/*@{*/
100848b8605Smrg#if defined(GLX_USE_TLS)
101848b8605Smrg
102b8e80941Smrg__thread struct _glapi_table *u_current_table
103848b8605Smrg    __attribute__((tls_model("initial-exec")))
104b8e80941Smrg#if defined(__NetBSD__)
105b8e80941Smrg    = NULL; /* non-zero initializers not supported with dlopen */
106b8e80941Smrg#else
107b8e80941Smrg    = (struct _glapi_table *) table_noop_array;
108b8e80941Smrg#endif
109848b8605Smrg
110848b8605Smrg__thread void *u_current_context
111848b8605Smrg    __attribute__((tls_model("initial-exec")));
112848b8605Smrg
113848b8605Smrg#else
114848b8605Smrg
115b8e80941Smrgstruct _glapi_table *u_current_table =
116b8e80941Smrg   (struct _glapi_table *) table_noop_array;
117848b8605Smrgvoid *u_current_context;
118848b8605Smrg
119b8e80941Smrgtss_t u_current_table_tsd;
120b8e80941Smrgstatic tss_t u_current_context_tsd;
121848b8605Smrgstatic int ThreadSafe;
122848b8605Smrg
123848b8605Smrg#endif /* defined(GLX_USE_TLS) */
124848b8605Smrg/*@}*/
125848b8605Smrg
126848b8605Smrg
127848b8605Smrgvoid
128848b8605Smrgu_current_destroy(void)
129848b8605Smrg{
130b8e80941Smrg#if !defined(GLX_USE_TLS)
131b8e80941Smrg   tss_delete(u_current_table_tsd);
132b8e80941Smrg   tss_delete(u_current_context_tsd);
133848b8605Smrg#endif
134848b8605Smrg}
135848b8605Smrg
136848b8605Smrg
137b8e80941Smrg#if !defined(GLX_USE_TLS)
138848b8605Smrg
139848b8605Smrgstatic void
140848b8605Smrgu_current_init_tsd(void)
141848b8605Smrg{
142b8e80941Smrg   tss_create(&u_current_table_tsd, NULL);
143b8e80941Smrg   tss_create(&u_current_context_tsd, NULL);
144848b8605Smrg}
145848b8605Smrg
146848b8605Smrg/**
147848b8605Smrg * Mutex for multithread check.
148848b8605Smrg */
149848b8605Smrgstatic mtx_t ThreadCheckMutex = _MTX_INITIALIZER_NP;
150848b8605Smrg
151b8e80941Smrg
152b8e80941Smrg#ifdef _WIN32
153b8e80941Smrgtypedef DWORD thread_id;
154b8e80941Smrg#else
155b8e80941Smrgtypedef thrd_t thread_id;
156b8e80941Smrg#endif
157b8e80941Smrg
158b8e80941Smrg
159b8e80941Smrgstatic inline thread_id
160b8e80941Smrgget_thread_id(void)
161b8e80941Smrg{
162b8e80941Smrg   /*
163b8e80941Smrg    * XXX: Callers of of this function assume it is a lightweight function.
164b8e80941Smrg    * But unfortunately C11's thrd_current() gives no such guarantees.  In
165b8e80941Smrg    * fact, it's pretty hard to have a compliant implementation of
166b8e80941Smrg    * thrd_current() on Windows with such characteristics.  So for now, we
167b8e80941Smrg    * side-step this mess and use Windows thread primitives directly here.
168b8e80941Smrg    */
169b8e80941Smrg#ifdef _WIN32
170b8e80941Smrg   return GetCurrentThreadId();
171b8e80941Smrg#else
172b8e80941Smrg   return thrd_current();
173b8e80941Smrg#endif
174b8e80941Smrg}
175b8e80941Smrg
176b8e80941Smrg
177b8e80941Smrgstatic inline int
178b8e80941Smrgthread_id_equal(thread_id t1, thread_id t2)
179b8e80941Smrg{
180b8e80941Smrg#ifdef _WIN32
181b8e80941Smrg   return t1 == t2;
182b8e80941Smrg#else
183b8e80941Smrg   return thrd_equal(t1, t2);
184b8e80941Smrg#endif
185b8e80941Smrg}
186b8e80941Smrg
187b8e80941Smrg
188848b8605Smrg/**
189848b8605Smrg * We should call this periodically from a function such as glXMakeCurrent
190848b8605Smrg * in order to test if multiple threads are being used.
191848b8605Smrg */
192848b8605Smrgvoid
193848b8605Smrgu_current_init(void)
194848b8605Smrg{
195b8e80941Smrg   static thread_id knownID;
196848b8605Smrg   static int firstCall = 1;
197848b8605Smrg
198848b8605Smrg   if (ThreadSafe)
199848b8605Smrg      return;
200848b8605Smrg
201848b8605Smrg   mtx_lock(&ThreadCheckMutex);
202848b8605Smrg   if (firstCall) {
203848b8605Smrg      u_current_init_tsd();
204848b8605Smrg
205b8e80941Smrg      knownID = get_thread_id();
206848b8605Smrg      firstCall = 0;
207848b8605Smrg   }
208b8e80941Smrg   else if (!thread_id_equal(knownID, get_thread_id())) {
209848b8605Smrg      ThreadSafe = 1;
210848b8605Smrg      u_current_set_table(NULL);
211848b8605Smrg      u_current_set_context(NULL);
212848b8605Smrg   }
213848b8605Smrg   mtx_unlock(&ThreadCheckMutex);
214848b8605Smrg}
215848b8605Smrg
216848b8605Smrg#else
217848b8605Smrg
218848b8605Smrgvoid
219848b8605Smrgu_current_init(void)
220848b8605Smrg{
221848b8605Smrg}
222848b8605Smrg
223848b8605Smrg#endif
224848b8605Smrg
225848b8605Smrg
226848b8605Smrg
227848b8605Smrg/**
228848b8605Smrg * Set the current context pointer for this thread.
229848b8605Smrg * The context pointer is an opaque type which should be cast to
230848b8605Smrg * void from the real context pointer type.
231848b8605Smrg */
232848b8605Smrgvoid
233848b8605Smrgu_current_set_context(const void *ptr)
234848b8605Smrg{
235848b8605Smrg   u_current_init();
236848b8605Smrg
237848b8605Smrg#if defined(GLX_USE_TLS)
238848b8605Smrg   u_current_context = (void *) ptr;
239848b8605Smrg#else
240b8e80941Smrg   tss_set(u_current_context_tsd, (void *) ptr);
241b8e80941Smrg   u_current_context = (ThreadSafe) ? NULL : (void *) ptr;
242848b8605Smrg#endif
243848b8605Smrg}
244848b8605Smrg
245848b8605Smrg/**
246848b8605Smrg * Get the current context pointer for this thread.
247848b8605Smrg * The context pointer is an opaque type which should be cast from
248848b8605Smrg * void to the real context pointer type.
249848b8605Smrg */
250848b8605Smrgvoid *
251848b8605Smrgu_current_get_context_internal(void)
252848b8605Smrg{
253848b8605Smrg#if defined(GLX_USE_TLS)
254848b8605Smrg   return u_current_context;
255848b8605Smrg#else
256b8e80941Smrg   return ThreadSafe ? tss_get(u_current_context_tsd) : u_current_context;
257848b8605Smrg#endif
258848b8605Smrg}
259848b8605Smrg
260848b8605Smrg/**
261848b8605Smrg * Set the global or per-thread dispatch table pointer.
262848b8605Smrg * If the dispatch parameter is NULL we'll plug in the no-op dispatch
263848b8605Smrg * table (__glapi_noop_table).
264848b8605Smrg */
265848b8605Smrgvoid
266b8e80941Smrgu_current_set_table(const struct _glapi_table *tbl)
267848b8605Smrg{
268848b8605Smrg   u_current_init();
269848b8605Smrg
270848b8605Smrg   stub_init_once();
271848b8605Smrg
272848b8605Smrg   if (!tbl)
273b8e80941Smrg      tbl = (const struct _glapi_table *) table_noop_array;
274848b8605Smrg
275848b8605Smrg#if defined(GLX_USE_TLS)
276b8e80941Smrg   u_current_table = (struct _glapi_table *) tbl;
277848b8605Smrg#else
278b8e80941Smrg   tss_set(u_current_table_tsd, (void *) tbl);
279b8e80941Smrg   u_current_table = (ThreadSafe) ? NULL : (void *) tbl;
280848b8605Smrg#endif
281848b8605Smrg}
282848b8605Smrg
283848b8605Smrg/**
284848b8605Smrg * Return pointer to current dispatch table for calling thread.
285848b8605Smrg */
286b8e80941Smrgstruct _glapi_table *
287848b8605Smrgu_current_get_table_internal(void)
288848b8605Smrg{
289848b8605Smrg#if defined(GLX_USE_TLS)
290b8e80941Smrg#  if defined(__NetBSD__)
291b8e80941Smrg   return (likely(u_current_table) ? u_current_table : (struct _glapi_table *) table_noop_array);
292b8e80941Smrg#  else
293848b8605Smrg   return u_current_table;
294b8e80941Smrg#  endif
295848b8605Smrg#else
296b8e80941Smrg   if (ThreadSafe)
297b8e80941Smrg      return (struct _glapi_table *) tss_get(u_current_table_tsd);
298b8e80941Smrg   else
299b8e80941Smrg      return (struct _glapi_table *) u_current_table;
300848b8605Smrg#endif
301848b8605Smrg}
302