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