Implement fork-handling and library teardown paths
- Define a function __glXThreadInitialize() which gets called when entering any GLX entrypoint, or when __glXGetDynDispatch() is called by a vendor-provided GLX extension entrypoint. This function detects if a fork occurred since the last entrypoint was called, and performs fork recovery if needed. - Implement __glXFini() so that libGLX cleans up allocated resources when it is unloaded. These paths make heavy use of the LKDHASH_TEARDOWN() macro that was implemented in a previous commit. Signed-off-by: Brian Nguyen <brnguyen@nvidia.com>
This commit is contained in:
parent
dc2f27980a
commit
d39e01a307
238
src/GLX/libglx.c
238
src/GLX/libglx.c
|
@ -35,6 +35,8 @@
|
|||
#include <X11/Xproto.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libglxthread.h"
|
||||
#include "libglxabipriv.h"
|
||||
|
@ -107,6 +109,8 @@ static void ThreadCreateTSDContextOnce(void)
|
|||
|
||||
PUBLIC XVisualInfo* glXChooseVisual(Display *dpy, int screen, int *attrib_list)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
return pDispatch->glx14ep.chooseVisual(dpy, screen, attrib_list);
|
||||
|
@ -133,6 +137,8 @@ PUBLIC void glXCopyContext(Display *dpy, GLXContext src, GLXContext dst,
|
|||
PUBLIC GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis,
|
||||
GLXContext share_list, Bool direct)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = vis->screen;
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -146,6 +152,8 @@ PUBLIC GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis,
|
|||
|
||||
PUBLIC void glXDestroyContext(Display *dpy, GLXContext context)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromContext(context);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -157,6 +165,8 @@ PUBLIC void glXDestroyContext(Display *dpy, GLXContext context)
|
|||
|
||||
PUBLIC GLXPixmap glXCreateGLXPixmap(Display *dpy, XVisualInfo *vis, Pixmap pixmap)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = vis->screen;
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -170,6 +180,8 @@ PUBLIC GLXPixmap glXCreateGLXPixmap(Display *dpy, XVisualInfo *vis, Pixmap pixma
|
|||
|
||||
PUBLIC void glXDestroyGLXPixmap(Display *dpy, GLXPixmap pix)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, pix);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -181,6 +193,8 @@ PUBLIC void glXDestroyGLXPixmap(Display *dpy, GLXPixmap pix)
|
|||
|
||||
PUBLIC int glXGetConfig(Display *dpy, XVisualInfo *vis, int attrib, int *value)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch;
|
||||
|
||||
if (!dpy || !vis || !value) {
|
||||
|
@ -194,12 +208,16 @@ PUBLIC int glXGetConfig(Display *dpy, XVisualInfo *vis, int attrib, int *value)
|
|||
|
||||
PUBLIC GLXContext glXGetCurrentContext(void)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
return __glXGetCurrentContext();
|
||||
}
|
||||
|
||||
|
||||
PUBLIC GLXDrawable glXGetCurrentDrawable(void)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
__GLXAPIState *apiState = __glXGetCurrentAPIState();
|
||||
return apiState->currentDraw;
|
||||
}
|
||||
|
@ -207,6 +225,8 @@ PUBLIC GLXDrawable glXGetCurrentDrawable(void)
|
|||
|
||||
PUBLIC Bool glXIsDirect(Display *dpy, GLXContext context)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromContext(context);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -249,6 +269,12 @@ static __GLXAPIState *CreateAPIState(glvnd_thread_t tid)
|
|||
return apiState;
|
||||
}
|
||||
|
||||
/* NOTE this assumes the __glXAPIStateHash lock is taken! */
|
||||
static void CleanupAPIStateEntry(void *unused, __GLXAPIState *apiState)
|
||||
{
|
||||
free(apiState->glas.id);
|
||||
}
|
||||
|
||||
/* NOTE this assumes the __glXAPIStateHash lock is taken! */
|
||||
static __GLXAPIState *LookupAPIState(glvnd_thread_t tid)
|
||||
{
|
||||
|
@ -529,6 +555,8 @@ static void SaveCurrentValues(GLXDrawable *pDraw,
|
|||
|
||||
PUBLIC Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext context)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch;
|
||||
Bool ret;
|
||||
GLXDrawable oldDraw, oldRead;
|
||||
|
@ -604,6 +632,8 @@ PUBLIC Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext contex
|
|||
|
||||
PUBLIC Bool glXQueryExtension(Display *dpy, int *error_base, int *event_base)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
/*
|
||||
* There isn't enough information to dispatch to a vendor's
|
||||
* implementation, so handle the request here.
|
||||
|
@ -624,6 +654,8 @@ PUBLIC Bool glXQueryExtension(Display *dpy, int *error_base, int *event_base)
|
|||
|
||||
PUBLIC Bool glXQueryVersion(Display *dpy, int *major, int *minor)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
/*
|
||||
* There isn't enough information to dispatch to a vendor's
|
||||
* implementation, so handle the request here.
|
||||
|
@ -681,6 +713,8 @@ PUBLIC Bool glXQueryVersion(Display *dpy, int *major, int *minor)
|
|||
|
||||
PUBLIC void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, drawable);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -690,6 +724,8 @@ PUBLIC void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
|
|||
|
||||
PUBLIC void glXUseXFont(Font font, int first, int count, int list_base)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetCurrentDispatch();
|
||||
|
||||
pDispatch->glx14ep.useXFont(font, first, count, list_base);
|
||||
|
@ -698,6 +734,8 @@ PUBLIC void glXUseXFont(Font font, int first, int count, int list_base)
|
|||
|
||||
PUBLIC void glXWaitGL(void)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetCurrentDispatch();
|
||||
|
||||
pDispatch->glx14ep.waitGL();
|
||||
|
@ -706,6 +744,8 @@ PUBLIC void glXWaitGL(void)
|
|||
|
||||
PUBLIC void glXWaitX(void)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetCurrentDispatch();
|
||||
|
||||
pDispatch->glx14ep.waitX();
|
||||
|
@ -716,6 +756,8 @@ PUBLIC void glXWaitX(void)
|
|||
|
||||
PUBLIC const char *glXGetClientString(Display *dpy, int name)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
int num_screens = XScreenCount(dpy);
|
||||
int screen;
|
||||
size_t n = CLIENT_STRING_BUFFER_SIZE - 1;
|
||||
|
@ -757,6 +799,8 @@ PUBLIC const char *glXGetClientString(Display *dpy, int name)
|
|||
|
||||
PUBLIC const char *glXQueryServerString(Display *dpy, int screen, int name)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
return pDispatch->glx14ep.queryServerString(dpy, screen, name);
|
||||
|
@ -765,6 +809,8 @@ PUBLIC const char *glXQueryServerString(Display *dpy, int screen, int name)
|
|||
|
||||
PUBLIC const char *glXQueryExtensionsString(Display *dpy, int screen)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
return pDispatch->glx14ep.queryExtensionsString(dpy, screen);
|
||||
|
@ -773,6 +819,8 @@ PUBLIC const char *glXQueryExtensionsString(Display *dpy, int screen)
|
|||
|
||||
PUBLIC Display *glXGetCurrentDisplay(void)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
__GLXAPIState *apiState = __glXGetCurrentAPIState();
|
||||
return apiState->currentDisplay;
|
||||
}
|
||||
|
@ -781,6 +829,8 @@ PUBLIC Display *glXGetCurrentDisplay(void)
|
|||
PUBLIC GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen,
|
||||
const int *attrib_list, int *nelements)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
GLXFBConfig *fbconfigs =
|
||||
pDispatch->glx14ep.chooseFBConfig(dpy, screen, attrib_list, nelements);
|
||||
|
@ -800,6 +850,8 @@ PUBLIC GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config,
|
|||
int render_type, GLXContext share_list,
|
||||
Bool direct)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromFBConfig(config);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -814,6 +866,8 @@ PUBLIC GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config,
|
|||
PUBLIC GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config,
|
||||
const int *attrib_list)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromFBConfig(config);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -828,6 +882,8 @@ PUBLIC GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config,
|
|||
PUBLIC GLXPixmap glXCreatePixmap(Display *dpy, GLXFBConfig config,
|
||||
Pixmap pixmap, const int *attrib_list)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromFBConfig(config);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -843,6 +899,8 @@ PUBLIC GLXPixmap glXCreatePixmap(Display *dpy, GLXFBConfig config,
|
|||
PUBLIC GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config,
|
||||
Window win, const int *attrib_list)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromFBConfig(config);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -857,6 +915,8 @@ PUBLIC GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config,
|
|||
|
||||
PUBLIC void glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, pbuf);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -868,6 +928,8 @@ PUBLIC void glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
|
|||
|
||||
PUBLIC void glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, pixmap);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -879,6 +941,8 @@ PUBLIC void glXDestroyPixmap(Display *dpy, GLXPixmap pixmap)
|
|||
|
||||
PUBLIC void glXDestroyWindow(Display *dpy, GLXWindow win)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, win);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -890,6 +954,8 @@ PUBLIC void glXDestroyWindow(Display *dpy, GLXWindow win)
|
|||
|
||||
PUBLIC GLXDrawable glXGetCurrentReadDrawable(void)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
__GLXAPIState *apiState = __glXGetCurrentAPIState();
|
||||
return apiState->currentRead;
|
||||
}
|
||||
|
@ -898,6 +964,8 @@ PUBLIC GLXDrawable glXGetCurrentReadDrawable(void)
|
|||
PUBLIC int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config,
|
||||
int attribute, int *value)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromFBConfig(config);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -907,6 +975,8 @@ PUBLIC int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig config,
|
|||
|
||||
PUBLIC GLXFBConfig *glXGetFBConfigs(Display *dpy, int screen, int *nelements)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
GLXFBConfig *fbconfigs = pDispatch->glx14ep.getFBConfigs(dpy, screen, nelements);
|
||||
int i;
|
||||
|
@ -924,6 +994,8 @@ PUBLIC GLXFBConfig *glXGetFBConfigs(Display *dpy, int screen, int *nelements)
|
|||
PUBLIC void glXGetSelectedEvent(Display *dpy, GLXDrawable draw,
|
||||
unsigned long *event_mask)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, draw);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -933,6 +1005,8 @@ PUBLIC void glXGetSelectedEvent(Display *dpy, GLXDrawable draw,
|
|||
|
||||
PUBLIC XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromFBConfig(config);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -942,6 +1016,8 @@ PUBLIC XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config)
|
|||
PUBLIC Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw,
|
||||
GLXDrawable read, GLXContext context)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const __GLXdispatchTableStatic *pDispatch;
|
||||
Bool ret;
|
||||
GLXDrawable oldDraw, oldRead;
|
||||
|
@ -1018,6 +1094,8 @@ PUBLIC Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw,
|
|||
|
||||
PUBLIC int glXQueryContext(Display *dpy, GLXContext context, int attribute, int *value)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromContext(context);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -1028,6 +1106,8 @@ PUBLIC int glXQueryContext(Display *dpy, GLXContext context, int attribute, int
|
|||
PUBLIC void glXQueryDrawable(Display *dpy, GLXDrawable draw,
|
||||
int attribute, unsigned int *value)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, draw);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -1037,6 +1117,8 @@ PUBLIC void glXQueryDrawable(Display *dpy, GLXDrawable draw,
|
|||
|
||||
PUBLIC void glXSelectEvent(Display *dpy, GLXDrawable draw, unsigned long event_mask)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
const int screen = __glXScreenFromDrawable(dpy, draw);
|
||||
const __GLXdispatchTableStatic *pDispatch = __glXGetStaticDispatch(dpy, screen);
|
||||
|
||||
|
@ -1128,6 +1210,11 @@ void cacheInitializeOnce(void)
|
|||
|
||||
}
|
||||
|
||||
static void CleanupProcAddressEntry(void *unused, __GLXprocAddressHash *pEntry)
|
||||
{
|
||||
free(pEntry->procName);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called externally by the libGL wrapper library to
|
||||
* retrieve libGLX entrypoints.
|
||||
|
@ -1183,11 +1270,15 @@ static void cacheProcAddress(const GLubyte *procName, __GLXextFuncPtr addr)
|
|||
|
||||
PUBLIC __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *procName)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
return glXGetProcAddress(procName);
|
||||
}
|
||||
|
||||
PUBLIC __GLXextFuncPtr glXGetProcAddress(const GLubyte *procName)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
__GLXextFuncPtr addr = NULL;
|
||||
|
||||
/*
|
||||
|
@ -1225,6 +1316,124 @@ done:
|
|||
return addr;
|
||||
}
|
||||
|
||||
int AtomicIncrement(int volatile *val)
|
||||
{
|
||||
return __sync_add_and_fetch(val, 1);
|
||||
}
|
||||
|
||||
int AtomicSwap(int volatile *val, int newVal)
|
||||
{
|
||||
return __sync_lock_test_and_set(val, newVal);
|
||||
}
|
||||
|
||||
int AtomicCompareAndSwap(int volatile *val, int oldVal, int newVal)
|
||||
{
|
||||
return __sync_val_compare_and_swap(val, oldVal, newVal);
|
||||
}
|
||||
|
||||
int AtomicDecrementClampAtZero(int volatile *val)
|
||||
{
|
||||
int oldVal, newVal;
|
||||
|
||||
oldVal = *val;
|
||||
newVal = oldVal;
|
||||
|
||||
do {
|
||||
if (oldVal <= 0) {
|
||||
assert(oldVal == 0);
|
||||
} else {
|
||||
newVal = oldVal - 1;
|
||||
if (newVal < 0) {
|
||||
newVal = 0;
|
||||
}
|
||||
oldVal = AtomicCompareAndSwap(val, oldVal, newVal);
|
||||
}
|
||||
} while ((oldVal > 0) && (newVal != oldVal - 1));
|
||||
|
||||
return newVal;
|
||||
}
|
||||
|
||||
static void __glXResetOnFork(void);
|
||||
|
||||
/*
|
||||
* Perform checks that need to occur when entering any GLX entrypoint.
|
||||
* Currently, this only detects whether a fork occurred since the last
|
||||
* entrypoint was called, and performs recovery as needed.
|
||||
*/
|
||||
void __glXThreadInitialize(void)
|
||||
{
|
||||
volatile static int g_threadsInCheck = 0;
|
||||
volatile static int g_lastPid = -1;
|
||||
|
||||
int lastPid;
|
||||
int pid = getpid();
|
||||
|
||||
AtomicIncrement(&g_threadsInCheck);
|
||||
|
||||
lastPid = AtomicSwap(&g_lastPid, pid);
|
||||
|
||||
if ((lastPid != -1) &&
|
||||
(lastPid != pid)) {
|
||||
|
||||
DBG_PRINTF(0, "Fork detected\n");
|
||||
|
||||
__glXResetOnFork();
|
||||
|
||||
// Force g_threadsInCheck to 0 to unblock other threads waiting here.
|
||||
g_threadsInCheck = 0;
|
||||
} else {
|
||||
AtomicDecrementClampAtZero(&g_threadsInCheck);
|
||||
while (g_threadsInCheck > 0) {
|
||||
// Wait for other threads to finish checking for a fork.
|
||||
//
|
||||
// If a fork happens while g_threadsInCheck > 0 the _first_ thread
|
||||
// to enter __glXThreadInitialize() will see the fork, handle it, and force
|
||||
// g_threadsInCheck to 0, unblocking any other threads stuck here.
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __glXAPITeardown(Bool doReset)
|
||||
{
|
||||
/* Clear the current TSD context */
|
||||
__glXPthreadFuncs.setspecific(tsdContextKey, NULL);
|
||||
|
||||
/*
|
||||
* XXX: This will leave dangling screen-context mappings, but they will be
|
||||
* cleared separately in __glXMappingTeardown().
|
||||
*/
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXcurrentContextHash,
|
||||
__glXCurrentContextHash, NULL, NULL, doReset);
|
||||
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXAPIState,
|
||||
__glXAPIStateHash, CleanupAPIStateEntry,
|
||||
NULL, doReset);
|
||||
|
||||
if (doReset) {
|
||||
/*
|
||||
* XXX: We should be able to get away with just resetting the proc address
|
||||
* hash lock, and not throwing away cached addresses.
|
||||
*/
|
||||
__glXPthreadFuncs.rwlock_init(&__glXProcAddressHash.lock, NULL);
|
||||
} else {
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXprocAddressHash,
|
||||
__glXProcAddressHash, CleanupProcAddressEntry,
|
||||
NULL, False);
|
||||
}
|
||||
}
|
||||
|
||||
static void __glXResetOnFork(void)
|
||||
{
|
||||
/* Reset all GLX API state */
|
||||
__glXAPITeardown(True);
|
||||
|
||||
/* Reset all mapping state */
|
||||
__glXMappingTeardown(True);
|
||||
|
||||
/* Reset GLdispatch */
|
||||
__glDispatchReset();
|
||||
}
|
||||
|
||||
void __attribute__ ((constructor)) __glXInit(void)
|
||||
{
|
||||
|
@ -1244,6 +1453,8 @@ void __attribute__ ((constructor)) __glXInit(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO install fork handlers using __register_atfork */
|
||||
|
||||
/* Register our XCloseDisplay() callback */
|
||||
XGLVRegisterCloseDisplayCallback(DisplayClosed);
|
||||
|
||||
|
@ -1253,7 +1464,32 @@ void __attribute__ ((constructor)) __glXInit(void)
|
|||
|
||||
void __attribute__ ((destructor)) __glXFini(void)
|
||||
{
|
||||
// TODO teardown code here
|
||||
/* Check for a fork before going further. */
|
||||
__glXThreadInitialize();
|
||||
|
||||
/*
|
||||
* If libGLX owns the current API state, lose current
|
||||
* in GLdispatch before going further.
|
||||
*/
|
||||
__GLdispatchAPIState *glas =
|
||||
__glDispatchGetCurrentAPIState();
|
||||
|
||||
if (glas && glas->tag == GLDISPATCH_API_GLX) {
|
||||
__glDispatchLoseCurrent();
|
||||
}
|
||||
|
||||
|
||||
/* Unregister all XCloseDisplay() callbacks */
|
||||
XGLVUnregisterCloseDisplayCallbacks();
|
||||
|
||||
/* Tear down all GLX API state */
|
||||
__glXAPITeardown(False);
|
||||
|
||||
/* Tear down all mapping state */
|
||||
__glXMappingTeardown(False);
|
||||
|
||||
/* Tear down GLdispatch if necessary */
|
||||
__glDispatchFini();
|
||||
}
|
||||
|
||||
__GLXdispatchTableDynamic *__glXGetCurrentDynDispatch(void)
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "libglxmapping.h"
|
||||
#include "libglxnoop.h"
|
||||
#include "GLdispatch.h"
|
||||
#include "uthash.h"
|
||||
#include "lkdhash.h"
|
||||
|
||||
/*
|
||||
* Define current API library state here. An API state is per-thread, per-winsys
|
||||
|
|
|
@ -149,7 +149,16 @@ static GLboolean AllocDispatchIndex(__GLXvendorInfo *vendor,
|
|||
return GL_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
/*!
|
||||
* Callback function used when freeing the dispatch index hash table.
|
||||
*/
|
||||
static void CleanupDispatchIndexEntry(void *unused, __GLXdispatchIndexHash *pEntry)
|
||||
{
|
||||
assert(pEntry);
|
||||
free(pEntry->procName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* This function queries each loaded vendor to determine if there is
|
||||
* a vendor-implemented dispatch function. The dispatch function
|
||||
* uses the vendor <-> API library ABI to determine the screen given
|
||||
|
@ -292,6 +301,26 @@ static char *ConstructVendorLibraryFilename(const char *vendorName)
|
|||
return filename;
|
||||
}
|
||||
|
||||
void TeardownVendor(__GLXvendorInfo *vendor, Bool doLibraryUnload)
|
||||
{
|
||||
free(vendor->name);
|
||||
if (vendor->glDispatch) {
|
||||
__glDispatchDestroyTable(vendor->glDispatch);
|
||||
}
|
||||
|
||||
/* Clean up the dynamic dispatch table */
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXdispatchFuncHash,
|
||||
vendor->dynDispatch->hash, NULL, NULL, True);
|
||||
|
||||
free(vendor->dynDispatch);
|
||||
|
||||
if (doLibraryUnload) {
|
||||
dlclose(vendor->dlhandle);
|
||||
}
|
||||
|
||||
free(vendor);
|
||||
}
|
||||
|
||||
__GLXvendorInfo *__glXLookupVendorByName(const char *vendorName)
|
||||
{
|
||||
__GLXvendorNameHash *pEntry = NULL;
|
||||
|
@ -407,19 +436,18 @@ fail:
|
|||
dlclose(dlhandle);
|
||||
}
|
||||
if (vendor) {
|
||||
free(vendor->name);
|
||||
if (vendor->glDispatch) {
|
||||
__glDispatchDestroyTable(vendor->glDispatch);
|
||||
}
|
||||
free(vendor->dynDispatch);
|
||||
}
|
||||
if (pEntry) {
|
||||
free(pEntry->vendor);
|
||||
TeardownVendor(vendor, False/* doLibraryUnload */);
|
||||
}
|
||||
free(pEntry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void CleanupVendorNameEntry(void *unused,
|
||||
__GLXvendorNameHash *pEntry)
|
||||
{
|
||||
TeardownVendor(pEntry->vendor, True/* doLibraryUnload */);
|
||||
}
|
||||
|
||||
__GLXvendorInfo *__glXLookupVendorByScreen(Display *dpy, const int screen)
|
||||
{
|
||||
__GLXvendorInfo *vendor = NULL;
|
||||
|
@ -525,6 +553,8 @@ __GLdispatchTable *__glXGetGLDispatch(Display *dpy, const int screen)
|
|||
|
||||
__GLXdispatchTableDynamic *__glXGetDynDispatch(Display *dpy, const int screen)
|
||||
{
|
||||
__glXThreadInitialize();
|
||||
|
||||
__GLXvendorInfo *vendor = __glXLookupVendorByScreen(dpy, screen);
|
||||
|
||||
if (vendor) {
|
||||
|
@ -761,3 +791,45 @@ int __glXScreenFromDrawable(Display *dpy, GLXDrawable drawable)
|
|||
{
|
||||
return ScreenFromXID(dpy, drawable);
|
||||
}
|
||||
|
||||
/*!
|
||||
* This handles freeing all mapping state during library teardown
|
||||
* and fork recovery.
|
||||
*/
|
||||
void __glXMappingTeardown(Bool doReset)
|
||||
{
|
||||
/* Tear down all hashtables used in this file */
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXdispatchIndexHash,
|
||||
__glXDispatchIndexHash, CleanupDispatchIndexEntry,
|
||||
NULL, doReset);
|
||||
|
||||
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
||||
__glXNextUnusedHashIndex = 0;
|
||||
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
||||
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXvendorScreenHash,
|
||||
__glXVendorScreenHash, NULL, NULL, doReset);
|
||||
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXscreenPointerMappingHash,
|
||||
__glXScreenPointerMappingHash, NULL, NULL, doReset);
|
||||
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXscreenXIDMappingHash,
|
||||
__glXScreenXIDMappingHash, NULL, NULL, doReset);
|
||||
|
||||
if (doReset) {
|
||||
/*
|
||||
* If we're just doing fork recovery, we don't actually want to unload
|
||||
* any currently loaded vendors. Just reset the corresponding lock.
|
||||
*/
|
||||
__glXPthreadFuncs.rwlock_init(&__glXVendorNameHash.lock, NULL);
|
||||
} else {
|
||||
/*
|
||||
* This implicitly unloads vendor libraries that were loaded when
|
||||
* they were added to this hashtable.
|
||||
*/
|
||||
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXvendorNameHash,
|
||||
__glXVendorNameHash, CleanupVendorNameEntry,
|
||||
NULL, False);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -88,9 +88,8 @@ void __glXNotifyContextDestroyed(GLXContext ctx);
|
|||
|
||||
/*
|
||||
* Close the vendor library and perform any relevant teardown. This should
|
||||
* be called on each vendor when the API library is unloaded.
|
||||
* TODO implement me
|
||||
* be called when the API library is unloaded.
|
||||
*/
|
||||
void __glXUnloadVendor(__GLXvendorInfo *vendor);
|
||||
void __glXMappingTeardown(Bool doReset);
|
||||
|
||||
#endif /* __LIB_GLX_MAPPING_H */
|
||||
|
|
|
@ -34,4 +34,6 @@
|
|||
|
||||
extern GLVNDPthreadFuncs __glXPthreadFuncs;
|
||||
|
||||
void __glXThreadInitialize();
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue