diff options
-rw-r--r-- | src/egl/main/eglcurrent.c | 89 |
1 files changed, 73 insertions, 16 deletions
diff --git a/src/egl/main/eglcurrent.c b/src/egl/main/eglcurrent.c index 96152db19fb..e1b35485176 100644 --- a/src/egl/main/eglcurrent.c +++ b/src/egl/main/eglcurrent.c @@ -3,6 +3,7 @@ #include "eglcurrent.h" #include "eglcontext.h" #include "egllog.h" +#include "eglmutex.h" /* a fallback thread info to guarantee that every thread always has one */ @@ -13,51 +14,108 @@ static _EGLThreadInfo dummy_thread; static __thread const _EGLThreadInfo *_egl_TSD; __attribute__ ((tls_model("initial-exec"))); -static INLINE EGLBoolean _eglInitTSD(void) { return EGL_TRUE; } -static INLINE void _eglFiniTSD(void) { } -static INLINE void _eglSetTSD(const _EGLThreadInfo *t) { _egl_TSD = t; } +static INLINE void _eglSetTSD(const _EGLThreadInfo *t) +{ + _egl_TSD = t; +} static INLINE _EGLThreadInfo *_eglGetTSD(void) { return (_EGLThreadInfo *) _egl_TSD; } +static INLINE void _eglFiniTSD(void) +{ +} + +static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *)) +{ + /* TODO destroy TSD */ + (void) dtor; + return EGL_TRUE; +} + #elif PTHREADS #include <pthread.h> +static _EGL_DECLARE_MUTEX(_egl_TSDMutex); +static EGLBoolean _egl_TSDInitialized; static pthread_key_t _egl_TSD; +static void (*_egl_FreeTSD)(_EGLThreadInfo *); -static INLINE EGLBoolean _eglInitTSD(void) +static INLINE void _eglSetTSD(const _EGLThreadInfo *t) { - return (pthread_key_create(&_egl_TSD, NULL) == 0); + pthread_setspecific(_egl_TSD, (const void *) t); } -static INLINE void _eglFiniTSD(void) +static INLINE _EGLThreadInfo *_eglGetTSD(void) { - pthread_key_delete(_egl_TSD); + return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD); } -static INLINE void _eglSetTSD(const _EGLThreadInfo *t) +static INLINE void _eglFiniTSD(void) { - pthread_setspecific(_egl_TSD, (const void *) t); + _eglLockMutex(&_egl_TSDMutex); + if (_egl_TSDInitialized) { + _EGLThreadInfo *t = _eglGetTSD(); + + _egl_TSDInitialized = EGL_FALSE; + if (t && _egl_FreeTSD) + _egl_FreeTSD((void *) t); + pthread_key_delete(_egl_TSD); + } + _eglUnlockMutex(&_egl_TSDMutex); } -static INLINE _EGLThreadInfo *_eglGetTSD(void) +static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *)) { - return (_EGLThreadInfo *) pthread_getspecific(_egl_TSD); + if (!_egl_TSDInitialized) { + _eglLockMutex(&_egl_TSDMutex); + + /* check again after acquiring lock */ + if (!_egl_TSDInitialized) { + if (pthread_key_create(&_egl_TSD, (void (*)(void *)) dtor) != 0) { + _eglUnlockMutex(&_egl_TSDMutex); + return EGL_FALSE; + } + _egl_FreeTSD = dtor; + _egl_TSDInitialized = EGL_TRUE; + } + + _eglUnlockMutex(&_egl_TSDMutex); + } + + return EGL_TRUE; } #else /* PTHREADS */ static const _EGLThreadInfo *_egl_TSD; +static void (*_egl_FreeTSD)(_EGLThreadInfo *); -static INLINE EGLBoolean _eglInitTSD(void) { return EGL_TRUE; } -static INLINE void _eglFiniTSD(void) { } -static INLINE void _eglSetTSD(const _EGLThreadInfo *t) { _egl_TSD = t; } +static INLINE void _eglSetTSD(const _EGLThreadInfo *t) +{ + _egl_TSD = t; +} static INLINE _EGLThreadInfo *_eglGetTSD(void) { return (_EGLThreadInfo *) _egl_TSD; } + +static INLINE void _eglFiniTSD(void) +{ + if (_egl_FreeTSD && _egl_TSD) + _egl_FreeTSD((_EGLThreadInfo *) _egl_TSD); +} + +static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *)) +{ + if (!_egl_FreeTSD && dtor) { + _egl_FreeTSD = dtor; + } + return EGL_TRUE; +} + #endif /* !PTHREADS */ @@ -104,7 +162,7 @@ EGLBoolean _eglInitCurrent(void) { _eglInitThreadInfo(&dummy_thread); - return _eglInitTSD(); + return _eglInitTSD((void (*)(void *)) _eglDestroyThreadInfo); } @@ -114,7 +172,6 @@ _eglInitCurrent(void) void _eglFiniCurrent(void) { - /* TODO trace and release all threads... */ _eglFiniTSD(); } |