From 02986cb2cc1b1d47b26a653e9ae0fa508365f616 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 18 Apr 2005 16:59:53 +0000 Subject: Add support for pthreads and TLS to libGL for __glXLock / __glXUnlock and for tracking the current GLX context. This fixes bug #3024. --- src/glx/x11/glxclient.h | 34 +++++++++++++++++---- src/glx/x11/glxext.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 9 deletions(-) (limited to 'src/glx/x11') diff --git a/src/glx/x11/glxclient.h b/src/glx/x11/glxclient.h index 4356ee8cf9..83e1f27269 100644 --- a/src/glx/x11/glxclient.h +++ b/src/glx/x11/glxclient.h @@ -60,8 +60,10 @@ #include "GL/internal/glcore.h" #include "glapitable.h" #include "glxextensions.h" -#ifdef XTHREADS -#include "Xthreads.h" +#if defined( XTHREADS ) +# include "Xthreads.h" +#elif defined( PTHREADS ) +# include #endif #ifdef GLX_BUILT_IN_XMESA #include "realglx.h" /* just silences prototype warnings */ @@ -625,24 +627,44 @@ extern __GLXdisplayPrivate *__glXInitialize(Display*); extern int __glXDebug; /* This is per-thread storage in an MT environment */ -#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS) -extern __GLXcontext *__glXGetCurrentContext(void); +#if defined( XTHREADS ) || defined( PTHREADS ) + extern void __glXSetCurrentContext(__GLXcontext *c); + +# if defined( GLX_USE_TLS ) + +extern __thread void * __glX_tls_Context + __attribute__((tls_model("initial-exec"))); + +# define __glXGetCurrentContext() __glX_tls_Context + +# else + +extern __GLXcontext *__glXGetCurrentContext(void); + +# endif /* defined( GLX_USE_TLS ) */ + #else + extern __GLXcontext *__glXcurrentContext; #define __glXGetCurrentContext() __glXcurrentContext #define __glXSetCurrentContext(gc) __glXcurrentContext = gc -#endif + +#endif /* defined( XTHREADS ) || defined( PTHREADS ) */ /* ** Global lock for all threads in this address space using the GLX ** extension */ -#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS) +#if defined( XTHREADS ) extern xmutex_rec __glXmutex; #define __glXLock() xmutex_lock(&__glXmutex) #define __glXUnlock() xmutex_unlock(&__glXmutex) +#elif defined( PTHREADS ) +extern pthread_mutex_t __glXmutex; +#define __glXLock() pthread_mutex_lock(&__glXmutex) +#define __glXUnlock() pthread_mutex_unlock(&__glXmutex) #else #define __glXLock() #define __glXUnlock() diff --git a/src/glx/x11/glxext.c b/src/glx/x11/glxext.c index 2c2217ebc5..badaf9a559 100644 --- a/src/glx/x11/glxext.c +++ b/src/glx/x11/glxext.c @@ -52,7 +52,9 @@ #include "indirect_init.h" #include "glapi.h" #ifdef XTHREADS -#include "Xthreads.h" +# include "Xthreads.h" +#elif defined(PTHREADS) +# include #endif #include "glxextensions.h" #include "glcontextmodes.h" @@ -138,7 +140,7 @@ static __GLapi *IndirectAPI = NULL; * Current context management and locking */ -#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS) +#if defined( XTHREADS ) /* thread safe */ static GLboolean TSDinitialized = GL_FALSE; @@ -174,6 +176,77 @@ void __glXSetCurrentContext(__GLXcontext *c) /* Used by the __glXLock() and __glXUnlock() macros */ xmutex_rec __glXmutex; +#elif defined( PTHREADS ) + +pthread_mutex_t __glXmutex = PTHREAD_MUTEX_INITIALIZER; + +# if defined( GLX_USE_TLS ) + +/** + * Per-thread GLX context pointer. + * + * \c __glXSetCurrentContext is written is such a way that this pointer can + * \b never be \c NULL. This is important! Because of this + * \c __glXGetCurrentContext can be implemented as trivial macro. + */ +__thread void * __glX_tls_Context __attribute__((tls_model("initial-exec"))) + = &dummyContext; + +void __glXSetCurrentContext( __GLXcontext * c ) +{ + __glX_tls_Context = (c != NULL) ? c : &dummyContext; +} + +# else + +static pthread_once_t once_control = PTHREAD_ONCE_INIT; + +/** + * Per-thread data key. + * + * Once \c init_thread_data has been called, the per-thread data key will + * take a value of \c NULL. As each new thread is created the default + * value, in that thread, will be \c NULL. + */ +static pthread_key_t ContextTSD; + +/** + * Initialize the per-thread data key. + * + * This function is called \b exactly once per-process (not per-thread!) to + * initialize the per-thread data key. This is ideally done using the + * \c pthread_once mechanism. + */ +static void init_thread_data( void ) +{ + if ( pthread_key_create( & ContextTSD, NULL ) != 0 ) { + perror( "pthread_key_create" ); + exit( -1 ); + } +} + +void __glXSetCurrentContext( __GLXcontext * c ) +{ + pthread_once( & once_control, init_thread_data ); + pthread_setspecific( ContextTSD, c ); +} + +__GLXcontext * __glXGetCurrentContext( void ) +{ + void * v; + + pthread_once( & once_control, init_thread_data ); + + v = pthread_getspecific( ContextTSD ); + return (v == NULL) ? & dummyContext : (__GLXcontext *) v; +} + +# endif /* defined( GLX_USE_TLS ) */ + +#elif defined( THREADS ) + +#error Unknown threading method specified. + #else /* not thread safe */ @@ -1119,7 +1192,7 @@ __GLXdisplayPrivate *__glXInitialize(Display* dpy) XEDataObject dataObj; int major, minor; -#if defined(GLX_DIRECT_RENDERING) && defined(XTHREADS) +#if defined(XTHREADS) { static int firstCall = 1; if (firstCall) { -- cgit v1.2.3