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