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