There is a possbile race that _glapi_Context is reset by another thread
after it is tested in GET_CURRENT_CONTEXT but before it is returned.  To
avoid the race in a lockless fashion, no threads should reset
_glapi_Context (or _glapi_Dispatch).

This patch renames ThreadSafe to _glapi_ThreadSafe and makes it global
so that it can be tested for thread-safe mode.  This also removes a
__builtin_expect so that multithreaded apps are not punished.
---
 src/mesa/glapi/glapi.c    |   32 ++++++++++++++++----------------
 src/mesa/glapi/glapi.h    |    3 ++-
 src/mesa/glapi/glthread.h |    2 +-
 3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/src/mesa/glapi/glapi.c b/src/mesa/glapi/glapi.c
index b9ab9c0..b05f80c 100644
--- a/src/mesa/glapi/glapi.c
+++ b/src/mesa/glapi/glapi.c
@@ -172,8 +172,8 @@ static GLint NoOpUnused(void)
  * There is a race condition in setting \c _glapi_Dispatch to \c NULL.  It is
  * possible for the original thread to be setting it at the same instant a new
  * thread, perhaps running on a different processor, is clearing it.  Because
- * of that, \c ThreadSafe, which can only ever be changed to \c GL_TRUE, is
- * used to determine whether or not the application is multithreaded.
+ * of that, \c _glapi_ThreadSafe, which can only ever be changed to \c GL_TRUE,
+ * is used to determine whether or not the application is multithreaded.
  * 
  * In the TLS case, the variables \c _glapi_Dispatch and \c _glapi_Context are
  * hardcoded to \c NULL.  Instead the TLS variables \c _glapi_tls_Dispatch and
@@ -199,7 +199,7 @@ PUBLIC const void *_glapi_Context = NULL;
 #if defined(THREADS)
 
 _glthread_DECLARE_STATIC_MUTEX(ThreadCheckMutex);
-static GLboolean ThreadSafe = GL_FALSE;  /**< In thread-safe mode? */
+GLboolean _glapi_ThreadSafe = GL_FALSE;  /**< In thread-safe mode? */
 _glthread_TSD _gl_DispatchTSD;           /**< Per-thread dispatch pointer */
 static _glthread_TSD ContextTSD;         /**< Per-thread context pointer */
 
@@ -235,7 +235,7 @@ _glapi_check_multithread(void)
    static unsigned long knownID;
    static GLboolean firstCall = GL_TRUE;
 
-   if (ThreadSafe)
+   if (_glapi_ThreadSafe)
       return;
 
    _glthread_LOCK_MUTEX(ThreadCheckMutex);
@@ -248,9 +248,12 @@ _glapi_check_multithread(void)
       firstCall = GL_FALSE;
    }
    else if (knownID != _glthread_GetID()) {
-      ThreadSafe = GL_TRUE;
-      _glapi_set_dispatch(NULL);
-      _glapi_set_context(NULL);
+      /*
+       * switch to thread-safe mode.  _glapi_Context and _glapi_Dispatch are no
+       * longer accessed after this point, except for raced by the first
+       * thread.  Because of the race, they cannot be reset.
+       */
+      _glapi_ThreadSafe = GL_TRUE;
    }
    _glthread_UNLOCK_MUTEX(ThreadCheckMutex);
 #endif
@@ -270,8 +273,9 @@ _glapi_set_context(void *context)
 #if defined(GLX_USE_TLS)
    _glapi_tls_Context = context;
 #elif defined(THREADS)
+   if (!_glapi_ThreadSafe)
+      _glapi_Context = context;
    _glthread_SetTSD(&ContextTSD, context);
-   _glapi_Context = (ThreadSafe) ? NULL : context;
 #else
    _glapi_Context = context;
 #endif
@@ -290,12 +294,7 @@ _glapi_get_context(void)
 #if defined(GLX_USE_TLS)
    return _glapi_tls_Context;
 #elif defined(THREADS)
-   if (ThreadSafe) {
-      return _glthread_GetTSD(&ContextTSD);
-   }
-   else {
-      return _glapi_Context;
-   }
+   return (_glapi_ThreadSafe) ? _glthread_GetTSD(&ContextTSD) : _glapi_Context;
 #else
    return _glapi_Context;
 #endif
@@ -510,8 +509,9 @@ _glapi_set_dispatch(struct _glapi_table *dispatch)
 #if defined(GLX_USE_TLS)
    _glapi_tls_Dispatch = dispatch;
 #elif defined(THREADS)
+   if (!_glapi_ThreadSafe)
+      _glapi_Dispatch = dispatch;
    _glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch);
-   _glapi_Dispatch = (ThreadSafe) ? NULL : dispatch;
 #else /*THREADS*/
    _glapi_Dispatch = dispatch;
 #endif /*THREADS*/
@@ -529,7 +529,7 @@ _glapi_get_dispatch(void)
 #if defined(GLX_USE_TLS)
    api = _glapi_tls_Dispatch;
 #elif defined(THREADS)
-   api = (ThreadSafe)
+   api = (_glapi_ThreadSafe)
      ? (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD)
      : _glapi_Dispatch;
 #else
diff --git a/src/mesa/glapi/glapi.h b/src/mesa/glapi/glapi.h
index 8f2cf66..e935195 100644
--- a/src/mesa/glapi/glapi.h
+++ b/src/mesa/glapi/glapi.h
@@ -91,10 +91,11 @@ extern __thread void * _glapi_tls_Context
 #else
 
 extern void *_glapi_Context;
+extern GLboolean _glapi_ThreadSafe;
 extern struct _glapi_table *_glapi_Dispatch;
 
 # ifdef THREADS
-#  define GET_CURRENT_CONTEXT(C)  GLcontext *C = (GLcontext *) (_glapi_Context 
? _glapi_Context : _glapi_get_context())
+#  define GET_CURRENT_CONTEXT(C)  GLcontext *C = (GLcontext *) 
((!_glapi_ThreadSafe) ? _glapi_Context : _glapi_get_context())
 # else
 #  define GET_CURRENT_CONTEXT(C)  GLcontext *C = (GLcontext *) _glapi_Context
 # endif
diff --git a/src/mesa/glapi/glthread.h b/src/mesa/glapi/glthread.h
index dfe09a9..5b19883 100644
--- a/src/mesa/glapi/glthread.h
+++ b/src/mesa/glapi/glthread.h
@@ -364,7 +364,7 @@ extern __thread struct _glapi_table * _glapi_tls_Dispatch
 #elif !defined(GL_CALL)
 # if defined(THREADS)
 #  define GET_DISPATCH() \
-   ((__builtin_expect( _glapi_Dispatch != NULL, 1 )) \
+   ((!_glapi_ThreadSafe) \
        ? _glapi_Dispatch : _glapi_get_dispatch())
 # else
 #  define GET_DISPATCH() _glapi_Dispatch
-- 
1.6.2.4


------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge  
This is your chance to win up to $100,000 in prizes! For a limited time, 
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize  
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
Mesa3d-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to