1//===----------------------------------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7// 8// This file implements the storage for the "Caught Exception Stack" 9// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack 10// 11//===----------------------------------------------------------------------===// 12 13#include "cxa_exception.h" 14 15#include <__threading_support> 16 17#if defined(_LIBCXXABI_HAS_NO_THREADS) 18 19namespace __cxxabiv1 { 20extern "C" { 21 static __cxa_eh_globals eh_globals; 22 __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } 23 __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } 24} // extern "C" 25} // namespace __cxxabiv1 26 27#elif defined(HAS_THREAD_LOCAL) 28 29namespace __cxxabiv1 { 30namespace { 31 __cxa_eh_globals *__globals() { 32 static thread_local __cxa_eh_globals eh_globals; 33 return &eh_globals; 34 } 35} // namespace 36 37extern "C" { 38 __cxa_eh_globals *__cxa_get_globals() { return __globals(); } 39 __cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); } 40} // extern "C" 41} // namespace __cxxabiv1 42 43#else 44 45#include "abort_message.h" 46#include "fallback_malloc.h" 47 48#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) 49#pragma comment(lib, "pthread") 50#endif 51 52// In general, we treat all threading errors as fatal. 53// We cannot call std::terminate() because that will in turn 54// call __cxa_get_globals() and cause infinite recursion. 55 56namespace __cxxabiv1 { 57namespace { 58 std::__libcpp_tls_key key_; 59 std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; 60 61 void _LIBCPP_TLS_DESTRUCTOR_CC destruct_(void *p) { 62 __free_with_fallback(p); 63 if (0 != std::__libcpp_tls_set(key_, NULL)) 64 abort_message("cannot zero out thread value for __cxa_get_globals()"); 65 } 66 67 void construct_() { 68 if (0 != std::__libcpp_tls_create(&key_, destruct_)) 69 abort_message("cannot create thread specific key for __cxa_get_globals()"); 70 } 71} // namespace 72 73extern "C" { 74 __cxa_eh_globals *__cxa_get_globals() { 75 // Try to get the globals for this thread 76 __cxa_eh_globals *retVal = __cxa_get_globals_fast(); 77 78 // If this is the first time we've been asked for these globals, create them 79 if (NULL == retVal) { 80 retVal = static_cast<__cxa_eh_globals*>( 81 __calloc_with_fallback(1, sizeof(__cxa_eh_globals))); 82 if (NULL == retVal) 83 abort_message("cannot allocate __cxa_eh_globals"); 84 if (0 != std::__libcpp_tls_set(key_, retVal)) 85 abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); 86 } 87 return retVal; 88 } 89 90 // Note that this implementation will reliably return NULL if not 91 // preceded by a call to __cxa_get_globals(). This is an extension 92 // to the Itanium ABI and is taken advantage of in several places in 93 // libc++abi. 94 __cxa_eh_globals *__cxa_get_globals_fast() { 95 // First time through, create the key. 96 if (0 != std::__libcpp_execute_once(&flag_, construct_)) 97 abort_message("execute once failure in __cxa_get_globals_fast()"); 98 return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); 99 } 100} // extern "C" 101} // namespace __cxxabiv1 102 103#endif 104