1 // -*- C++ -*- Manage the thread-local exception globals. 2 // Copyright (C) 2001-2018 Free Software Foundation, Inc. 3 // 4 // This file is part of GCC. 5 // 6 // GCC is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 // 11 // GCC is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 #include <bits/c++config.h> 26 #include <exception> 27 #include <cstdlib> 28 #include "cxxabi.h" 29 #include "unwind-cxx.h" 30 #include "bits/gthr.h" 31 32 #if _GLIBCXX_HOSTED 33 using std::free; 34 using std::malloc; 35 #else 36 // In a freestanding environment, these functions may not be 37 // available -- but for now, we assume that they are. 38 extern "C" void *malloc (std::size_t); 39 extern "C" void free(void *); 40 #endif 41 42 using namespace __cxxabiv1; 43 44 #if _GLIBCXX_HAVE_TLS 45 46 namespace 47 { 48 abi::__cxa_eh_globals* 49 get_global() _GLIBCXX_NOTHROW 50 { 51 static __thread abi::__cxa_eh_globals global; 52 return &global; 53 } 54 } // anonymous namespace 55 56 extern "C" __cxa_eh_globals* 57 __cxxabiv1::__cxa_get_globals_fast() _GLIBCXX_NOTHROW 58 { return get_global(); } 59 60 extern "C" __cxa_eh_globals* 61 __cxxabiv1::__cxa_get_globals() _GLIBCXX_NOTHROW 62 { return get_global(); } 63 64 65 #else 66 67 // Single-threaded fallback buffer. 68 static __cxa_eh_globals eh_globals; 69 70 #if __GTHREADS 71 72 static void 73 eh_globals_dtor(void* ptr) 74 { 75 if (ptr) 76 { 77 __cxa_eh_globals* g = reinterpret_cast<__cxa_eh_globals*>(ptr); 78 __cxa_exception* exn = g->caughtExceptions; 79 __cxa_exception* next; 80 while (exn) 81 { 82 next = exn->nextException; 83 _Unwind_DeleteException(&exn->unwindHeader); 84 exn = next; 85 } 86 free(ptr); 87 } 88 } 89 90 struct __eh_globals_init 91 { 92 __gthread_key_t _M_key; 93 bool _M_init; 94 95 __eh_globals_init() : _M_init(false) 96 { 97 if (__gthread_active_p()) 98 _M_init = __gthread_key_create(&_M_key, eh_globals_dtor) == 0; 99 } 100 101 ~__eh_globals_init() 102 { 103 if (_M_init) 104 __gthread_key_delete(_M_key); 105 _M_init = false; 106 } 107 }; 108 109 static __eh_globals_init init; 110 111 extern "C" __cxa_eh_globals* 112 __cxxabiv1::__cxa_get_globals_fast() _GLIBCXX_NOTHROW 113 { 114 __cxa_eh_globals* g; 115 if (init._M_init) 116 g = static_cast<__cxa_eh_globals*>(__gthread_getspecific(init._M_key)); 117 else 118 g = &eh_globals; 119 return g; 120 } 121 122 extern "C" __cxa_eh_globals* 123 __cxxabiv1::__cxa_get_globals() _GLIBCXX_NOTHROW 124 { 125 __cxa_eh_globals* g; 126 if (init._M_init) 127 { 128 g = static_cast<__cxa_eh_globals*>(__gthread_getspecific(init._M_key)); 129 if (!g) 130 { 131 void* v = malloc(sizeof(__cxa_eh_globals)); 132 if (v == 0 || __gthread_setspecific(init._M_key, v) != 0) 133 std::terminate(); 134 g = static_cast<__cxa_eh_globals*>(v); 135 g->caughtExceptions = 0; 136 g->uncaughtExceptions = 0; 137 #ifdef __ARM_EABI_UNWINDER__ 138 g->propagatingExceptions = 0; 139 #endif 140 } 141 } 142 else 143 g = &eh_globals; 144 return g; 145 } 146 147 #else 148 149 extern "C" __cxa_eh_globals* 150 __cxxabiv1::__cxa_get_globals_fast() _GLIBCXX_NOTHROW 151 { return &eh_globals; } 152 153 extern "C" __cxa_eh_globals* 154 __cxxabiv1::__cxa_get_globals() _GLIBCXX_NOTHROW 155 { return &eh_globals; } 156 157 #endif 158 159 #endif 160