Allocate thread local buffers in __init_tls.
Thread local buffers were using pthread_setspecific for storage with
lazy initialization. pthread_setspecific shares TLS slots between the
linker and libc.so, so thread local buffers being initialized in a
different order between libc.so and the linker meant that bad things
would happen (manifesting as snprintf not working because the
locale was mangled)
Bug: http://b/20464031
Test: /data/nativetest64/bionic-unit-tests/bionic-unit-tests
everything passes
Test: /data/nativetest/bionic-unit-tests/bionic-unit-tests
thread_local tests are failing both before and after (KUSER_HELPERS?)
Test: /data/nativetest64/bionic-unit-tests-static/bionic-unit-tests-static
no additional failures
Change-Id: I9f445a77c6e86979f3fa49c4a5feecf6ec2b0c3f
diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp
index 113118d..38e15b7 100644
--- a/libc/bionic/locale.cpp
+++ b/libc/bionic/locale.cpp
@@ -37,6 +37,8 @@
#include "private/bionic_macros.h"
+#include "bionic/pthread_internal.h"
+
// We only support two locales, the "C" locale (also known as "POSIX"),
// and the "C.UTF-8" locale (also known as "en_US.UTF-8").
@@ -161,17 +163,9 @@
return const_cast<char*>(__bionic_current_locale_is_utf8 ? "C.UTF-8" : "C");
}
-// We can't use a constructor to create g_uselocal_key, because it may be used in constructors.
-static pthread_once_t g_uselocale_once = PTHREAD_ONCE_INIT;
-static pthread_key_t g_uselocale_key;
-
-static void g_uselocale_key_init() {
- pthread_key_create(&g_uselocale_key, NULL);
-}
-
locale_t uselocale(locale_t new_locale) {
- pthread_once(&g_uselocale_once, g_uselocale_key_init);
- locale_t old_locale = static_cast<locale_t>(pthread_getspecific(g_uselocale_key));
+ locale_t* locale_storage = &__get_bionic_tls().locale;
+ locale_t old_locale = *locale_storage;
// If this is the first call to uselocale(3) on this thread, we return LC_GLOBAL_LOCALE.
if (old_locale == NULL) {
@@ -179,7 +173,7 @@
}
if (new_locale != NULL) {
- pthread_setspecific(g_uselocale_key, new_locale);
+ *locale_storage = new_locale;
}
return old_locale;