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