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
19namespace __cxxabiv1 {
20extern "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
29namespace __cxxabiv1 {
30
31namespace {
32    __cxa_eh_globals * __globals () {
33        static thread_local __cxa_eh_globals eh_globals;
34        return &eh_globals;
35        }
36    }
37
38extern "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(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA)
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
57namespace __cxxabiv1 {
58namespace {
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
74extern "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
106