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