diff options
author | Chad Versace <chad.versace@linux.intel.com> | 2013-07-19 19:17:38 -0700 |
---|---|---|
committer | Chad Versace <chad.versace@linux.intel.com> | 2013-07-19 19:17:38 -0700 |
commit | 5bbe4c0c7ff58439acca23938f494be928070ef6 (patch) | |
tree | 3af17870cc92607ca86394d26109f53cccc39ee9 | |
parent | 7fc45480fc6dadfdbdf55b4c9042edadb57c8376 (diff) | |
parent | f3b201604691c1c67c8a1a518ddcbcd26509223d (diff) |
Merge branch 'support-no-tls'
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/waffle/core/wcore_tinfo.c | 98 |
2 files changed, 83 insertions, 19 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 289dd8b..45c3385 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,8 +223,8 @@ set(CMAKE_C_FLAGS_DEBUG "-g3 -O0 -DDEBUG") # single-stepping. set(CMAKE_C_FLAGS_RELEASE "-g1 -O2 -DNDEBUG") -if(NOT waffle_has_tls) - message(FATAL "Compiler does not support thread local storage with keyword '__thread'") +if(waffle_has_tls) + add_definitions(-DWAFFLE_HAS_TLS) endif() if(waffle_has_tls_model_initial_exec) diff --git a/src/waffle/core/wcore_tinfo.c b/src/waffle/core/wcore_tinfo.c index e40cb30..4184b52 100644 --- a/src/waffle/core/wcore_tinfo.c +++ b/src/waffle/core/wcore_tinfo.c @@ -1,4 +1,4 @@ -// Copyright 2012 Intel Corporation +// Copyright 2012-2013 Intel Corporation // // All rights reserved. // @@ -38,6 +38,10 @@ #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; + +#ifdef WAFFLE_HAS_TLS /// @brief Thread-local storage for all of Waffle. /// /// For documentation on the tls_model, see the GCC manual [1] and @@ -48,39 +52,99 @@ /// /// [2] Ulrich Drepper. "Elf Handling For Thread Local Storage". /// http://people.redhat.com/drepper/tls.pdf - static __thread struct wcore_tinfo wcore_tinfo #ifdef WAFFLE_HAS_TLS_MODEL_INITIAL_EXEC __attribute__((tls_model("initial-exec"))) #endif ; +#endif // WAFFLE_HAS_TLS + +static void __attribute__((noreturn)) +wcore_tinfo_abort_init(void) +{ + printf("waffle: fatal-error: failed to initialize thread local info\n"); + abort(); +} static void -wcore_tinfo_init(void) +wcore_tinfo_key_dtor(void *args) { - assert(!wcore_tinfo.is_init); + struct wcore_tinfo *tinfo = args; + if (!tinfo) + return; - // FIXME: wcore_tinfo.error leaks at thread exit. To fix this, Waffle - // FIXME: needs a function like eglTerminate(). - wcore_tinfo.error = wcore_error_tinfo_create(); - if (!wcore_tinfo.error) - goto error; + wcore_error_tinfo_destroy(tinfo->error); - wcore_tinfo.is_init = true; - return; +#ifndef WAFFLE_HAS_TLS + free(tinfo); +#endif +} -error: - printf("waffle: fatal-error: failed to initialize thread local info\n"); - abort(); +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; + + tinfo->error = wcore_error_tinfo_create(); + if (!tinfo->error) + wcore_tinfo_abort_init(); + + tinfo->is_init = true; + +#ifdef WAFFLE_HAS_TLS + // 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(); +#endif + + err = pthread_setspecific(wcore_tinfo_key, tinfo); + if (err) + wcore_tinfo_abort_init(); } struct wcore_tinfo* wcore_tinfo_get(void) { - if (!wcore_tinfo.is_init) - wcore_tinfo_init(); - +#ifdef WAFFLE_HAS_TLS + wcore_tinfo_init(&wcore_tinfo); return &wcore_tinfo; +#else + int err; + struct wcore_tinfo *tinfo; + + err = pthread_once(&wcore_tinfo_once, wcore_tinfo_key_create); + if (err) + wcore_tinfo_abort_init(); + + tinfo = pthread_getspecific(wcore_tinfo_key); + if (tinfo) + return tinfo; + + tinfo = malloc(sizeof(*tinfo)); + if (!tinfo) + wcore_tinfo_abort_init(); + + wcore_tinfo_init(tinfo); + return tinfo; +#endif } /// @} |