xref: /openbsd-src/gnu/llvm/libcxxabi/src/cxa_exception_storage.cpp (revision 8f1d572453a8bab44a2fe956e25efc4124e87e82)
1*8f1d5724Srobert //===----------------------------------------------------------------------===//
279c2e3e6Spatrick //
379c2e3e6Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
479c2e3e6Spatrick // See https://llvm.org/LICENSE.txt for license information.
579c2e3e6Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
679c2e3e6Spatrick //
779c2e3e6Spatrick //
879c2e3e6Spatrick //  This file implements the storage for the "Caught Exception Stack"
979c2e3e6Spatrick //  https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack
1079c2e3e6Spatrick //
1179c2e3e6Spatrick //===----------------------------------------------------------------------===//
1279c2e3e6Spatrick 
1379c2e3e6Spatrick #include "cxa_exception.h"
1479c2e3e6Spatrick 
1579c2e3e6Spatrick #include <__threading_support>
1679c2e3e6Spatrick 
1779c2e3e6Spatrick #if defined(_LIBCXXABI_HAS_NO_THREADS)
1879c2e3e6Spatrick 
1979c2e3e6Spatrick namespace __cxxabiv1 {
2079c2e3e6Spatrick extern "C" {
2179c2e3e6Spatrick     static __cxa_eh_globals eh_globals;
__cxa_get_globals()2279c2e3e6Spatrick     __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
__cxa_get_globals_fast()2379c2e3e6Spatrick     __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; }
24*8f1d5724Srobert } // extern "C"
25*8f1d5724Srobert } // namespace __cxxabiv1
2679c2e3e6Spatrick 
2779c2e3e6Spatrick #elif defined(HAS_THREAD_LOCAL)
2879c2e3e6Spatrick 
2979c2e3e6Spatrick namespace __cxxabiv1 {
3079c2e3e6Spatrick namespace {
__globals()3179c2e3e6Spatrick     __cxa_eh_globals *__globals() {
3279c2e3e6Spatrick         static thread_local __cxa_eh_globals eh_globals;
3379c2e3e6Spatrick         return &eh_globals;
3479c2e3e6Spatrick     }
35*8f1d5724Srobert } // namespace
3679c2e3e6Spatrick 
3779c2e3e6Spatrick extern "C" {
__cxa_get_globals()3879c2e3e6Spatrick     __cxa_eh_globals *__cxa_get_globals() { return __globals(); }
__cxa_get_globals_fast()3979c2e3e6Spatrick     __cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); }
40*8f1d5724Srobert } // extern "C"
41*8f1d5724Srobert } // namespace __cxxabiv1
4279c2e3e6Spatrick 
4379c2e3e6Spatrick #else
4479c2e3e6Spatrick 
4579c2e3e6Spatrick #include "abort_message.h"
4679c2e3e6Spatrick #include "fallback_malloc.h"
4779c2e3e6Spatrick 
4879c2e3e6Spatrick #if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
4979c2e3e6Spatrick #pragma comment(lib, "pthread")
5079c2e3e6Spatrick #endif
5179c2e3e6Spatrick 
5279c2e3e6Spatrick //  In general, we treat all threading errors as fatal.
5379c2e3e6Spatrick //  We cannot call std::terminate() because that will in turn
5479c2e3e6Spatrick //  call __cxa_get_globals() and cause infinite recursion.
5579c2e3e6Spatrick 
5679c2e3e6Spatrick namespace __cxxabiv1 {
5779c2e3e6Spatrick namespace {
5879c2e3e6Spatrick     std::__libcpp_tls_key key_;
5979c2e3e6Spatrick     std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER;
6079c2e3e6Spatrick 
destruct_(void * p)6179c2e3e6Spatrick     void _LIBCPP_TLS_DESTRUCTOR_CC destruct_(void *p) {
6279c2e3e6Spatrick         __free_with_fallback(p);
6379c2e3e6Spatrick         if (0 != std::__libcpp_tls_set(key_, NULL))
6479c2e3e6Spatrick             abort_message("cannot zero out thread value for __cxa_get_globals()");
6579c2e3e6Spatrick     }
6679c2e3e6Spatrick 
construct_()6779c2e3e6Spatrick     void construct_() {
6879c2e3e6Spatrick         if (0 != std::__libcpp_tls_create(&key_, destruct_))
6979c2e3e6Spatrick             abort_message("cannot create thread specific key for __cxa_get_globals()");
7079c2e3e6Spatrick     }
71*8f1d5724Srobert } // namespace
7279c2e3e6Spatrick 
7379c2e3e6Spatrick extern "C" {
__cxa_get_globals()7479c2e3e6Spatrick     __cxa_eh_globals *__cxa_get_globals() {
7579c2e3e6Spatrick         // Try to get the globals for this thread
7679c2e3e6Spatrick         __cxa_eh_globals *retVal = __cxa_get_globals_fast();
7779c2e3e6Spatrick 
7879c2e3e6Spatrick         // If this is the first time we've been asked for these globals, create them
7979c2e3e6Spatrick         if (NULL == retVal) {
80*8f1d5724Srobert             retVal = static_cast<__cxa_eh_globals*>(
81*8f1d5724Srobert                 __calloc_with_fallback(1, sizeof(__cxa_eh_globals)));
8279c2e3e6Spatrick             if (NULL == retVal)
8379c2e3e6Spatrick                 abort_message("cannot allocate __cxa_eh_globals");
8479c2e3e6Spatrick             if (0 != std::__libcpp_tls_set(key_, retVal))
8579c2e3e6Spatrick                abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()");
8679c2e3e6Spatrick         }
8779c2e3e6Spatrick         return retVal;
8879c2e3e6Spatrick     }
8979c2e3e6Spatrick 
9079c2e3e6Spatrick     // Note that this implementation will reliably return NULL if not
9179c2e3e6Spatrick     // preceded by a call to __cxa_get_globals().  This is an extension
9279c2e3e6Spatrick     // to the Itanium ABI and is taken advantage of in several places in
9379c2e3e6Spatrick     // libc++abi.
__cxa_get_globals_fast()9479c2e3e6Spatrick     __cxa_eh_globals *__cxa_get_globals_fast() {
9579c2e3e6Spatrick         // First time through, create the key.
9679c2e3e6Spatrick         if (0 != std::__libcpp_execute_once(&flag_, construct_))
9779c2e3e6Spatrick             abort_message("execute once failure in __cxa_get_globals_fast()");
9879c2e3e6Spatrick         return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_));
9979c2e3e6Spatrick     }
100*8f1d5724Srobert } // extern "C"
101*8f1d5724Srobert } // namespace __cxxabiv1
10279c2e3e6Spatrick 
10379c2e3e6Spatrick #endif
104