Remove _glapi_check_multithread from the interface exported by the loader to

the driver.  The loader now takes care of this for the driver.

Remove _glapi_DispatchTSD and give _glapi_Dispatch its semantic (i.e.,
having a NULL value means that the application is multithreaded and
_glapi_get_dispatch must be called).

Gut all of the dispatch override code.  This removes _glapi_RealDispatch,
_glapi_tls_RealDispatch, _glapi_begin_dispatch_override,
_glapi_end_dispatch_override, and _glapi_get_override_dispatch.

Remove _glapi_get_proc_address, _glapi_get_proc_name, _glapi_get_version,
and _glapi_check_table from the loader / driver interface.

Reviewed by: Brian Paul
This commit is contained in:
Ian Romanick
2005-08-10 23:54:15 +00:00
parent 1b8d0f149e
commit 967b006f51
9 changed files with 896 additions and 1122 deletions

View File

@@ -133,122 +133,65 @@ static GLint NoOpUnused(void)
/***** BEGIN THREAD-SAFE DISPATCH *****/
/**
* \name Current dispatch and current context control variables
*
* Depending on whether or not multithreading is support, and the type of
* support available, several variables are used to store the current context
* pointer and the current dispatch table pointer. In the non-threaded case,
* the variables \c _glapi_Dispatch and \c _glapi_Context are used for this
* purpose.
*
* In the "normal" threaded case, the variables \c _glapi_Dispatch and
* \c _glapi_Context will be \c NULL if an application is detected as being
* multithreaded. Single-threaded applications will use \c _glapi_Dispatch
* and \c _glapi_Context just like the case without any threading support.
* When \c _glapi_Dispatch and \c _glapi_Context are \c NULL, the thread state
* data \c _gl_DispatchTSD and \c ContextTSD are used. Drivers and the
* static dispatch functions access these variables via \c _glapi_get_dispatch
* and \c _glapi_get_context.
*
* 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.
*
* 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
* \c _glapi_tls_Context are used. Having \c _glapi_Dispatch and
* \c _glapi_Context be hardcoded to \c NULL maintains binary compatability
* between TLS enabled loaders and non-TLS DRI drivers.
*/
/*@{*/
#if defined(GLX_USE_TLS)
PUBLIC __thread struct _glapi_table * _glapi_tls_Dispatch
__attribute__((tls_model("initial-exec")))
= (struct _glapi_table *) __glapi_noop_table;
PUBLIC __thread void * _glapi_tls_Context
__attribute__((tls_model("initial-exec")));
PUBLIC const struct _glapi_table *_glapi_Dispatch = NULL;
PUBLIC const void *_glapi_Context = NULL;
#else
#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
*
* If thread-safety is supported, there are two potential mechanisms that can
* be used. The old-style mechanism would set \c _glapi_Dispatch to a special
* thread-safe dispatch table. These dispatch routines would call
* \c _glapi_get_dispatch to get the actual dispatch pointer. In this
* setup \c _glapi_Dispatch could never be \c NULL. This dual layered
* dispatch setup performed great for single-threaded apps, but didn't
* perform well for multithreaded apps.
*
* In the new mechansim, there are two variables. The first is
* \c _glapi_DispatchTSD. In the single-threaded case, this variable points
* to the dispatch table. In the multi-threaded case, this variable is
* \c NULL, and thread-specific variable \c _gl_DispatchTSD points to the
* actual dispatch table. \c _glapi_DispatchTSD is used to signal to the
* static dispatch functions to call \c _glapi_get_dispatch to get the real
* dispatch table.
*
* There is a race condition in setting \c _glapi_DispatchTSD 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.
*/
/*@{*/
static GLboolean ThreadSafe = GL_FALSE; /**< In thread-safe mode? */
_glthread_TSD _gl_DispatchTSD; /**< Per-thread dispatch pointer */
static _glthread_TSD RealDispatchTSD; /**< only when using override */
static _glthread_TSD ContextTSD; /**< Per-thread context pointer */
/*@}*/
#endif /* defined(GLX_USE_TLS) */
#endif /* defined(THREADS) */
#define DISPATCH_TABLE_NAME __glapi_threadsafe_table
#define UNUSED_TABLE_NAME __unused_threadsafe_functions
#define TABLE_ENTRY(name) (_glapi_proc) gl##name
static GLint glUnused(void)
{
return 0;
}
#include "glapitemp.h"
#endif
/***** END THREAD-SAFE DISPATCH *****/
#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.
*/
/*@{*/
PUBLIC const struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
PUBLIC const struct _glapi_table *_glapi_DispatchTSD = NULL;
PUBLIC const void *_glapi_Context = NULL;
/*@}*/
#else
PUBLIC struct _glapi_table *_glapi_Dispatch = (struct _glapi_table *) __glapi_noop_table;
#if defined( THREADS )
PUBLIC struct _glapi_table *_glapi_DispatchTSD = (struct _glapi_table *) __glapi_noop_table;
#endif
PUBLIC struct _glapi_table *_glapi_RealDispatch = (struct _glapi_table *) __glapi_noop_table;
/* Used when thread safety disabled */
PUBLIC struct _glapi_table *_glapi_Dispatch =
(struct _glapi_table *) __glapi_noop_table;
PUBLIC void *_glapi_Context = NULL;
#endif /* defined(GLX_USE_TLS) */
static GLboolean DispatchOverride = GL_FALSE;
/*@}*/
/**
@@ -272,7 +215,7 @@ str_dup(const char *str)
* We should call this periodically from a function such as glXMakeCurrent
* in order to test if multiple threads are being used.
*/
PUBLIC void
void
_glapi_check_multithread(void)
{
#if defined(THREADS) && !defined(GLX_USE_TLS)
@@ -309,7 +252,6 @@ _glapi_set_context(void *context)
#if defined(GLX_USE_TLS)
_glapi_tls_Context = context;
#elif defined(THREADS)
(void) __unused_threadsafe_functions; /* silence a warning */
_glthread_SetTSD(&ContextTSD, context);
_glapi_Context = (ThreadSafe) ? NULL : context;
#else
@@ -367,40 +309,12 @@ _glapi_set_dispatch(struct _glapi_table *dispatch)
#endif
#if defined(GLX_USE_TLS)
if (DispatchOverride) {
_glapi_tls_RealDispatch = dispatch;
}
else {
_glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch);
_glapi_tls_Dispatch = dispatch;
}
_glapi_tls_Dispatch = dispatch;
#elif defined(THREADS)
if (DispatchOverride) {
_glthread_SetTSD(&RealDispatchTSD, (void *) dispatch);
if (ThreadSafe)
_glapi_RealDispatch = (struct _glapi_table*) __glapi_threadsafe_table;
else
_glapi_RealDispatch = dispatch;
}
else {
/* normal operation */
_glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch);
if (ThreadSafe) {
_glapi_Dispatch = (struct _glapi_table *) __glapi_threadsafe_table;
_glapi_DispatchTSD = NULL;
}
else {
_glapi_Dispatch = dispatch;
_glapi_DispatchTSD = dispatch;
}
}
_glthread_SetTSD(&_gl_DispatchTSD, (void *) dispatch);
_glapi_Dispatch = (ThreadSafe) ? NULL : dispatch;
#else /*THREADS*/
if (DispatchOverride) {
_glapi_RealDispatch = dispatch;
}
else {
_glapi_Dispatch = dispatch;
}
_glapi_Dispatch = dispatch;
#endif /*THREADS*/
}
@@ -412,128 +326,20 @@ _glapi_set_dispatch(struct _glapi_table *dispatch)
PUBLIC struct _glapi_table *
_glapi_get_dispatch(void)
{
struct _glapi_table * api;
#if defined(GLX_USE_TLS)
struct _glapi_table * api = (DispatchOverride)
? _glapi_tls_RealDispatch : _glapi_tls_Dispatch;
api = _glapi_tls_Dispatch;
#elif defined(THREADS)
api = (ThreadSafe)
? (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD)
: _glapi_Dispatch;
#else
api = _glapi_Dispatch;
#endif
assert( api != NULL );
return api;
#elif defined(THREADS)
if (ThreadSafe) {
if (DispatchOverride) {
return (struct _glapi_table *) _glthread_GetTSD(&RealDispatchTSD);
}
else {
return (struct _glapi_table *) _glthread_GetTSD(&_gl_DispatchTSD);
}
}
else {
if (DispatchOverride) {
assert(_glapi_RealDispatch);
return _glapi_RealDispatch;
}
else {
assert(_glapi_DispatchTSD);
return _glapi_DispatchTSD;
}
}
#else
return _glapi_Dispatch;
#endif
}
/*
* Notes on dispatch overrride:
*
* Dispatch override allows an external agent to hook into the GL dispatch
* mechanism before execution goes into the core rendering library. For
* example, a trace mechanism would insert itself as an overrider, print
* logging info for each GL function, then dispatch to the real GL function.
*
* libGLS (GL Stream library) is another agent that might use override.
*
* We don't allow more than one layer of overriding at this time.
* In the future we may allow nested/layered override. In that case
* _glapi_begin_dispatch_override() will return an override layer,
* _glapi_end_dispatch_override(layer) will remove an override layer
* and _glapi_get_override_dispatch(layer) will return the dispatch
* table for a given override layer. layer = 0 will be the "real"
* dispatch table.
*/
/*
* Return: dispatch override layer number.
*/
PUBLIC int
_glapi_begin_dispatch_override(struct _glapi_table *override)
{
struct _glapi_table *real = _glapi_get_dispatch();
assert(!DispatchOverride); /* can't nest at this time */
DispatchOverride = GL_TRUE;
_glapi_set_dispatch(real);
#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;
_glapi_DispatchTSD = NULL;
}
else {
_glapi_Dispatch = override;
_glapi_DispatchTSD = override;
}
#else
_glapi_Dispatch = override;
#endif
return 1;
}
PUBLIC void
_glapi_end_dispatch_override(int layer)
{
struct _glapi_table *real = _glapi_get_dispatch();
(void) layer;
DispatchOverride = GL_FALSE;
_glapi_set_dispatch(real);
/* the rest of this isn't needed, just play it safe */
#if defined(GLX_USE_TLS)
_glapi_tls_RealDispatch = NULL;
#else
# if defined(THREADS)
_glthread_SetTSD(&RealDispatchTSD, NULL);
# endif
_glapi_RealDispatch = NULL;
#endif
}
PUBLIC struct _glapi_table *
_glapi_get_override_dispatch(int layer)
{
if (layer == 0) {
return _glapi_get_dispatch();
}
else {
if (DispatchOverride) {
#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;
#endif
}
else {
return NULL;
}
}
}
@@ -1063,7 +869,7 @@ _glapi_get_proc_offset(const char *funcName)
* in the name of static functions, try generating a new API entrypoint on
* the fly with assembly language.
*/
PUBLIC _glapi_proc
_glapi_proc
_glapi_get_proc_address(const char *funcName)
{
struct _glapi_function * entry;
@@ -1101,7 +907,7 @@ _glapi_get_proc_address(const char *funcName)
* Return the name of the function at the given dispatch offset.
* This is only intended for debugging.
*/
PUBLIC const char *
const char *
_glapi_get_proc_name(GLuint offset)
{
GLuint i;
@@ -1136,22 +942,11 @@ _glapi_get_dispatch_table_size(void)
/**
* Get API dispatcher version string.
*/
PUBLIC const char *
_glapi_get_version(void)
{
return "20021001"; /* YYYYMMDD */
}
/**
* Make sure there are no NULL pointers in the given dispatch table.
* Intended for debugging purposes.
*/
PUBLIC void
void
_glapi_check_table(const struct _glapi_table *table)
{
#ifdef DEBUG