Index: configs/linux-dri =================================================================== RCS file: /cvs/mesa/Mesa/configs/linux-dri,v retrieving revision 1.17 diff -u -d -r1.17 linux-dri --- configs/linux-dri 29 Oct 2004 00:10:43 -0000 1.17 +++ configs/linux-dri 10 Nov 2004 20:11:02 -0000 @@ -17,7 +17,7 @@ CFLAGS = -DDRI_NEW_INTERFACE_ONLY $(WARN_FLAGS) -g $(OPT_FLAGS) $(ASM_FLAGS) \ -std=c99 $(PIC_FLAGS) -ffast-math $(SOURCE_FLAGS) -DPTHREADS \ - -DUSE_EXTERNAL_DXTN_LIB=1 \ + -DUSE_EXTERNAL_DXTN_LIB=1 -DGLX_USE_TLS \ -I/usr/X11R6/include -I/usr/X11R6/include/X11/extensions CXXFLAGS = -DDRI_NEW_INTERFACE_ONLY $(WARN_FLAGS) -g $(OPT_FLAGS) -fPIC \ @@ -34,7 +34,7 @@ # Directories -SRC_DIRS = mesa glu glut/glx glw glx/x11 +SRC_DIRS = mesa glx/x11 glu glut/glx glw DRIVER_DIRS = dri PROGRAM_DIRS = WINDOW_SYSTEM=dri Index: src/mesa/glapi/gl_x86_asm.py =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/glapi/gl_x86_asm.py,v retrieving revision 1.6 diff -u -d -r1.6 gl_x86_asm.py --- src/mesa/glapi/gl_x86_asm.py 25 Aug 2004 15:10:51 -0000 1.6 +++ src/mesa/glapi/gl_x86_asm.py 10 Nov 2004 20:11:02 -0000 @@ -87,7 +87,17 @@ print '# define THREADS' print '#endif' print '' - print '#if defined(PTHREADS)' + print '#ifdef GLX_USE_TLS' + print '' + print '# define GL_STUB(fn,off,fn_alt)\t\t\t\\' + print 'ALIGNTEXT16;\t\t\t\t\t\t\\' + print 'GLOBL_FN(GL_PREFIX(fn, fn_alt));\t\t\t\\' + print 'GL_PREFIX(fn, fn_alt):\t\t\t\t\t\\' + print '\tCALL(get_dispatch) ;\t\t\t\t\\' + print '\tNOP ;\t\t\t\t\t\t\\' + print '\tJMP(GL_OFFSET(off))' + print '' + print '#elif defined(PTHREADS)' print '# define GL_STUB(fn,off,fn_alt)\t\t\t\\' print 'ALIGNTEXT16;\t\t\t\t\t\t\\' print 'GLOBL_FN(GL_PREFIX(fn, fn_alt));\t\t\t\\' @@ -120,7 +130,14 @@ print '' print 'SEG_TEXT' print '' - print '#ifdef PTHREADS' + print '#ifdef GLX_USE_TLS' + print '' + print 'ALIGNTEXT16' + print 'GLNAME(get_dispatch):' + print '\tmovl\t%gs:_glapi_tls_Dispatch@NTPOFF, %eax' + print '\tret' + print '' + print '#elif defined(PTHREADS)' print 'EXTERN GLNAME(_glapi_Dispatch)' print 'EXTERN GLNAME(_gl_DispatchTSD)' print 'EXTERN GLNAME(pthread_getspecific)' @@ -143,6 +160,19 @@ def printRealFooter(self): print '' + print '#if defined(GLX_USE_TLS) && defined(__linux__)' + print ' .section ".note.ABI-tag", "a"' + print ' .p2align 2' + print ' .long 1f - 0f /* name length */' + print ' .long 3f - 2f /* data length */' + print ' .long 1 /* note length */' + print '0: .asciz "GNU" /* vendor name */' + print '1: .p2align 2' + print '2: .long 0 /* note data: the ABI tag */' + print ' .long 2,4,20 /* Minimum kernel version w/TLS */' + print '3: .p2align 2 /* pad out section */' + print '#endif /* GLX_USE_TLS */' + print '' print '#endif /* __WIN32__ */' return Index: src/mesa/glapi/glapi.c =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/glapi/glapi.c,v retrieving revision 1.83 diff -u -d -r1.83 glapi.c --- src/mesa/glapi/glapi.c 5 Nov 2004 18:32:02 -0000 1.83 +++ src/mesa/glapi/glapi.c 10 Nov 2004 20:11:03 -0000 @@ -134,6 +134,28 @@ #if defined(THREADS) +#if defined(GLX_USE_TLS) + +__thread struct _glapi_table * _glapi_tls_Dispatch + __attribute__((tls_model("initial-exec"))) + = (struct _glapi_table *) __glapi_noop_table; + +static __thread struct _glapi_table * _glapi_tls_RealDispatch + __attribute__((tls_model("initial-exec"))) + = (struct _glapi_table *) __glapi_noop_table; + +__thread void * _glapi_tls_Context + __attribute__((tls_model("initial-exec"))); + +/** + * Legacy per-thread dispatch pointer. This is only needed to support + * non-TLS DRI drivers. + */ + +_glthread_TSD _gl_DispatchTSD; + +#else + /** * \name Multi-threaded control support variables * @@ -167,6 +189,7 @@ static _glthread_TSD ContextTSD; /**< Per-thread context pointer */ /*@}*/ +#endif /* defined(GLX_USE_TLS) */ #define DISPATCH_TABLE_NAME __glapi_threadsafe_table #define UNUSED_TABLE_NAME __usused_threadsafe_functions @@ -186,16 +209,41 @@ +#if defined(GLX_USE_TLS) + +/** + * \name Old dispatch pointers + * + * Very old DRI based drivers assume that \c _glapi_Dispatch will never be + * \c NULL. Becuase of that, special "thread-safe" dispatch functions are + * needed here. Slightly more recent drivers detect the multi-threaded case + * by \c _glapi_DispatchTSD being \c NULL. + * + * \deprecated + * + * \warning + * \c _glapi_RealDispatch does not exist in TLS builds. I don't think it was + * ever used outside libGL.so, so this should be safe. + */ +/*@{*/ +const struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table; +const struct _glapi_table *_glapi_DispatchTSD = NULL; +const void *_glapi_Context = NULL; +/*@}*/ + +#else + struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table; #if defined( THREADS ) struct _glapi_table *_glapi_DispatchTSD = (struct _glapi_table *) __glapi_noop_table; #endif struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table; - - /* Used when thread safety disabled */ void *_glapi_Context = NULL; +#endif /* defined(GLX_USE_TLS) */ + + static GLboolean DispatchOverride = GL_FALSE; @@ -224,7 +272,7 @@ void _glapi_check_multithread(void) { -#if defined(THREADS) +#if defined(THREADS) && !defined(GLX_USE_TLS) if (!ThreadSafe) { static unsigned long knownID; static GLboolean firstCall = GL_TRUE; @@ -246,7 +294,7 @@ -/* +/** * Set the current context pointer for this thread. * The context pointer is an opaque type which should be cast to * void from the real context pointer type. @@ -254,7 +302,9 @@ void _glapi_set_context(void *context) { -#if defined(THREADS) +#if defined(GLX_USE_TLS) + _glapi_tls_Context = context; +#elif defined(THREADS) _glthread_SetTSD(&ContextTSD, context); _glapi_Context = (ThreadSafe) ? NULL : context; #else @@ -264,7 +314,7 @@ -/* +/** * Get the current context pointer for this thread. * The context pointer is an opaque type which should be cast from * void to the real context pointer type. @@ -272,7 +322,9 @@ void * _glapi_get_context(void) { -#if defined(THREADS) +#if defined(GLX_USE_TLS) + return _glapi_tls_Context; +#elif defined(THREADS) if (ThreadSafe) { return _glthread_GetTSD(&ContextTSD); } @@ -302,7 +354,15 @@ } #endif -#if defined(THREADS) +#if defined(GLX_USE_TLS) + if (DispatchOverride) { + _glapi_tls_RealDispatch = dispatch; + } + else { + _glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch); + _glapi_tls_Dispatch = dispatch; + } +#elif defined(THREADS) if (DispatchOverride) { _glthread_SetTSD(&RealDispatchTSD, (void *) dispatch); if (ThreadSafe) @@ -340,7 +400,13 @@ struct _glapi_table * _glapi_get_dispatch(void) { -#if defined(THREADS) +#if defined(GLX_USE_TLS) + struct _glapi_table * api = (DispatchOverride) + ? _glapi_tls_RealDispatch : _glapi_tls_Dispatch; + + assert( api != NULL ); + return api; +#elif defined(THREADS) if (ThreadSafe) { if (DispatchOverride) { return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD); @@ -397,7 +463,10 @@ _glapi_set_dispatch(real); -#if defined(THREADS) +#if defined(GLX_USE_TLS) + _glthread_SetTSD(&_gl_DispatchTSD, (void *) override); + _glapi_tls_Dispatch = override; +#elif defined(THREADS) _glthread_SetTSD(&_gl_DispatchTSD, (void *) override); if ( ThreadSafe ) { _glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table; @@ -422,7 +491,9 @@ DispatchOverride = GL_FALSE; _glapi_set_dispatch(real); /* the rest of this isn't needed, just play it safe */ -#if defined(THREADS) +#if defined(GLX_USE_TLS) + _glapi_tls_RealDispatch = NULL; +#elif defined(THREADS) _glthread_SetTSD(&RealDispatchTSD, NULL); #endif _glapi_RealDispatch = NULL; @@ -437,7 +508,9 @@ } else { if (DispatchOverride) { -#if defined(THREADS) +#if defined(GLX_USE_TLS) + return (struct _glapi_table *) _glapi_tls_Dispatch; +#elif defined(THREADS) return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD); #else return _glapi_Dispatch; @@ -500,7 +573,7 @@ #ifdef USE_X86_ASM extern const GLubyte gl_dispatch_functions_start[]; -# if defined(THREADS) +# if defined(THREADS) && !defined(GLX_USE_TLS) # define X86_DISPATCH_FUNCTION_SIZE 32 # else # define X86_DISPATCH_FUNCTION_SIZE 16 @@ -583,10 +656,14 @@ extern void __glapi_sparc_icache_flush(unsigned int *); #endif -/* +/** * Generate a dispatch function (entrypoint) which jumps through * the given slot number (offset) in the current dispatch table. * We need assembly language in order to accomplish this. + * + * \todo + * A TLS version of this is needed. The code right now will work on x86 in + * TLS mode, but it will be inefficient. */ static void * generate_entrypoint(GLuint functionOffset) Index: src/mesa/glapi/glapi.h =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/glapi/glapi.h,v retrieving revision 1.22 diff -u -d -r1.22 glapi.h --- src/mesa/glapi/glapi.h 10 Sep 2004 00:45:12 -0000 1.22 +++ src/mesa/glapi/glapi.h 10 Nov 2004 20:11:03 -0000 @@ -52,10 +52,17 @@ typedef void (*_glapi_warning_func)(void *ctx, const char *str, ...); -extern void *_glapi_Context; +#if defined (GLX_USE_TLS) + +const extern struct _glapi_table *_glapi_Dispatch __attribute__ ((deprecated)); +const extern void *_glapi_Context __attribute__ ((deprecated)); + +#else extern struct _glapi_table *_glapi_Dispatch; +extern void *_glapi_Context; +#endif /* defined (GLX_USE_TLS) */ extern void _glapi_noop_enable_warnings(GLboolean enable); Index: src/mesa/glapi/glthread.h =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/glapi/glthread.h,v retrieving revision 1.16 diff -u -d -r1.16 glthread.h --- src/mesa/glapi/glthread.h 14 Aug 2004 09:48:57 -0000 1.16 +++ src/mesa/glapi/glthread.h 10 Nov 2004 20:11:03 -0000 @@ -307,7 +307,14 @@ extern void _glthread_SetTSD(_glthread_TSD *, void *); -#ifndef GL_CALL +#if defined(GLX_USE_TLS) + +extern __thread struct _glapi_table * _glapi_tls_Dispatch + __attribute__((tls_model("initial-exec"))); + +# define GL_CALL(name) (*(_glapi_tls_Dispatch-> name)) + +#elif !defined(GL_CALL) # if defined(THREADS) extern struct _glapi_table * _glapi_DispatchTSD; # define GL_CALL(name) \ Index: src/mesa/x86/glapi_x86.S =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/x86/glapi_x86.S,v retrieving revision 1.44 diff -u -d -r1.44 glapi_x86.S --- src/mesa/x86/glapi_x86.S 28 Oct 2004 11:14:03 -0000 1.44 +++ src/mesa/x86/glapi_x86.S 10 Nov 2004 20:11:04 -0000 @@ -57,7 +57,17 @@ # define THREADS #endif -#if defined(PTHREADS) +#ifdef GLX_USE_TLS + +# define GL_STUB(fn,off,fn_alt) \ +ALIGNTEXT16; \ +GLOBL_FN(GL_PREFIX(fn, fn_alt)); \ +GL_PREFIX(fn, fn_alt): \ + CALL(get_dispatch) ; \ + NOP ; \ + JMP(GL_OFFSET(off)) + +#elif defined(PTHREADS) # define GL_STUB(fn,off,fn_alt) \ ALIGNTEXT16; \ GLOBL_FN(GL_PREFIX(fn, fn_alt)); \ @@ -90,7 +100,14 @@ SEG_TEXT -#ifdef PTHREADS +#ifdef GLX_USE_TLS + +ALIGNTEXT16 +GLNAME(get_dispatch): + movl %gs:_glapi_tls_Dispatch@NTPOFF, %eax + ret + +#elif defined(PTHREADS) EXTERN GLNAME(_glapi_Dispatch) EXTERN GLNAME(_gl_DispatchTSD) EXTERN GLNAME(pthread_getspecific) @@ -1070,4 +1087,17 @@ GL_STUB(PointParameterfSGIS, _gloffset_PointParameterfEXT, PointParameterfSGIS@8) GL_STUB(PointParameterfvSGIS, _gloffset_PointParameterfvEXT, PointParameterfvSGIS@8) +#if defined(GLX_USE_TLS) && defined(__linux__) + .section ".note.ABI-tag", "a" + .p2align 2 + .long 1f - 0f /* name length */ + .long 3f - 2f /* data length */ + .long 1 /* note length */ +0: .asciz "GNU" /* vendor name */ +1: .p2align 2 +2: .long 0 /* note data: the ABI tag */ + .long 2,4,20 /* Minimum kernel version w/TLS */ +3: .p2align 2 /* pad out section */ +#endif /* GLX_USE_TLS */ + #endif /* __WIN32__ */ Index: src/glx/x11/dispatch.c =================================================================== RCS file: /cvs/mesa/Mesa/src/glx/x11/dispatch.c,v retrieving revision 1.1 diff -u -d -r1.1 dispatch.c --- src/glx/x11/dispatch.c 25 Oct 2004 21:09:16 -0000 1.1 +++ src/glx/x11/dispatch.c 10 Nov 2004 20:11:04 -0000 @@ -56,15 +56,10 @@ #define NAME(func) gl##func #define DISPATCH(func, args, msg) \ - const struct _glapi_table *dispatch; \ - dispatch = _glapi_Dispatch ? _glapi_Dispatch : _glapi_get_dispatch();\ - (dispatch->func) args + GL_CALL(func) args #define RETURN_DISPATCH(func, args, msg) \ - const struct _glapi_table *dispatch; \ - dispatch = _glapi_Dispatch ? _glapi_Dispatch : _glapi_get_dispatch();\ - return (dispatch->func) args - + return GL_CALL(func) args #include "glapitemp.h" Index: src/glx/x11/dri_glx.c =================================================================== RCS file: /cvs/mesa/Mesa/src/glx/x11/dri_glx.c,v retrieving revision 1.1 diff -u -d -r1.1 dri_glx.c --- src/glx/x11/dri_glx.c 25 Oct 2004 21:09:16 -0000 1.1 +++ src/glx/x11/dri_glx.c 10 Nov 2004 20:11:04 -0000 @@ -119,18 +119,26 @@ -/* - * Extract the ith directory path out of a colon-separated list of - * paths. - * Input: - * index - index of path to extract (starting at zero) - * paths - the colon-separated list of paths - * dirLen - max length of result to store in - * Output: - * dir - the extracted directory path, dir[0] will be zero when - * extraction fails. +/** + * Extract the ith directory path out of a colon-separated list of paths. No + * more than \c dirLen characters, including the terminating \c NUL, will be + * written to \c dir. + * + * \param index Index of path to extract (starting at zero) + * \param paths The colon-separated list of paths + * \param dirLen Maximum length of result to store in \c dir + * \param dir Buffer to hold the extracted directory path + * + * \returns + * The number of characters that would have been written to \c dir had there + * been enough room. This does not include the terminating \c NUL. When + * extraction fails, zero will be returned. + * + * \todo + * It seems like this function could be rewritten to use \c strchr. */ -static void ExtractDir(int index, const char *paths, int dirLen, char *dir) +static size_t +ExtractDir(int index, const char *paths, int dirLen, char *dir) { int i, len; const char *start, *end; @@ -146,7 +154,7 @@ else if (*start == 0) { /* end of string and couldn't find ith colon */ dir[0] = 0; - return; + return 0; } else { start++; @@ -168,22 +176,27 @@ len = dirLen - 1; strncpy(dir, start, len); dir[len] = 0; + + return( end - start ); } -/* - * Try to dlopen() the named driver. This function adds the - * "_dri.so" suffix to the driver name and searches the - * directories specified by the LIBGL_DRIVERS_PATH env var - * in order to find the driver. - * Input: - * driverName - a name like "tdfx", "i810", "mga", etc. - * Return: - * handle from dlopen, or NULL if driver file not found. +/** + * Try to \c dlopen the named driver. + * + * This function adds the "_dri.so" suffix to the driver name and searches the + * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in + * order to find the driver. + * + * \param driverName - a name like "tdfx", "i810", "mga", etc. + * + * \returns + * A handle from \c dlopen, or \c NULL if driver file not found. */ static __DRIdriver *OpenDriver(const char *driverName) { char *libPaths = NULL; + char libDir[1000]; int i; __DRIdriver *driver; @@ -204,16 +217,27 @@ if (!libPaths) libPaths = DEFAULT_DRIVER_DIR; - for (i = 0; ; i++) { - char libDir[1000], realDriverName[200]; - void *handle; - ExtractDir(i, libPaths, 1000, libDir); - if (!libDir[0]) - break; /* ran out of paths to search */ - snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName); + for ( i = 0 ; ExtractDir(i, libPaths, 1000, libDir) != 0 ; i++ ) { + char realDriverName[200]; + void *handle = NULL; + + + /* If TLS support is enabled, try to open the TLS version of the driver + * binary first. If that fails, try the non-TLS version. + */ +#ifdef GLX_USE_TLS + snprintf(realDriverName, 200, "%s/tls/%s_dri.so", libDir, driverName); InfoMessageF("OpenDriver: trying %s\n", realDriverName); handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); - if (handle) { +#endif + + if ( handle == NULL ) { + snprintf(realDriverName, 200, "%s/%s_dri.so", libDir, driverName); + InfoMessageF("OpenDriver: trying %s\n", realDriverName); + handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); + } + + if ( handle != NULL ) { /* allocate __DRIdriver struct */ driver = (__DRIdriver *) Xmalloc(sizeof(__DRIdriver)); if (!driver)