diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 8bb1be9d9..c99e69c90 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -191,7 +191,7 @@ int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr, // At offsets >= 0, we have the TLS slots. // At offsets < 0, we have the child stack. thread->tls = reinterpret_cast(reinterpret_cast(thread->attr.stack_base) + - thread->attr.stack_size - BIONIC_TLS_SLOTS * sizeof(void*)); + thread->attr.stack_size - BIONIC_ALIGN(BIONIC_TLS_SLOTS * sizeof(void*), 16)); void* child_stack = thread->tls; __init_tls(thread); diff --git a/libc/dns/resolv/res_state.c b/libc/dns/resolv/res_state.c index 57791d1b9..75bff9775 100644 --- a/libc/dns/resolv/res_state.c +++ b/libc/dns/resolv/res_state.c @@ -50,7 +50,6 @@ #endif static pthread_key_t _res_key; -static pthread_once_t _res_once = PTHREAD_ONCE_INIT; typedef struct { int _h_errno; @@ -105,6 +104,7 @@ _res_thread_free( void* _rt ) free(rt); } +__attribute__((constructor)) static void _res_init_key( void ) { @@ -115,7 +115,6 @@ static _res_thread* _res_thread_get(void) { _res_thread* rt; - pthread_once( &_res_once, _res_init_key ); rt = pthread_getspecific( _res_key ); if (rt != NULL) { diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h index 0c6e06239..4a3516683 100644 --- a/libc/private/bionic_tls.h +++ b/libc/private/bionic_tls.h @@ -75,22 +75,40 @@ enum { * enumerated above, and then there are those that are allocated during startup by calls to * pthread_key_create; grep for GLOBAL_INIT_THREAD_LOCAL_BUFFER to find those. We need to manually * maintain that second number, but pthread_test will fail if we forget. + * Following are current pthread keys used internally: + * basename libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * dirname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * uselocale libc + * getmntent_mntent libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * getmntent_strings libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * ptsname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * ttyname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * strerror libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * strsignal libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * stubs libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER) + * _res_key libc + * je_thread_allocated_tsd jemalloc + * je_arenas_tsd jemalloc + * je_tcache_tsd jemalloc + * je_tcache_enabled_tsd jemalloc + * je_quarantine_tsd jemalloc + * */ -#define GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT 9 + +#define LIBC_TLS_RESERVED_SLOTS 11 #if defined(USE_JEMALLOC) /* jemalloc uses 5 keys for itself. */ -#define BIONIC_TLS_RESERVED_SLOTS (GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT + 5) +#define BIONIC_TLS_RESERVED_SLOTS (LIBC_TLS_RESERVED_SLOTS + 5) #else -#define BIONIC_TLS_RESERVED_SLOTS GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT +#define BIONIC_TLS_RESERVED_SLOTS LIBC_TLS_RESERVED_SLOTS #endif /* * Maximum number of elements in the TLS array. * This includes space for pthread keys and our own internal slots. - * We need to round up to maintain stack alignment. */ -#define BIONIC_TLS_SLOTS BIONIC_ALIGN(PTHREAD_KEYS_MAX + TLS_SLOT_FIRST_USER_SLOT + BIONIC_TLS_RESERVED_SLOTS, 4) +#define BIONIC_TLS_SLOTS (PTHREAD_KEYS_MAX + TLS_SLOT_FIRST_USER_SLOT + BIONIC_TLS_RESERVED_SLOTS) __END_DECLS diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index f63d1ee93..4fc5bed51 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -42,19 +42,19 @@ TEST(pthread, pthread_key_create) { } TEST(pthread, pthread_keys_max) { - // POSIX says PTHREAD_KEYS_MAX should be at least 128. - ASSERT_GE(PTHREAD_KEYS_MAX, 128); + // POSIX says PTHREAD_KEYS_MAX should be at least _POSIX_THREAD_KEYS_MAX. + ASSERT_GE(PTHREAD_KEYS_MAX, _POSIX_THREAD_KEYS_MAX); } -TEST(pthread, _SC_THREAD_KEYS_MAX_big_enough_for_POSIX) { - // sysconf shouldn't return a smaller value. +TEST(pthread, sysconf_SC_THREAD_KEYS_MAX_eq_PTHREAD_KEYS_MAX) { int sysconf_max = sysconf(_SC_THREAD_KEYS_MAX); - ASSERT_GE(sysconf_max, PTHREAD_KEYS_MAX); + ASSERT_EQ(sysconf_max, PTHREAD_KEYS_MAX); } TEST(pthread, pthread_key_many_distinct) { - // We should be able to allocate at least this many keys. - int nkeys = sysconf(_SC_THREAD_KEYS_MAX) / 2; + // As gtest uses pthread keys, we can't allocate exactly PTHREAD_KEYS_MAX + // pthread keys, but We should be able to allocate at least this many keys. + int nkeys = PTHREAD_KEYS_MAX / 2; std::vector keys; auto scope_guard = make_scope_guard([&keys]{ @@ -80,14 +80,13 @@ TEST(pthread, pthread_key_many_distinct) { } } -TEST(pthread, pthread_key_EAGAIN) { - int sysconf_max = sysconf(_SC_THREAD_KEYS_MAX); - +TEST(pthread, pthread_key_not_exceed_PTHREAD_KEYS_MAX) { std::vector keys; int rv = 0; - // Two keys are used by gtest, so sysconf_max should be more than we are - // allowed to allocate now. - for (int i = 0; i < sysconf_max; i++) { + + // Pthread keys are used by gtest, so PTHREAD_KEYS_MAX should + // be more than we are allowed to allocate now. + for (int i = 0; i < PTHREAD_KEYS_MAX; i++) { pthread_key_t key; rv = pthread_key_create(&key, NULL); if (rv == EAGAIN) { diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp index 96d66e48d..f5c0524c4 100644 --- a/tests/unistd_test.cpp +++ b/tests/unistd_test.cpp @@ -576,7 +576,7 @@ TEST(unistd, _POSIX_macros_smoke) { EXPECT_EQ(_POSIX_VERSION, _POSIX_THREAD_ATTR_STACKSIZE); EXPECT_EQ(0, _POSIX_THREAD_CPUTIME); // Use sysconf to detect support at runtime. EXPECT_GT(_POSIX_THREAD_DESTRUCTOR_ITERATIONS, 0); - EXPECT_GT(_POSIX_THREAD_KEYS_MAX, 0); + EXPECT_EQ(_POSIX_THREAD_KEYS_MAX, 128); EXPECT_EQ(_POSIX_VERSION, _POSIX_THREAD_PRIORITY_SCHEDULING); EXPECT_EQ(_POSIX_VERSION, _POSIX_THREAD_PRIO_INHERIT); EXPECT_EQ(_POSIX_VERSION, _POSIX_THREAD_PRIO_PROTECT);