1 //===--------------------- cxa_exception_storage.cpp ----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 // 9 // This file implements the storage for the "Caught Exception Stack" 10 // http://mentorembedded.github.io/cxx-abi/abi-eh.html (section 2.2.2) 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "cxa_exception.hpp" 15 16 #include <__threading_support> 17 18 #if defined(_LIBCXXABI_HAS_NO_THREADS) 19 20 namespace __cxxabiv1 { 21 extern "C" { 22 static __cxa_eh_globals eh_globals; 23 __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } 24 __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } 25 } 26 } 27 28 #elif defined(HAS_THREAD_LOCAL) 29 30 namespace __cxxabiv1 { 31 32 namespace { 33 __cxa_eh_globals * __globals () { 34 static thread_local __cxa_eh_globals eh_globals; 35 return &eh_globals; 36 } 37 } 38 39 extern "C" { 40 __cxa_eh_globals * __cxa_get_globals () { return __globals (); } 41 __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); } 42 } 43 } 44 45 #else 46 47 #include "abort_message.h" 48 #include "fallback_malloc.h" 49 50 // In general, we treat all threading errors as fatal. 51 // We cannot call std::terminate() because that will in turn 52 // call __cxa_get_globals() and cause infinite recursion. 53 54 namespace __cxxabiv1 { 55 namespace { 56 std::__libcpp_tls_key key_; 57 std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; 58 59 void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) { 60 __free_with_fallback ( p ); 61 if ( 0 != std::__libcpp_tls_set ( key_, NULL ) ) 62 abort_message("cannot zero out thread value for __cxa_get_globals()"); 63 } 64 65 void construct_ () { 66 if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) ) 67 abort_message("cannot create thread specific key for __cxa_get_globals()"); 68 } 69 } 70 71 extern "C" { 72 __cxa_eh_globals * __cxa_get_globals () { 73 // Try to get the globals for this thread 74 __cxa_eh_globals* retVal = __cxa_get_globals_fast (); 75 76 // If this is the first time we've been asked for these globals, create them 77 if ( NULL == retVal ) { 78 retVal = static_cast<__cxa_eh_globals*> 79 (__calloc_with_fallback (1, sizeof (__cxa_eh_globals))); 80 if ( NULL == retVal ) 81 abort_message("cannot allocate __cxa_eh_globals"); 82 if ( 0 != std::__libcpp_tls_set ( key_, retVal ) ) 83 abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); 84 } 85 return retVal; 86 } 87 88 // Note that this implementation will reliably return NULL if not 89 // preceded by a call to __cxa_get_globals(). This is an extension 90 // to the Itanium ABI and is taken advantage of in several places in 91 // libc++abi. 92 __cxa_eh_globals * __cxa_get_globals_fast () { 93 // First time through, create the key. 94 if (0 != std::__libcpp_execute_once(&flag_, construct_)) 95 abort_message("execute once failure in __cxa_get_globals_fast()"); 96 // static int init = construct_(); 97 return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); 98 } 99 100 } 101 } 102 #endif 103