static const char* __bionic_set_dlerror(char* new_value) { char** dlerror_slot = &reinterpret_cast<char**>(__get_tls())[TLS_SLOT_DLERROR]; const char* old_value = *dlerror_slot; *dlerror_slot = new_value; return old_value; }
// We flag the __libc_preinit function as a constructor to ensure // that its address is listed in libc.so's .init_array section. // This ensures that the function is called by the dynamic linker // as soon as the shared library is loaded. __attribute__((constructor)) static void __libc_preinit() { /* ARC MOD BEGIN */ #endif /* Initialize IRT table using __nacl_irt_query. */ #if defined(__native_client__) || defined(BARE_METAL_BIONIC) __nacl_irt_query = irt_query; __init_irt_table(); #endif /* ARC MOD END */ // Read the kernel argument block pointer from TLS. void* tls = const_cast<void*>(__get_tls()); KernelArgumentBlock** args_slot = &reinterpret_cast<KernelArgumentBlock**>(tls)[TLS_SLOT_BIONIC_PREINIT]; KernelArgumentBlock* args = *args_slot; // Clear the slot so no other initializer sees its value. // __libc_init_common() will change the TLS area so the old one won't be accessible anyway. *args_slot = NULL; __libc_init_common(*args); // Hooks for the debug malloc and pthread libraries to let them know that we're starting up. /* ARC MOD BEGIN */ // We do not use the pthread debug feature. // pthread_debug_init(); /* ARC MOD END */ malloc_debug_init(); }
void __libc_preinit(void) { /* Read the ELF data pointer from a special slot of the * TLS area, then call __libc_init_common with it. * * Note that: * - we clear the slot so no other initializer sees its value. * - __libc_init_common() will change the TLS area so the old one * won't be accessible anyway. */ void** tls_area = (void**)__get_tls(); unsigned* elfdata = tls_area[TLS_SLOT_BIONIC_PREINIT]; tls_area[TLS_SLOT_BIONIC_PREINIT] = NULL; __libc_init_common(elfdata); /* Setup pthread routines accordingly to the environment. * Requires system properties */ #ifdef PTHREAD_DEBUG extern void pthread_debug_init(void); pthread_debug_init(); #endif /* Setup malloc routines accordingly to the environment. * Requires system properties */ extern void malloc_debug_init(void); malloc_debug_init(); }
int pthread_setspecific(pthread_key_t key, const void* ptr) { ScopedTlsMapAccess tls_map; if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { return EINVAL; } __get_tls()[key] = const_cast<void*>(ptr); return 0; }
int pthread_setspecific(pthread_key_t key, const void* ptr) { ScopedTlsMapAccess tls_map; if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { return EINVAL; } ((uint32_t *)__get_tls())[key] = (uint32_t)ptr; return 0; }
void* pthread_getspecific(pthread_key_t key) { if (!IsValidUserKey(key)) { return NULL; } // For performance reasons, we do not lock/unlock the global TLS map // to check that the key is properly allocated. If the key was not // allocated, the value read from the TLS should always be NULL // due to pthread_key_delete() clearing the values for all threads. return __get_tls()[key]; }
// We flag the __libc_preinit function as a constructor to ensure // that its address is listed in libc.so's .init_array section. // This ensures that the function is called by the dynamic linker // as soon as the shared library is loaded. __attribute__((constructor)) static void __libc_preinit() { // Read the kernel argument block pointer from TLS. void** tls = __get_tls(); KernelArgumentBlock** args_slot = &reinterpret_cast<KernelArgumentBlock**>(tls)[TLS_SLOT_BIONIC_PREINIT]; KernelArgumentBlock* args = *args_slot; // Clear the slot so no other initializer sees its value. // __libc_init_common() will change the TLS area so the old one won't be accessible anyway. *args_slot = NULL; __libc_init_common(*args); // Hooks for various libraries to let them know that we're starting up. malloc_debug_init(); netdClientInit(); }
TEST(tls, get_tls_for_art) { get_tls_fn_t get_tls_for_art = NULL; #if !defined(__native_client__) && defined(__i386__) get_tls_for_art = *(get_tls_fn_t*)POINTER_TO_GET_TLS_FUNC_ON_BMM_I386; #elif defined(__native_client__) && defined(__x86_64__) get_tls_for_art = *(get_tls_fn_t*)POINTER_TO_GET_TLS_FUNC_ON_NACL_X86_64; #elif ((defined(__native_client__) && defined(__i386__)) || \ (!defined(__native_client__) && defined(__arm__))) // No fixed address for __get_tls on this target, skipping this test return; #else # error Unsupported target #endif // Note we cannot test get_tls_for_art == __get_tls as // get_tls_for_art is a pointer to __get_tls in runnable-ld.so, // not in libc.so. EXPECT_EQ(get_tls_for_art(), __get_tls()); }
// Called from pthread_exit() to remove all TLS key data // from this thread's TLS area. This must call the destructor of all keys // that have a non-NULL data value and a non-NULL destructor. void CleanAll() { void** tls = __get_tls(); // Because destructors can do funky things like deleting/creating other // keys, we need to implement this in a loop. for (int rounds = PTHREAD_DESTRUCTOR_ITERATIONS; rounds > 0; --rounds) { size_t called_destructor_count = 0; for (int key = 0; key < BIONIC_TLS_SLOTS; ++key) { if (IsInUse(key)) { void* data = tls[key]; void (*key_destructor)(void*) = s_tls_map_.key_destructors[key]; if (data != NULL && key_destructor != NULL) { // we need to clear the key data now, this will prevent the // destructor (or a later one) from seeing the old value if // it calls pthread_getspecific() for some odd reason // we do not do this if 'key_destructor == NULL' just in case another // destructor function might be responsible for manually // releasing the corresponding data. tls[key] = NULL; // because the destructor is free to call pthread_key_create // and/or pthread_key_delete, we need to temporarily unlock // the TLS map Unlock(); (*key_destructor)(data); Lock(); ++called_destructor_count; } } } // If we didn't call any destructors, there is no need to check the TLS data again. if (called_destructor_count == 0) { break; } } }
volatile int* __errno() { return reinterpret_cast<int*>(&(__get_tls()[TLS_SLOT_ERRNO])); }
pthread_internal_t* __get_thread(void) { return reinterpret_cast<pthread_internal_t*>(__get_tls()[TLS_SLOT_THREAD_ID]); }
volatile int* __errno( void ) { return &((volatile int*)__get_tls())[TLS_SLOT_ERRNO]; }