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 <__thread/support.h> 16 17 #if defined(_LIBCXXABI_HAS_NO_THREADS) 18 19 namespace __cxxabiv1 { 20 extern "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 __has_feature(cxx_thread_local) 28 29 namespace __cxxabiv1 { 30 namespace { 31 __cxa_eh_globals *__globals() { 32 static thread_local __cxa_eh_globals eh_globals; 33 return &eh_globals; 34 } 35 } // namespace 36 37 extern "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 56 namespace __cxxabiv1 { 57 namespace { 58 std::__libcpp_tls_key key_; 59 constinit 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 73 extern "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