1// -*- C++ -*- Manage the thread-local exception globals. 2// Copyright (C) 2001-2015 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 33using std::free; 34using std::malloc; 35#else 36// In a freestanding environment, these functions may not be 37// available -- but for now, we assume that they are. 38extern "C" void *malloc (std::size_t); 39extern "C" void free(void *); 40#endif 41 42using namespace __cxxabiv1; 43 44#if _GLIBCXX_HAVE_TLS 45 46namespace 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 56extern "C" __cxa_eh_globals* 57__cxxabiv1::__cxa_get_globals_fast() _GLIBCXX_NOTHROW 58{ return get_global(); } 59 60extern "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. 68static __cxa_eh_globals eh_globals; 69 70#if __GTHREADS 71 72static void 73eh_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 90struct __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 109static __eh_globals_init init; 110 111extern "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 122extern "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 149extern "C" __cxa_eh_globals* 150__cxxabiv1::__cxa_get_globals_fast() _GLIBCXX_NOTHROW 151{ return &eh_globals; } 152 153extern "C" __cxa_eh_globals* 154__cxxabiv1::__cxa_get_globals() _GLIBCXX_NOTHROW 155{ return &eh_globals; } 156 157#endif 158 159#endif 160