This patch series aims to improve resource management of EGL.  There are
two things it wants to improve

* Do not assume that eglGetDisplay is the first function called and
  various management code is initialized
* Free per-thread info and display when thread or process exits

For the former, it initializes resource management code (eglcurrent.c
and egldisplay.c) on demand, or uses static initialization
(eglglobals.c).  For the latter, cleanup functions are registered so
that they are called when thread exits or process exits.  It is through
the destructor function of pthread_key_create, or atexit.

The first patch adds eglmutex.h.  It uses pthread mutex when available,
otherwise it's no-op.

The second patch makes TSD key be created with a destructor.  The
destructor is called to free _EGLThreadInfo when a thread exits.

The third patch makes TSD be initialized on demand.

The fourth patch moves display and surface hash tables from _eglGlobal
to egldisplay.c.  They are not, and should not, be used outside of
egldisplay.c.  The hash tables are also made to initialize on demand.

The last 3 patches make _eglGlobal be initialized statically, and
register atexit calls to free the hash tables or main thread's
per-thread data.

 b/src/egl/main/Makefile     |    1 
 b/src/egl/main/eglapi.c     |    1 
 b/src/egl/main/eglcurrent.c |   89 ++++++++++++++++++++++++++++++++++++--------
 b/src/egl/main/eglcurrent.h |    8 ---
 b/src/egl/main/egldisplay.c |   85 +++++++++++++++++++++++++++++++++++-------
 b/src/egl/main/egldisplay.h |    5 ++
 b/src/egl/main/eglglobals.c |    4 -
 b/src/egl/main/eglglobals.h |    4 -
 b/src/egl/main/eglmutex.h   |   52 +++++++++++++++++++++++++
 src/egl/main/eglcurrent.c   |   42 ++++++++++----------
 src/egl/main/egldisplay.c   |   20 ++++++++-
 src/egl/main/eglglobals.c   |   78 +++++++++++++++++++++++---------------
 src/egl/main/eglglobals.h   |   19 ++++-----
 13 files changed, 299 insertions(+), 109 deletions(-)

-- 
Regards,
olv
>From 3492312f60ff38f3123b5e16c0b3c88732c67a35 Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 11:35:06 +0800
Subject: [PATCH 1/8] egl: Add eglmutex.h.

The implementation uses pthread mutex when available.  Otherwise, it is
no-op.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/Makefile   |    1 +
 src/egl/main/eglmutex.h |   52 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 0 deletions(-)
 create mode 100644 src/egl/main/eglmutex.h

diff --git a/src/egl/main/Makefile b/src/egl/main/Makefile
index 7cab005..e897b4b 100644
--- a/src/egl/main/Makefile
+++ b/src/egl/main/Makefile
@@ -20,6 +20,7 @@ HEADERS = \
 	eglhash.h \
 	eglmisc.h \
 	eglmode.h \
+	eglmutex.h \
 	eglscreen.h \
 	eglstring.h \
 	eglsurface.h \
diff --git a/src/egl/main/eglmutex.h b/src/egl/main/eglmutex.h
new file mode 100644
index 0000000..29faba0
--- /dev/null
+++ b/src/egl/main/eglmutex.h
@@ -0,0 +1,52 @@
+#ifndef EGLMUTEX_INCLUDED
+#define EGLMUTEX_INCLUDED
+
+#include "eglcompiler.h"
+
+#ifdef PTHREADS
+#include <pthread.h>
+
+typedef pthread_mutex_t _EGLMutex;
+
+static INLINE void _eglInitMutex(_EGLMutex *m)
+{
+   pthread_mutex_init(m, NULL);
+}
+
+static INLINE void
+_eglDestroyMutex(_EGLMutex *m)
+{
+   pthread_mutex_destroy(m);
+}
+
+static INLINE void
+_eglLockMutex(_EGLMutex *m)
+{
+   pthread_mutex_lock(m);
+}
+
+static INLINE void
+_eglUnlockMutex(_EGLMutex *m)
+{
+   pthread_mutex_unlock(m);
+}
+
+#define _EGL_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define _EGL_DECLARE_MUTEX(m) \
+   _EGLMutex m = _EGL_MUTEX_INITIALIZER
+
+#else
+
+typedef int _EGLMutex;
+static INLINE void _eglInitMutex(_EGLMutex *m) { (void) m; }
+static INLINE void _eglDestroyMutex(_EGLMutex *m) { (void) m; }
+static INLINE void _eglLockMutex(_EGLMutex *m) { (void) m; }
+static INLINE void _eglUnlockMutex(_EGLMutex *m) { (void) m; }
+
+#define _EGL_MUTEX_INITIALIZER 0
+#define _EGL_DECLARE_MUTEX(m) \
+   _EGLMutex m = _EGL_MUTEX_INITIALIZER
+
+#endif
+
+#endif /* EGLMUTEX_INCLUDED */
-- 
1.6.2.4

