/ src / cxa_exception_storage.cpp
cxa_exception_storage.cpp
  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;
 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  #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  
 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  
 74  extern "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