197403Sobrien// -*- C++ -*- Manage the thread-local exception globals. 2169691Skan// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 3169691Skan// Free Software Foundation, Inc. 497403Sobrien// 5132720Skan// This file is part of GCC. 697403Sobrien// 7132720Skan// GCC is free software; you can redistribute it and/or modify 897403Sobrien// it under the terms of the GNU General Public License as published by 997403Sobrien// the Free Software Foundation; either version 2, or (at your option) 1097403Sobrien// any later version. 1197403Sobrien// 12132720Skan// GCC is distributed in the hope that it will be useful, 1397403Sobrien// but WITHOUT ANY WARRANTY; without even the implied warranty of 1497403Sobrien// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1597403Sobrien// GNU General Public License for more details. 1697403Sobrien// 1797403Sobrien// You should have received a copy of the GNU General Public License 18132720Skan// along with GCC; see the file COPYING. If not, write to 19169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 20169691Skan// Boston, MA 02110-1301, USA. 2197403Sobrien 2297403Sobrien// As a special exception, you may use this file as part of a free software 2397403Sobrien// library without restriction. Specifically, if other files instantiate 2497403Sobrien// templates or use macros or inline functions from this file, or you compile 2597403Sobrien// this file and link it with other files to produce an executable, this 2697403Sobrien// file does not by itself cause the resulting executable to be covered by 2797403Sobrien// the GNU General Public License. This exception does not however 2897403Sobrien// invalidate any other reasons why the executable file might be covered by 2997403Sobrien// the GNU General Public License. 3097403Sobrien 31169691Skan#include <bits/c++config.h> 3297403Sobrien#include <exception> 3397403Sobrien#include <cstdlib> 34169691Skan#include "cxxabi.h" 3597403Sobrien#include "unwind-cxx.h" 3697403Sobrien#include "bits/gthr.h" 3797403Sobrien 38169691Skan#if _GLIBCXX_HOSTED 39169691Skanusing std::free; 40169691Skanusing std::malloc; 41169691Skan#else 42169691Skan// In a freestanding environment, these functions may not be 43169691Skan// available -- but for now, we assume that they are. 44169691Skanextern "C" void *malloc (std::size_t); 45169691Skanextern "C" void free(void *); 46169691Skan#endif 47169691Skan 4897403Sobrienusing namespace __cxxabiv1; 4997403Sobrien 50169691Skan#if _GLIBCXX_HAVE_TLS 5197403Sobrien 52169691Skannamespace 53169691Skan{ 54169691Skan abi::__cxa_eh_globals* 55169691Skan get_global() throw() 56169691Skan { 57169691Skan static __thread abi::__cxa_eh_globals global; 58169691Skan return &global; 59169691Skan } 60169691Skan} // anonymous namespace 61169691Skan 62169691Skanextern "C" __cxa_eh_globals* 63169691Skan__cxxabiv1::__cxa_get_globals_fast() throw() 64169691Skan{ return get_global(); } 65169691Skan 66169691Skanextern "C" __cxa_eh_globals* 67169691Skan__cxxabiv1::__cxa_get_globals() throw() 68169691Skan{ return get_global(); } 69169691Skan 70169691Skan 71169691Skan#else 72169691Skan 7397403Sobrien// Single-threaded fallback buffer. 74169691Skanstatic __cxa_eh_globals eh_globals; 7597403Sobrien 7697403Sobrien#if __GTHREADS 7797403Sobrien 7897403Sobrienstatic void 79169691Skaneh_globals_dtor(void* ptr) 8097403Sobrien{ 8197403Sobrien if (ptr) 82146897Skan { 83169691Skan __cxa_eh_globals* g = reinterpret_cast<__cxa_eh_globals*>(ptr); 84169691Skan __cxa_exception* exn = g->caughtExceptions; 85169691Skan __cxa_exception* next; 86146897Skan while (exn) 87146897Skan { 88146897Skan next = exn->nextException; 89169691Skan _Unwind_DeleteException(&exn->unwindHeader); 90146897Skan exn = next; 91146897Skan } 92169691Skan free(ptr); 93146897Skan } 9497403Sobrien} 9597403Sobrien 96169691Skanstruct __eh_globals_init 9797403Sobrien{ 98169691Skan __gthread_key_t _M_key; 99169691Skan bool _M_init; 10097403Sobrien 101169691Skan __eh_globals_init() : _M_init(false) 102169691Skan { 103169691Skan if (__gthread_active_p()) 104169691Skan _M_init = __gthread_key_create(&_M_key, eh_globals_dtor) == 0; 105169691Skan } 106169691Skan 107169691Skan ~__eh_globals_init() 108169691Skan { 109169691Skan if (_M_init) 110169691Skan __gthread_key_delete(_M_key); 111169691Skan _M_init = false; 112169691Skan } 113169691Skan}; 114169691Skan 115169691Skanstatic __eh_globals_init init; 116169691Skan 117169691Skanextern "C" __cxa_eh_globals* 118169691Skan__cxxabiv1::__cxa_get_globals_fast() throw() 11997403Sobrien{ 120169691Skan __cxa_eh_globals* g; 121169691Skan if (init._M_init) 122169691Skan g = static_cast<__cxa_eh_globals*>(__gthread_getspecific(init._M_key)); 123169691Skan else 124169691Skan g = &eh_globals; 125169691Skan return g; 12697403Sobrien} 12797403Sobrien 128169691Skanextern "C" __cxa_eh_globals* 129169691Skan__cxxabiv1::__cxa_get_globals() throw() 13097403Sobrien{ 131169691Skan __cxa_eh_globals* g; 132169691Skan if (init._M_init) 133169691Skan { 134169691Skan g = static_cast<__cxa_eh_globals*>(__gthread_getspecific(init._M_key)); 135169691Skan if (!g) 136169691Skan { 137169691Skan void* v = malloc(sizeof(__cxa_eh_globals)); 138169691Skan if (v == 0 || __gthread_setspecific(init._M_key, v) != 0) 139169691Skan std::terminate(); 140169691Skan g = static_cast<__cxa_eh_globals*>(v); 141169691Skan g->caughtExceptions = 0; 142169691Skan g->uncaughtExceptions = 0; 143169691Skan } 144169691Skan } 14597403Sobrien else 146169691Skan g = &eh_globals; 147169691Skan return g; 14897403Sobrien} 14997403Sobrien 150169691Skan#else 15197403Sobrien 152169691Skanextern "C" __cxa_eh_globals* 153169691Skan__cxxabiv1::__cxa_get_globals_fast() throw() 154169691Skan{ return &eh_globals; } 15597403Sobrien 156169691Skanextern "C" __cxa_eh_globals* 157169691Skan__cxxabiv1::__cxa_get_globals() throw() 158169691Skan{ return &eh_globals; } 15997403Sobrien 160169691Skan#endif 16197403Sobrien 16297403Sobrien#endif 163