1 | //===----------------------------------------------------------------------===// |
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 <__thread/support.h> |
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 | } // extern "C" |
25 | } // namespace __cxxabiv1 |
26 | |
27 | #elif defined(HAS_THREAD_LOCAL) |
28 | |
29 | namespace __cxxabiv1 { |
30 | namespace { |
31 | __cxa_eh_globals *__globals() { |
32 | static thread_local __cxa_eh_globals eh_globals; |
33 | return &eh_globals; |
34 | } |
35 | } // namespace |
36 | |
37 | extern "C" { |
38 | __cxa_eh_globals *__cxa_get_globals() { return __globals(); } |
39 | __cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); } |
40 | } // extern "C" |
41 | } // namespace __cxxabiv1 |
42 | |
43 | #else |
44 | |
45 | #include "abort_message.h" |
46 | #include "fallback_malloc.h" |
47 | |
48 | #if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) |
49 | #pragma comment(lib, "pthread") |
50 | #endif |
51 | |
52 | // In general, we treat all threading errors as fatal. |
53 | // We cannot call std::terminate() because that will in turn |
54 | // call __cxa_get_globals() and cause infinite recursion. |
55 | |
56 | namespace __cxxabiv1 { |
57 | namespace { |
58 | std::__libcpp_tls_key key_; |
59 | std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; |
60 | |
61 | void _LIBCPP_TLS_DESTRUCTOR_CC destruct_(void *p) { |
62 | __free_with_fallback(p); |
63 | if (0 != std::__libcpp_tls_set(key_, NULL)) |
64 | abort_message("cannot zero out thread value for __cxa_get_globals()" ); |
65 | } |
66 | |
67 | void construct_() { |
68 | if (0 != std::__libcpp_tls_create(&key_, destruct_)) |
69 | abort_message(format: "cannot create thread specific key for __cxa_get_globals()" ); |
70 | } |
71 | } // namespace |
72 | |
73 | extern "C" { |
74 | __cxa_eh_globals *__cxa_get_globals() { |
75 | // Try to get the globals for this thread |
76 | __cxa_eh_globals *retVal = __cxa_get_globals_fast(); |
77 | |
78 | // If this is the first time we've been asked for these globals, create them |
79 | if (NULL == retVal) { |
80 | retVal = static_cast<__cxa_eh_globals*>( |
81 | __calloc_with_fallback(1, sizeof(__cxa_eh_globals))); |
82 | if (NULL == retVal) |
83 | abort_message(format: "cannot allocate __cxa_eh_globals" ); |
84 | if (0 != std::__libcpp_tls_set(key_, retVal)) |
85 | abort_message(format: "std::__libcpp_tls_set failure in __cxa_get_globals()" ); |
86 | } |
87 | return retVal; |
88 | } |
89 | |
90 | // Note that this implementation will reliably return NULL if not |
91 | // preceded by a call to __cxa_get_globals(). This is an extension |
92 | // to the Itanium ABI and is taken advantage of in several places in |
93 | // libc++abi. |
94 | __cxa_eh_globals *__cxa_get_globals_fast() { |
95 | // First time through, create the key. |
96 | if (0 != std::__libcpp_execute_once(&flag_, construct_)) |
97 | abort_message(format: "execute once failure in __cxa_get_globals_fast()" ); |
98 | return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); |
99 | } |
100 | } // extern "C" |
101 | } // namespace __cxxabiv1 |
102 | |
103 | #endif |
104 | |