>From 3de03bb7f4de26ca74fdb1838d9a1fb58b1ca53f Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 12:20:31 +0800
Subject: [PATCH 2/8] 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 <[email protected]>
---
 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();
 }
 
-- 
1.6.2.4

>From bb5d1c3c4cbe8f4a933ff08bf506199c16800fc7 Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 12:46:08 +0800
Subject: [PATCH 3/8] egl: Initialize current thread management on demand.

Current thread management was initialized in _eglInitGlobals, which is
called only in eglGetDisplay.  Since EGL does not require eglGetDisplay
to be called first, the initialization is better to be done on demand.

_eglFiniCurrent is removed, as it is not called at all.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglcurrent.c |   37 +++++++++++++++++++------------------
 src/egl/main/eglcurrent.h |    8 --------
 src/egl/main/eglglobals.c |    4 ----
 3 files changed, 19 insertions(+), 30 deletions(-)

diff --git a/src/egl/main/eglcurrent.c b/src/egl/main/eglcurrent.c
index e1b3548..f92719c 100644
--- a/src/egl/main/eglcurrent.c
+++ b/src/egl/main/eglcurrent.c
@@ -6,8 +6,12 @@
 #include "eglmutex.h"
 
 
+/* This should be kept in sync with _eglInitThreadInfo() */
+#define _EGL_THREAD_INFO_INITIALIZER \
+   { EGL_SUCCESS, { NULL }, 1 }
+
 /* a fallback thread info to guarantee that every thread always has one */
-static _EGLThreadInfo dummy_thread;
+static _EGLThreadInfo dummy_thread = _EGL_THREAD_INFO_INITIALIZER;
 
 
 #ifdef GLX_USE_TLS
@@ -32,6 +36,7 @@ static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
 {
    /* TODO destroy TSD */
    (void) dtor;
+   (void) _eglFiniTSD;
    return EGL_TRUE;
 }
 
@@ -79,6 +84,7 @@ static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
             return EGL_FALSE;
          }
          _egl_FreeTSD = dtor;
+         (void) _eglFiniTSD;
          _egl_TSDInitialized = EGL_TRUE;
       }
 
@@ -112,6 +118,7 @@ static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
 {
    if (!_egl_FreeTSD && dtor) {
       _egl_FreeTSD = dtor;
+      (void) _eglFiniTSD;
    }
    return EGL_TRUE;
 }
@@ -156,23 +163,17 @@ _eglDestroyThreadInfo(_EGLThreadInfo *t)
 
 
 /**
- * Initialize "current thread" management.
+ * Make sure TSD is initialized and return current value.
  */
-EGLBoolean
-_eglInitCurrent(void)
+static INLINE _EGLThreadInfo *
+_eglCheckedGetTSD(void)
 {
-   _eglInitThreadInfo(&dummy_thread);
-   return _eglInitTSD((void (*)(void *)) _eglDestroyThreadInfo);
-}
-
+   if (_eglInitTSD(&_eglDestroyThreadInfo) != EGL_TRUE) {
+      _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
+      return NULL;
+   }
 
-/**
- * Finish "current thread" management.
- */
-void
-_eglFiniCurrent(void)
-{
-   _eglFiniTSD();
+   return _eglGetTSD();
 }
 
 
