diff options
author | Chad Versace <chad.versace@linux.intel.com> | 2013-07-10 22:58:03 -0700 |
---|---|---|
committer | Chad Versace <chad.versace@linux.intel.com> | 2013-07-19 19:15:20 -0700 |
commit | 6178e22d23dde1cd4f71bd081aa0ba97d0658cde (patch) | |
tree | 67c0afba0043d6fca2c2496d5e3885484596679f | |
parent | d56440ca5f26cabb4f05744650ef532faf060786 (diff) |
core: Prevent leak at thread exit
When the thread exits, teardown the thread-local data in wcore_tinfo.
Tested on Mac OS with XCode 3.1 gcc and XCode 4.6.2 clang by Nigel.
Tested-by: Nigel Stewart <nigelstewart@gmail.com>
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
-rw-r--r-- | src/waffle/core/wcore_tinfo.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/src/waffle/core/wcore_tinfo.c b/src/waffle/core/wcore_tinfo.c index 654802e..da57b82 100644 --- a/src/waffle/core/wcore_tinfo.c +++ b/src/waffle/core/wcore_tinfo.c @@ -38,6 +38,9 @@ #include "wcore_error.h" #include "wcore_tinfo.h" +static pthread_once_t wcore_tinfo_once = PTHREAD_ONCE_INIT; +static pthread_key_t wcore_tinfo_key; + /// @brief Thread-local storage for all of Waffle. /// /// For documentation on the tls_model, see the GCC manual [1] and @@ -63,18 +66,51 @@ wcore_tinfo_abort_init(void) } static void +wcore_tinfo_key_dtor(void *args) +{ + struct wcore_tinfo *tinfo = args; + if (!tinfo) + return; + + wcore_error_tinfo_destroy(tinfo->error); +} + +static void +wcore_tinfo_key_create(void) +{ + int err; + + err = pthread_key_create(&wcore_tinfo_key, wcore_tinfo_key_dtor); + if (err) + wcore_tinfo_abort_init(); +} + +static void wcore_tinfo_init(struct wcore_tinfo *tinfo) { + int err; + if (tinfo->is_init) return; - // FIXME: wcore_tinfo.error leaks at thread exit. To fix this, Waffle - // FIXME: needs a function like eglTerminate(). tinfo->error = wcore_error_tinfo_create(); if (!tinfo->error) wcore_tinfo_abort_init(); tinfo->is_init = true; + + // Register tinfo with the key's destructor to prevent memory leaks at + // thread exit. The destructor must be registered once per process, but + // each instance of tinfo must be registered individually. The key's data + // is never retrieved because use the key only to register tinfo for + // destruction. + err = pthread_once(&wcore_tinfo_once, wcore_tinfo_key_create); + if (err) + wcore_tinfo_abort_init(); + + err = pthread_setspecific(wcore_tinfo_key, tinfo); + if (err) + wcore_tinfo_abort_init(); } struct wcore_tinfo* |