Mesa (master): egl: Destroy eglThreadInfo on thread exit.

Brian Paul brianp at kemper.freedesktop.org
Wed Aug 12 04:15:22 UTC 2009


Module: Mesa
Branch: master
Commit: f6c2f5e37925abe3ea7036b7a3bd6ca1721e4f73
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=f6c2f5e37925abe3ea7036b7a3bd6ca1721e4f73

Author: Chia-I Wu <olvaffe at gmail.com>
Date:   Mon Aug 10 12:20:31 2009 +0800

egl: Destroy eglThreadInfo on thread exit.

This is done through pthread TSD destructor.  It destroys all thread
infos except for main thread's.  The thread info of the main thread is
destroyed by _eglFiniCurrent.

TLS case is not supported yet.

Signed-off-by: Chia-I Wu <olvaffe at gmail.com>

---

 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 96152db..e1b3548 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();
 }
 




More information about the mesa-commit mailing list