1109998Smarkm//===----------------------------------------------------------------------===// 2109998Smarkm// 3109998Smarkm// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4109998Smarkm// See https://llvm.org/LICENSE.txt for license information. 5109998Smarkm// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6109998Smarkm// 7109998Smarkm// 8109998Smarkm// This file implements the storage for the "Caught Exception Stack" 9109998Smarkm// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack 10215697Ssimon// 11215697Ssimon//===----------------------------------------------------------------------===// 12109998Smarkm 13109998Smarkm#include "cxa_exception.h" 14109998Smarkm 15109998Smarkm#include <__threading_support> 16109998Smarkm 17109998Smarkm#if defined(_LIBCXXABI_HAS_NO_THREADS) 18109998Smarkm 19109998Smarkmnamespace __cxxabiv1 { 20109998Smarkmextern "C" { 21109998Smarkm static __cxa_eh_globals eh_globals; 22109998Smarkm __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } 23109998Smarkm __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } 24109998Smarkm} // extern "C" 25109998Smarkm} // namespace __cxxabiv1 26109998Smarkm 27109998Smarkm#elif defined(HAS_THREAD_LOCAL) 28109998Smarkm 29109998Smarkmnamespace __cxxabiv1 { 30109998Smarkmnamespace { 31109998Smarkm __cxa_eh_globals *__globals() { 32109998Smarkm static thread_local __cxa_eh_globals eh_globals; 33109998Smarkm return &eh_globals; 34109998Smarkm } 35109998Smarkm} // namespace 36109998Smarkm 37109998Smarkmextern "C" { 38109998Smarkm __cxa_eh_globals *__cxa_get_globals() { return __globals(); } 39109998Smarkm __cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); } 40109998Smarkm} // extern "C" 41109998Smarkm} // namespace __cxxabiv1 42109998Smarkm 43109998Smarkm#else 44109998Smarkm 45109998Smarkm#include "abort_message.h" 46109998Smarkm#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