Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25.  
  26. /*
  27.  * This file manages the OpenGL API dispatch layer.
  28.  * The dispatch table (struct _glapi_table) is basically just a list
  29.  * of function pointers.
  30.  * There are functions to set/get the current dispatch table for the
  31.  * current thread and to manage registration/dispatch of dynamically
  32.  * added extension functions.
  33.  *
  34.  * It's intended that this file and the other glapi*.[ch] files are
  35.  * flexible enough to be reused in several places:  XFree86, DRI-
  36.  * based libGL.so, and perhaps the SGI SI.
  37.  *
  38.  * NOTE: There are no dependencies on Mesa in this code.
  39.  *
  40.  * Versions (API changes):
  41.  *   2000/02/23  - original version for Mesa 3.3 and XFree86 4.0
  42.  *   2001/01/16  - added dispatch override feature for Mesa 3.5
  43.  *   2002/06/28  - added _glapi_set_warning_func(), Mesa 4.1.
  44.  *   2002/10/01  - _glapi_get_proc_address() will now generate new entrypoints
  45.  *                 itself (using offset ~0).  _glapi_add_entrypoint() can be
  46.  *                 called afterward and it'll fill in the correct dispatch
  47.  *                 offset.  This allows DRI libGL to avoid probing for DRI
  48.  *                 drivers!  No changes to the public glapi interface.
  49.  */
  50.  
  51. #include "c11/threads.h"
  52. #include "u_current.h"
  53.  
  54. #ifndef MAPI_MODE_UTIL
  55.  
  56. #include "table.h"
  57. #include "stub.h"
  58.  
  59. #else
  60.  
  61. extern void init_glapi_relocs_once(void);
  62. extern void (*__glapi_noop_table[])(void);
  63.  
  64. #define table_noop_array __glapi_noop_table
  65. #define stub_init_once() init_glapi_relocs_once()
  66.  
  67. #endif
  68.  
  69. /**
  70.  * \name Current dispatch and current context control variables
  71.  *
  72.  * Depending on whether or not multithreading is support, and the type of
  73.  * support available, several variables are used to store the current context
  74.  * pointer and the current dispatch table pointer.  In the non-threaded case,
  75.  * the variables \c _glapi_Dispatch and \c _glapi_Context are used for this
  76.  * purpose.
  77.  *
  78.  * In the "normal" threaded case, the variables \c _glapi_Dispatch and
  79.  * \c _glapi_Context will be \c NULL if an application is detected as being
  80.  * multithreaded.  Single-threaded applications will use \c _glapi_Dispatch
  81.  * and \c _glapi_Context just like the case without any threading support.
  82.  * When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state
  83.  * data \c _gl_DispatchTSD and \c ContextTSD are used.  Drivers and the
  84.  * static dispatch functions access these variables via \c _glapi_get_dispatch
  85.  * and \c _glapi_get_context.
  86.  *
  87.  * There is a race condition in setting \c _glapi_Dispatch to \c NULL.  It is
  88.  * possible for the original thread to be setting it at the same instant a new
  89.  * thread, perhaps running on a different processor, is clearing it.  Because
  90.  * of that, \c ThreadSafe, which can only ever be changed to \c GL_TRUE, is
  91.  * used to determine whether or not the application is multithreaded.
  92.  *
  93.  * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are
  94.  * hardcoded to \c NULL.  Instead the TLS variables \c _glapi_tls_Dispatch and
  95.  * \c _glapi_tls_Context are used.  Having \c _glapi_Dispatch and
  96.  * \c _glapi_Context be hardcoded to \c NULL maintains binary compatability
  97.  * between TLS enabled loaders and non-TLS DRI drivers.
  98.  */
  99. /*@{*/
  100. #if defined(GLX_USE_TLS)
  101.  
  102. __thread struct mapi_table *u_current_table
  103.     __attribute__((tls_model("initial-exec")))
  104.     = (struct mapi_table *) table_noop_array;
  105.  
  106. __thread void *u_current_context
  107.     __attribute__((tls_model("initial-exec")));
  108.  
  109. #else
  110.  
  111. struct mapi_table *u_current_table =
  112.    (struct mapi_table *) table_noop_array;
  113. void *u_current_context;
  114.  
  115. tss_t u_current_table_tsd;
  116. static tss_t u_current_context_tsd;
  117. static int ThreadSafe;
  118.  
  119. #endif /* defined(GLX_USE_TLS) */
  120. /*@}*/
  121.  
  122.  
  123. void
  124. u_current_destroy(void)
  125. {
  126. #if !defined(GLX_USE_TLS)
  127.    tss_delete(u_current_table_tsd);
  128.    tss_delete(u_current_context_tsd);
  129. #endif
  130. }
  131.  
  132.  
  133. #if !defined(GLX_USE_TLS)
  134.  
  135. static void
  136. u_current_init_tsd(void)
  137. {
  138.    tss_create(&u_current_table_tsd, NULL);
  139.    tss_create(&u_current_context_tsd, NULL);
  140. }
  141.  
  142. /**
  143.  * Mutex for multithread check.
  144.  */
  145. static mtx_t ThreadCheckMutex = _MTX_INITIALIZER_NP;
  146.  
  147.  
  148. #ifdef _WIN32
  149. typedef DWORD thread_id;
  150. #else
  151. typedef thrd_t thread_id;
  152. #endif
  153.  
  154.  
  155. static inline thread_id
  156. get_thread_id(void)
  157. {
  158.    /*
  159.     * XXX: Callers of of this function assume it is a lightweight function.
  160.     * But unfortunately C11's thrd_current() gives no such guarantees.  In
  161.     * fact, it's pretty hard to have a compliant implementation of
  162.     * thrd_current() on Windows with such characteristics.  So for now, we
  163.     * side-step this mess and use Windows thread primitives directly here.
  164.     */
  165. #ifdef _WIN32
  166.    return GetCurrentThreadId();
  167. #else
  168.    return thrd_current();
  169. #endif
  170. }
  171.  
  172.  
  173. static inline int
  174. thread_id_equal(thread_id t1, thread_id t2)
  175. {
  176. #ifdef _WIN32
  177.    return t1 == t2;
  178. #else
  179.    return thrd_equal(t1, t2);
  180. #endif
  181. }
  182.  
  183.  
  184. /**
  185.  * We should call this periodically from a function such as glXMakeCurrent
  186.  * in order to test if multiple threads are being used.
  187.  */
  188. void
  189. u_current_init(void)
  190. {
  191.    static thread_id knownID;
  192.    static int firstCall = 1;
  193.  
  194.    if (ThreadSafe)
  195.       return;
  196.  
  197.    mtx_lock(&ThreadCheckMutex);
  198.    if (firstCall) {
  199.       u_current_init_tsd();
  200.  
  201.       knownID = get_thread_id();
  202.       firstCall = 0;
  203.    }
  204.    else if (!thread_id_equal(knownID, get_thread_id())) {
  205.       ThreadSafe = 1;
  206.       u_current_set_table(NULL);
  207.       u_current_set_context(NULL);
  208.    }
  209.    mtx_unlock(&ThreadCheckMutex);
  210. }
  211.  
  212. #else
  213.  
  214. void
  215. u_current_init(void)
  216. {
  217. }
  218.  
  219. #endif
  220.  
  221.  
  222.  
  223. /**
  224.  * Set the current context pointer for this thread.
  225.  * The context pointer is an opaque type which should be cast to
  226.  * void from the real context pointer type.
  227.  */
  228. void
  229. u_current_set_context(const void *ptr)
  230. {
  231.    u_current_init();
  232.  
  233. #if defined(GLX_USE_TLS)
  234.    u_current_context = (void *) ptr;
  235. #else
  236.    tss_set(u_current_context_tsd, (void *) ptr);
  237.    u_current_context = (ThreadSafe) ? NULL : (void *) ptr;
  238. #endif
  239. }
  240.  
  241. /**
  242.  * Get the current context pointer for this thread.
  243.  * The context pointer is an opaque type which should be cast from
  244.  * void to the real context pointer type.
  245.  */
  246. void *
  247. u_current_get_context_internal(void)
  248. {
  249. #if defined(GLX_USE_TLS)
  250.    return u_current_context;
  251. #else
  252.    return ThreadSafe ? tss_get(u_current_context_tsd) : u_current_context;
  253. #endif
  254. }
  255.  
  256. /**
  257.  * Set the global or per-thread dispatch table pointer.
  258.  * If the dispatch parameter is NULL we'll plug in the no-op dispatch
  259.  * table (__glapi_noop_table).
  260.  */
  261. void
  262. u_current_set_table(const struct mapi_table *tbl)
  263. {
  264.    u_current_init();
  265.  
  266.    stub_init_once();
  267.  
  268.    if (!tbl)
  269.       tbl = (const struct mapi_table *) table_noop_array;
  270.  
  271. #if defined(GLX_USE_TLS)
  272.    u_current_table = (struct mapi_table *) tbl;
  273. #else
  274.    tss_set(u_current_table_tsd, (void *) tbl);
  275.    u_current_table = (ThreadSafe) ? NULL : (void *) tbl;
  276. #endif
  277. }
  278.  
  279. /**
  280.  * Return pointer to current dispatch table for calling thread.
  281.  */
  282. struct mapi_table *
  283. u_current_get_table_internal(void)
  284. {
  285. #if defined(GLX_USE_TLS)
  286.    return u_current_table;
  287. #else
  288.    if (ThreadSafe)
  289.       return (struct mapi_table *) tss_get(u_current_table_tsd);
  290.    else
  291.       return (struct mapi_table *) u_current_table;
  292. #endif
  293. }
  294.