/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include "thread-local.h" #ifdef __linux__ #include #include #include extern "C" { extern int arch_prctl(int, unsigned long*); } #endif //__linux__ namespace HPHP { #ifdef USE_GCC_FAST_TLS void ThreadLocalManager::OnThreadExit(void* p) { auto list = getList(p); p = list->head; delete list; while (p != nullptr) { auto* pNode = static_cast*>(p); if (pNode->m_on_thread_exit_fn) { pNode->m_on_thread_exit_fn(p); } p = pNode->m_next; } } void ThreadLocalManager::PushTop(void* nodePtr, size_t nodeSize) { auto& node = *static_cast*>(nodePtr); auto key = GetManager().m_key; auto list = getList(pthread_getspecific(key)); if (UNLIKELY(!list)) { ThreadLocalSetValue(key, list = new ThreadLocalList); } node.m_next = list->head; node.m_size = nodeSize; list->head = node.m_next; } ThreadLocalManager& ThreadLocalManager::GetManager() { static ThreadLocalManager m; return m; } #ifdef __APPLE__ ThreadLocalManager::ThreadLocalList::ThreadLocalList() { pthread_t self = pthread_self(); handler.__routine = ThreadLocalManager::OnThreadExit; handler.__arg = this; handler.__next = self->__cleanup_stack; self->__cleanup_stack = &handler; } #endif #endif #ifdef __linux__ static int visit_phdr(dl_phdr_info* info, size_t, void*) { for (size_t i = 0, n = info->dlpi_phnum; i < n; ++i) { const auto& hdr = info->dlpi_phdr[i]; auto addr = info->dlpi_addr + hdr.p_vaddr; if (addr < 0x100000000LL && hdr.p_type == PT_TLS) { // found the main thread-local section assert(int(hdr.p_memsz) == hdr.p_memsz); // ensure no truncation return hdr.p_memsz; } } return 0; } std::pair getCppTdata() { uintptr_t addr; if (!arch_prctl(ARCH_GET_FS, &addr)) { // fs points to the end of the threadlocal area. size_t size = dl_iterate_phdr(&visit_phdr, nullptr); return {(void*)(addr - size), size}; } return {nullptr, 0}; } #else // how do you find the thread local section on your system? std::pair getCppTdata() { return {nullptr, 0}; } #endif //__linux__ }