1 //===--------------------- cxa_exception_storage.cpp ----------------------===// 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 19 namespace __cxxabiv1 { 20 extern "C" { 21 static __cxa_eh_globals eh_globals; __cxa_get_globals()22 __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } __cxa_get_globals_fast()23 __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } 24 } 25 } 26 27 #elif defined(HAS_THREAD_LOCAL) 28 29 namespace __cxxabiv1 { 30 31 namespace { __globals()32 __cxa_eh_globals * __globals () { 33 static thread_local __cxa_eh_globals eh_globals; 34 return &eh_globals; 35 } 36 } 37 38 extern "C" { __cxa_get_globals()39 __cxa_eh_globals * __cxa_get_globals () { return __globals (); } __cxa_get_globals_fast()40 __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); } 41 } 42 } 43 44 #else 45 46 #include "abort_message.h" 47 #include "fallback_malloc.h" 48 49 #if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) 50 #pragma comment(lib, "pthread") 51 #endif 52 53 // In general, we treat all threading errors as fatal. 54 // We cannot call std::terminate() because that will in turn 55 // call __cxa_get_globals() and cause infinite recursion. 56 57 namespace __cxxabiv1 { 58 namespace { 59 std::__libcpp_tls_key key_; 60 std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; 61 destruct_(void * p)62 void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) { 63 __free_with_fallback ( p ); 64 if ( 0 != std::__libcpp_tls_set ( key_, NULL ) ) 65 abort_message("cannot zero out thread value for __cxa_get_globals()"); 66 } 67 construct_()68 void construct_ () { 69 if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) ) 70 abort_message("cannot create thread specific key for __cxa_get_globals()"); 71 } 72 } 73 74 extern "C" { __cxa_get_globals()75 __cxa_eh_globals * __cxa_get_globals () { 76 // Try to get the globals for this thread 77 __cxa_eh_globals* retVal = __cxa_get_globals_fast (); 78 79 // If this is the first time we've been asked for these globals, create them 80 if ( NULL == retVal ) { 81 retVal = static_cast<__cxa_eh_globals*> 82 (__calloc_with_fallback (1, sizeof (__cxa_eh_globals))); 83 if ( NULL == retVal ) 84 abort_message("cannot allocate __cxa_eh_globals"); 85 if ( 0 != std::__libcpp_tls_set ( key_, retVal ) ) 86 abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); 87 } 88 return retVal; 89 } 90 91 // Note that this implementation will reliably return NULL if not 92 // preceded by a call to __cxa_get_globals(). This is an extension 93 // to the Itanium ABI and is taken advantage of in several places in 94 // libc++abi. __cxa_get_globals_fast()95 __cxa_eh_globals * __cxa_get_globals_fast () { 96 // First time through, create the key. 97 if (0 != std::__libcpp_execute_once(&flag_, construct_)) 98 abort_message("execute once failure in __cxa_get_globals_fast()"); 99 // static int init = construct_(); 100 return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); 101 } 102 103 } 104 } 105 #endif 106