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 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 } 25} 26 27#elif defined(HAS_THREAD_LOCAL) 28 29namespace __cxxabiv1 { 30 31namespace { 32 __cxa_eh_globals * __globals () { 33 static thread_local __cxa_eh_globals eh_globals; 34 return &eh_globals; 35 } 36 } 37 38extern "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#if defined(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) 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 57namespace __cxxabiv1 { 58namespace { 59 std::__libcpp_tls_key key_; 60 std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; 61 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 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 74extern "C" { 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. 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