cxa_exception_storage.cpp revision 71ba2871943cec379da0585c16f69fb5ac5a884b
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#include <__threading_support>
18
19#if defined(_LIBCXXABI_HAS_NO_THREADS)
20
21namespace __cxxabiv1 {
22extern "C" {
23    static __cxa_eh_globals eh_globals;
24    __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
25    __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; }
26    }
27}
28
29#elif defined(HAS_THREAD_LOCAL)
30
31namespace __cxxabiv1 {
32
33namespace {
34    __cxa_eh_globals * __globals () {
35        static thread_local __cxa_eh_globals eh_globals;
36        return &eh_globals;
37        }
38    }
39
40extern "C" {
41    __cxa_eh_globals * __cxa_get_globals      () { return __globals (); }
42    __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); }
43    }
44}
45
46#else
47
48#include "abort_message.h"
49#include "fallback_malloc.h"
50
51//  In general, we treat all threading errors as fatal.
52//  We cannot call std::terminate() because that will in turn
53//  call __cxa_get_globals() and cause infinite recursion.
54
55namespace __cxxabiv1 {
56namespace {
57    std::__libcpp_tls_key key_;
58    std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER;
59
60    void destruct_ (void *p) {
61        __free_with_fallback ( p );
62        if ( 0 != std::__libcpp_tls_set ( key_, NULL ) )
63            abort_message("cannot zero out thread value for __cxa_get_globals()");
64        }
65
66    void construct_ () {
67        if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) )
68            abort_message("cannot create thread specific key for __cxa_get_globals()");
69        }
70}
71
72extern "C" {
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                        (__calloc_with_fallback (1, sizeof (__cxa_eh_globals)));
81            if ( NULL == retVal )
82                abort_message("cannot allocate __cxa_eh_globals");
83            if ( 0 != std::__libcpp_tls_set ( key_, retVal ) )
84               abort_message("std::__libcpp_tls_set 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.
93    __cxa_eh_globals * __cxa_get_globals_fast () {
94    //  First time through, create the key.
95        if (0 != std::__libcpp_execute_once(&flag_, construct_))
96            abort_message("execute once failure in __cxa_get_globals_fast()");
97//        static int init = construct_();
98        return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_));
99        }
100
101}
102}
103#endif
104