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(__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
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