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;
__cxa_get_globals()22     __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
__cxa_get_globals_fast()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 {
__globals()32     __cxa_eh_globals * __globals () {
33         static thread_local __cxa_eh_globals eh_globals;
34         return &eh_globals;
35         }
36     }
37 
38 extern "C" {
__cxa_get_globals()39     __cxa_eh_globals * __cxa_get_globals      () { return __globals (); }
__cxa_get_globals_fast()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 
destruct_(void * p)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 
construct_()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" {
__cxa_get_globals()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.
__cxa_get_globals_fast()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