@@ -186,7 +187,7 @@ _eglFiniCurrent(void)
 _EGLThreadInfo *
 _eglGetCurrentThread(void)
 {
-   _EGLThreadInfo *t = _eglGetTSD();
+   _EGLThreadInfo *t = _eglCheckedGetTSD();
    if (!t) {
       t = _eglCreateThreadInfo();
       _eglSetTSD(t);
@@ -202,7 +203,7 @@ _eglGetCurrentThread(void)
 void
 _eglDestroyCurrentThread(void)
 {
-   _EGLThreadInfo *t = _eglGetTSD();
+   _EGLThreadInfo *t = _eglCheckedGetTSD();
    if (t) {
       _eglDestroyThreadInfo(t);
       _eglSetTSD(NULL);
@@ -219,7 +220,7 @@ _eglDestroyCurrentThread(void)
 EGLBoolean
 _eglIsCurrentThreadDummy(void)
 {
-   _EGLThreadInfo *t = _eglGetTSD();
+   _EGLThreadInfo *t = _eglCheckedGetTSD();
    return (!t || t == &dummy_thread);
 }
 
diff --git a/src/egl/main/eglcurrent.h b/src/egl/main/eglcurrent.h
index f9fdf7b..8eb2410 100644
--- a/src/egl/main/eglcurrent.h
+++ b/src/egl/main/eglcurrent.h
@@ -20,14 +20,6 @@ struct _egl_thread_info
 };
 
 
-extern EGLBoolean
-_eglInitCurrent(void);
-
-
-extern void
-_eglFiniCurrent(void);
-
-
 /**
  * Return true if a client API enum can be converted to an index.
  */
diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c
index 55de394..23a3ef5 100644
--- a/src/egl/main/eglglobals.c
+++ b/src/egl/main/eglglobals.c
@@ -21,9 +21,6 @@ _eglInitGlobals(void)
       _eglGlobal.Initialized = EGL_TRUE;
 
       _eglGlobal.ClientAPIsMask = 0x0;
-
-      if (!_eglInitCurrent())
-         _eglLog(_EGL_FATAL, "failed to initialize \"current\" system");
    }
 }
 
@@ -34,7 +31,6 @@ _eglInitGlobals(void)
 void
 _eglDestroyGlobals(void)
 {
-   _eglFiniCurrent();
    /* XXX TODO walk over table entries, deleting each */
    _eglDeleteHashTable(_eglGlobal.Displays);
    _eglDeleteHashTable(_eglGlobal.Surfaces);
-- 
1.6.2.4

>From fdbf5cedc3c9aeb25ef38cc243d397de583fc4bc Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 14:16:32 +0800
Subject: [PATCH 4/8] egl: Make display and surface hash tables local.

Move display and surface hash tables to egldisplay.c, and have them
initialized on demand.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/egldisplay.c |   85 ++++++++++++++++++++++++++++++++++++++-------
 src/egl/main/egldisplay.h |    5 +++
 src/egl/main/eglglobals.c |    6 +---
 src/egl/main/eglglobals.h |    4 --
 4 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c
index 5304b84..58d9352 100644
--- a/src/egl/main/egldisplay.c
+++ b/src/egl/main/egldisplay.c
@@ -1,4 +1,3 @@
-
 /**
  * Functions related to EGLDisplay.
  */
@@ -13,6 +12,51 @@
 #include "eglglobals.h"
 #include "eglhash.h"
 #include "eglstring.h"
+#include "eglmutex.h"
+
+
+static _EGL_DECLARE_MUTEX(_eglDisplayInitMutex);
+static _EGLHashtable *_eglDisplayHash;
+/* TODO surface hash table should be per-display */
+static _EGLHashtable *_eglSurfaceHash;
+
+
+/**
+ * Finish display management.
+ */
+static void
+_eglFiniDisplay(void)
+{
+   _eglLockMutex(&_eglDisplayInitMutex);
+   if (_eglDisplayHash) {
+      /* XXX TODO walk over table entries, deleting each */
+      _eglDeleteHashTable(_eglDisplayHash);
+      _eglDisplayHash = NULL;
+      _eglDeleteHashTable(_eglSurfaceHash);
+      _eglSurfaceHash = NULL;
+   }
+   _eglUnlockMutex(&_eglDisplayInitMutex);
+}
+
+
+/* This can be avoided if hash table can be statically initialized */
+static INLINE void
+_eglInitDisplay(void)
+{
+   if (!_eglDisplayHash) {
+      _eglLockMutex(&_eglDisplayInitMutex);
+
+      /* check again after acquiring lock */
+      if (!_eglDisplayHash) {
+         _eglDisplayHash = _eglNewHashTable();
+         _eglSurfaceHash = _eglNewHashTable();
+
+         (void) _eglFiniDisplay;
+      }
+
+      _eglUnlockMutex(&_eglDisplayInitMutex);
+   }
+}
 
 
 /**
@@ -31,6 +75,9 @@ _eglNewDisplay(NativeDisplayType nativeDisplay)
       dpy->Xdpy = (Display *) nativeDisplay;
 #endif
 
+      _eglInitDisplay();
+      dpy->SurfaceHash = _eglSurfaceHash;
+
       dpy->DriverName = _eglChooseDriver(dpy);
       if (!dpy->DriverName) {
          free(dpy);
@@ -49,10 +96,13 @@ EGLDisplay
 _eglLinkDisplay(_EGLDisplay *dpy)
 {
    EGLuint key;
-   key = _eglHashGenKey(_eglGlobal.Displays);
+
+   _eglInitDisplay();
+
+   key = _eglHashGenKey(_eglDisplayHash);
    assert(key);
    /* "link" the display to the hash table */
-   _eglHashInsert(_eglGlobal.Displays, key, dpy);
+   _eglHashInsert(_eglDisplayHash, key, dpy);
    dpy->Handle = (EGLDisplay) _eglUIntToPointer(key);
 
    return dpy->Handle;
@@ -67,7 +117,10 @@ void
 _eglUnlinkDisplay(_EGLDisplay *dpy)
 {
    EGLuint key = _eglPointerToUInt((void *) dpy->Handle);
-   _eglHashRemove(_eglGlobal.Displays, key);
+
+   _eglInitDisplay();
+
+   _eglHashRemove(_eglDisplayHash, key);
    dpy->Handle = EGL_NO_DISPLAY;
 }
 
@@ -84,7 +137,7 @@ _eglGetDisplayHandle(_EGLDisplay *display)
       return EGL_NO_DISPLAY;
 }
 
- 
+
 /**
  * Lookup a handle to find the linked display.
  * Return NULL if the handle has no corresponding linked display.
@@ -93,7 +146,10 @@ _EGLDisplay *
 _eglLookupDisplay(EGLDisplay dpy)
 {
    EGLuint key = _eglPointerToUInt((void *) dpy);
-   return (_EGLDisplay *) _eglHashLookup(_eglGlobal.Displays, key);
+
+   _eglInitDisplay();
+
+   return (_EGLDisplay *) _eglHashLookup(_eglDisplayHash, key);
 }
 
 
@@ -104,17 +160,20 @@ _eglLookupDisplay(EGLDisplay dpy)
 _EGLDisplay *
 _eglFindDisplay(NativeDisplayType nativeDisplay)
 {
-   EGLuint key = _eglHashFirstEntry(_eglGlobal.Displays);
+   EGLuint key;
+
+   _eglInitDisplay();
 
    /* Walk the hash table.  Should switch to list if it is a problem. */
+   key = _eglHashFirstEntry(_eglDisplayHash);
    while (key) {
       _EGLDisplay *dpy = (_EGLDisplay *)
-            _eglHashLookup(_eglGlobal.Displays, key);
+            _eglHashLookup(_eglDisplayHash, key);
       assert(dpy);
 
       if (dpy->NativeDisplay == nativeDisplay)
          return dpy;
-      key = _eglHashNextEntry(_eglGlobal.Displays, key);
+      key = _eglHashNextEntry(_eglDisplayHash, key);
    }
 
    return NULL;
@@ -254,9 +313,9 @@ _eglLinkSurface(_EGLSurface *surf, _EGLDisplay *dpy)
    surf->Next = dpy->SurfaceList;
    dpy->SurfaceList = surf;
 
-   key = _eglHashGenKey(_eglGlobal.Surfaces);
+   key = _eglHashGenKey(dpy->SurfaceHash);
    assert(key);
-   _eglHashInsert(_eglGlobal.Surfaces, key, surf);
+   _eglHashInsert(dpy->SurfaceHash, key, surf);
 
    surf->Handle = (EGLSurface) _eglUIntToPointer(key);
    return surf->Handle;
@@ -273,7 +332,7 @@ _eglUnlinkSurface(_EGLSurface *surf)
    _EGLSurface *prev;
    EGLuint key = _eglPointerToUInt((void *) surf->Handle);
 
-   _eglHashRemove(_eglGlobal.Surfaces, key);
+   _eglHashRemove(surf->Display->SurfaceHash, key);
    surf->Handle = EGL_NO_SURFACE;
 
    prev = surf->Display->SurfaceList;
@@ -317,5 +376,5 @@ _EGLSurface *
 _eglLookupSurface(EGLSurface surf)
 {
    EGLuint key = _eglPointerToUInt((void *) surf);
-   return (_EGLSurface *) _eglHashLookup(_eglGlobal.Surfaces, key);
+   return (_EGLSurface *) _eglHashLookup(_eglSurfaceHash, key);
 }
diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
index 2ef5db8..70c59ef 100644
--- a/src/egl/main/egldisplay.h
+++ b/src/egl/main/egldisplay.h
@@ -6,6 +6,7 @@
 #endif
 
 #include "egltypedefs.h"
+#include "eglhash.h"
 
 
 struct _egl_display 
@@ -26,6 +27,10 @@ struct _egl_display
    /* lists of linked contexts and surface */
    _EGLContext *ContextList;
    _EGLSurface *SurfaceList;
+
+   /* hash table to map surfaces to handles */
+   _EGLHashtable *SurfaceHash;
+
 #ifdef _EGL_PLATFORM_X
    Display *Xdpy;
 #endif
diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c
index 23a3ef5..f2c1c21 100644
--- a/src/egl/main/eglglobals.c
+++ b/src/egl/main/eglglobals.c
@@ -1,5 +1,6 @@
 #include <stdlib.h>
 #include "eglglobals.h"
+#include "egldisplay.h"
 #include "egllog.h"
 
 struct _egl_global _eglGlobal = 
@@ -15,8 +16,6 @@ void
 _eglInitGlobals(void)
 {
    if (!_eglGlobal.Initialized) {
-      _eglGlobal.Displays = _eglNewHashTable();
-      _eglGlobal.Surfaces = _eglNewHashTable();
       _eglGlobal.FreeScreenHandle = 1;
       _eglGlobal.Initialized = EGL_TRUE;
 
@@ -31,7 +30,4 @@ _eglInitGlobals(void)
 void
 _eglDestroyGlobals(void)
 {
-   /* XXX TODO walk over table entries, deleting each */
-   _eglDeleteHashTable(_eglGlobal.Displays);
-   _eglDeleteHashTable(_eglGlobal.Surfaces);
 }
diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h
index a9443cf..47fd943 100644
--- a/src/egl/main/eglglobals.h
+++ b/src/egl/main/eglglobals.h
@@ -13,10 +13,6 @@ struct _egl_global
 {
    EGLBoolean Initialized;
 
-   /* these are private to egldisplay.c */
-   _EGLHashtable *Displays;
-   _EGLHashtable *Surfaces;
-
    EGLScreenMESA FreeScreenHandle;
 
    /* bitmaks of supported APIs (supported by _some_ driver) */
-- 
1.6.2.4

>From dad6a3aaa6f9badda2c86df37d44cef5df6cd438 Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 15:13:42 +0800
Subject: [PATCH 5/8] egl: Implement _eglFiniDisplay.

_eglFiniDisplay is called at exit time to free allocated displays.  It
is, however, not used right now.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/egldisplay.c |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c
index 58d9352..6fdb3b7 100644
--- a/src/egl/main/egldisplay.c
+++ b/src/egl/main/egldisplay.c
@@ -13,6 +13,7 @@
 #include "eglhash.h"
 #include "eglstring.h"
 #include "eglmutex.h"
+#include "egllog.h"
 
 
 static _EGL_DECLARE_MUTEX(_eglDisplayInitMutex);
@@ -29,7 +30,22 @@ _eglFiniDisplay(void)
 {
    _eglLockMutex(&_eglDisplayInitMutex);
    if (_eglDisplayHash) {
-      /* XXX TODO walk over table entries, deleting each */
+      EGLuint key = _eglHashFirstEntry(_eglDisplayHash);
+
+      while (key) {
+         _EGLDisplay *dpy = (_EGLDisplay *)
+            _eglHashLookup(_eglDisplayHash, key);
+         assert(dpy);
+
+         if (dpy->ContextList || dpy->SurfaceList)
+            _eglLog(_EGL_DEBUG, "Display %u is destroyed with resources", key);
+
+         _eglCleanupDisplay(dpy);
+         free(dpy);
+
+         key = _eglHashNextEntry(_eglDisplayHash, key);
+      }
+
       _eglDeleteHashTable(_eglDisplayHash);
       _eglDisplayHash = NULL;
       _eglDeleteHashTable(_eglSurfaceHash);
-- 
1.6.2.4

>From 006b66973fa3e97245315d7734f2425fb152f0de Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 16:37:28 +0800
Subject: [PATCH 6/8] egl: Make _eglGlobal initialize statically.

Now that display and surface hash tables are moved out, _eglGlobal can
be initialized statically.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglapi.c     |    1 -
 src/egl/main/eglglobals.c |   32 ++++++--------------------------
 src/egl/main/eglglobals.h |   10 ----------
 3 files changed, 6 insertions(+), 37 deletions(-)

diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index f0a6f7f..fde6b73 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -50,7 +50,6 @@ EGLDisplay EGLAPIENTRY
 eglGetDisplay(NativeDisplayType nativeDisplay)
 {
    _EGLDisplay *dpy;
-   _eglInitGlobals();
    dpy = _eglFindDisplay(nativeDisplay);
    if (!dpy) {
       dpy = _eglNewDisplay(nativeDisplay);
diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c
index f2c1c21..8703168 100644
--- a/src/egl/main/eglglobals.c
+++ b/src/egl/main/eglglobals.c
@@ -3,31 +3,11 @@
 #include "egldisplay.h"
 #include "egllog.h"
 
-struct _egl_global _eglGlobal = 
+struct _egl_global _eglGlobal =
 {
-   EGL_FALSE
+   1,                      /* FreeScreenHandle */
+   0x0,                    /* ClientAPIsMask */
+   { 0x0 },                /* ClientAPIs */
+   0,                      /* NumDrivers */
+   { NULL },               /* Drivers */
 };
-
-/**
- * Init the fields in the _eglGlobal struct
- * May be safely called more than once.
- */
-void
-_eglInitGlobals(void)
-{
-   if (!_eglGlobal.Initialized) {
-      _eglGlobal.FreeScreenHandle = 1;
-      _eglGlobal.Initialized = EGL_TRUE;
-
-      _eglGlobal.ClientAPIsMask = 0x0;
-   }
-}
-
-
-/**
- * Should call this via an atexit handler.
- */
-void
-_eglDestroyGlobals(void)
-{
-}
diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h
index 47fd943..2f3c211 100644
--- a/src/egl/main/eglglobals.h
+++ b/src/egl/main/eglglobals.h
@@ -11,8 +11,6 @@
  */
 struct _egl_global
 {
-   EGLBoolean Initialized;
-
    EGLScreenMESA FreeScreenHandle;
 
    /* bitmaks of supported APIs (supported by _some_ driver) */
@@ -28,12 +26,4 @@ struct _egl_global
 extern struct _egl_global _eglGlobal;
 
 
-extern void
-_eglInitGlobals(void);
-
-
-extern void
-_eglDestroyGlobals(void);
-
-
 #endif /* EGLGLOBALS_INCLUDED */
-- 
1.6.2.4

>From 170bb717d3bb0b292cc801656137094c8f74d48d Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 17:35:20 +0800
Subject: [PATCH 7/8] egl: Add _eglAddAtExitCall.

Add a convenient wrapper to register atexit calls.  Add mutex to
_eglGlobal along the way.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglglobals.c |   40 ++++++++++++++++++++++++++++++++++++++++
 src/egl/main/eglglobals.h |    9 +++++++++
 2 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c
index 8703168..e93b48e 100644
--- a/src/egl/main/eglglobals.c
+++ b/src/egl/main/eglglobals.c
@@ -1,13 +1,53 @@
 #include <stdlib.h>
+#include <assert.h>
 #include "eglglobals.h"
 #include "egldisplay.h"
 #include "egllog.h"
+#include "eglmutex.h"
 
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+
+static _EGL_DECLARE_MUTEX(_eglGlobalMutex);
 struct _egl_global _eglGlobal =
 {
+   &_eglGlobalMutex,       /* Mutex */
    1,                      /* FreeScreenHandle */
    0x0,                    /* ClientAPIsMask */
    { 0x0 },                /* ClientAPIs */
    0,                      /* NumDrivers */
    { NULL },               /* Drivers */
+   0,                      /* NumAtExitCalls */
+   { NULL },               /* AtExitCalls */
 };
+
+
+static void
+_eglAtExit(void)
+{
+   EGLint i;
+   for (i = _eglGlobal.NumAtExitCalls - 1; i >= 0; i--)
+      _eglGlobal.AtExitCalls[i]();
+}
+
+
+void
+_eglAddAtExitCall(void (*func)(void))
+{
+   if (func) {
+      static EGLBoolean registered = EGL_FALSE;
+
+      _eglLockMutex(_eglGlobal.Mutex);
+
+      if (!registered) {
+         atexit(_eglAtExit);
+         registered = EGL_TRUE;
+      }
+
+      assert(_eglGlobal.NumAtExitCalls < ARRAY_SIZE(_eglGlobal.AtExitCalls));
+      _eglGlobal.AtExitCalls[_eglGlobal.NumAtExitCalls++] = func;
+
+      _eglUnlockMutex(_eglGlobal.Mutex);
+   }
+}
diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h
index 2f3c211..1e2c674 100644
--- a/src/egl/main/eglglobals.h
+++ b/src/egl/main/eglglobals.h
@@ -4,6 +4,7 @@
 #include "egltypedefs.h"
 #include "eglhash.h"
 #include "eglcurrent.h"
+#include "eglmutex.h"
 
 
 /**
@@ -11,6 +12,7 @@
  */
 struct _egl_global
 {
+   _EGLMutex *Mutex;
    EGLScreenMESA FreeScreenHandle;
 
    /* bitmaks of supported APIs (supported by _some_ driver) */
@@ -20,10 +22,17 @@ struct _egl_global
 
    EGLint NumDrivers;
    _EGLDriver *Drivers[10];
+
+   EGLint NumAtExitCalls;
+   void (*AtExitCalls[10])(void);
 };
 
 
 extern struct _egl_global _eglGlobal;
 
 
+extern void
+_eglAddAtExitCall(void (*func)(void));
+
+
 #endif /* EGLGLOBALS_INCLUDED */
-- 
1.6.2.4

>From 115a760cbce888089ef02a35c1b84ee84d39451f Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 10 Aug 2009 16:45:12 +0800
Subject: [PATCH 8/8] egl: Use _eglAddAtExitCall to free thread infos and displays.

Thread infos and displays are usually not freed by applications.  This
commit add atexit calls to free them.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/egl/main/eglcurrent.c |    5 +++--
 src/egl/main/egldisplay.c |    2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/egl/main/eglcurrent.c b/src/egl/main/eglcurrent.c
index f92719c..4431f96 100644
--- a/src/egl/main/eglcurrent.c
+++ b/src/egl/main/eglcurrent.c
@@ -4,6 +4,7 @@
 #include "eglcontext.h"
 #include "egllog.h"
 #include "eglmutex.h"
+#include "eglglobals.h"
 
 
 /* This should be kept in sync with _eglInitThreadInfo() */
@@ -84,7 +85,7 @@ static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
             return EGL_FALSE;
          }
          _egl_FreeTSD = dtor;
-         (void) _eglFiniTSD;
+         _eglAddAtExitCall(_eglFiniTSD);
          _egl_TSDInitialized = EGL_TRUE;
       }
 
@@ -118,7 +119,7 @@ static INLINE EGLBoolean _eglInitTSD(void (*dtor)(_EGLThreadInfo *))
 {
    if (!_egl_FreeTSD && dtor) {
       _egl_FreeTSD = dtor;
-      (void) _eglFiniTSD;
+      _eglAddAtExitCall(_eglFiniTSD);
    }
    return EGL_TRUE;
 }
diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c
index 6fdb3b7..feae1d6 100644
--- a/src/egl/main/egldisplay.c
+++ b/src/egl/main/egldisplay.c
@@ -67,7 +67,7 @@ _eglInitDisplay(void)
          _eglDisplayHash = _eglNewHashTable();
          _eglSurfaceHash = _eglNewHashTable();
 
-         (void) _eglFiniDisplay;
+         _eglAddAtExitCall(_eglFiniDisplay);
       }
 
       _eglUnlockMutex(&_eglDisplayInitMutex);
-- 
1.6.2.4

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Mesa3d-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to