1// Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. 2// 3// This file is part of GCC. 4// 5// GCC is free software; you can redistribute it and/or modify 6// it under the terms of the GNU General Public License as published by 7// the Free Software Foundation; either version 2, or (at your option) 8// any later version. 9 10// GCC is distributed in the hope that it will be useful, 11// but WITHOUT ANY WARRANTY; without even the implied warranty of 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13// GNU General Public License for more details. 14 15// You should have received a copy of the GNU General Public License 16// along with GCC; see the file COPYING. If not, write to 17// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 18// Boston, MA 02110-1301, USA. 19 20// As a special exception, you may use this file as part of a free software 21// library without restriction. Specifically, if other files instantiate 22// templates or use macros or inline functions from this file, or you compile 23// this file and link it with other files to produce an executable, this 24// file does not by itself cause the resulting executable to be covered by 25// the GNU General Public License. This exception does not however 26// invalidate any other reasons why the executable file might be covered by 27// the GNU General Public License. 28 29// Written by Mark Mitchell, CodeSourcery LLC, <mark@codesourcery.com> 30// Thread support written by Jason Merrill, Red Hat Inc. <jason@redhat.com> 31 32#include <bits/c++config.h> 33#include <cxxabi.h> 34#include <exception> 35#include <new> 36#include <ext/atomicity.h> 37#include <ext/concurrence.h> 38 39// The IA64/generic ABI uses the first byte of the guard variable. 40// The ARM EABI uses the least significant bit. 41 42// Thread-safe static local initialization support. 43#ifdef __GTHREADS 44namespace 45{ 46 // A single mutex controlling all static initializations. 47 static __gnu_cxx::__recursive_mutex* static_mutex; 48 49 typedef char fake_recursive_mutex[sizeof(__gnu_cxx::__recursive_mutex)] 50 __attribute__ ((aligned(__alignof__(__gnu_cxx::__recursive_mutex)))); 51 fake_recursive_mutex fake_mutex; 52 53 static void init() 54 { static_mutex = new (&fake_mutex) __gnu_cxx::__recursive_mutex(); } 55 56 __gnu_cxx::__recursive_mutex& 57 get_static_mutex() 58 { 59 static __gthread_once_t once = __GTHREAD_ONCE_INIT; 60 __gthread_once(&once, init); 61 return *static_mutex; 62 } 63} 64 65#ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE 66inline bool 67__test_and_acquire (__cxxabiv1::__guard *g) 68{ 69 bool b = _GLIBCXX_GUARD_TEST (g); 70 _GLIBCXX_READ_MEM_BARRIER; 71 return b; 72} 73#define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __test_and_acquire (G) 74#endif 75 76#ifndef _GLIBCXX_GUARD_SET_AND_RELEASE 77inline void 78__set_and_release (__cxxabiv1::__guard *g) 79{ 80 _GLIBCXX_WRITE_MEM_BARRIER; 81 _GLIBCXX_GUARD_SET (g); 82} 83#define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __set_and_release (G) 84#endif 85 86#else /* !__GTHREADS */ 87 88#undef _GLIBCXX_GUARD_TEST_AND_ACQUIRE 89#undef _GLIBCXX_GUARD_SET_AND_RELEASE 90#define _GLIBCXX_GUARD_SET_AND_RELEASE(G) _GLIBCXX_GUARD_SET (G) 91 92#endif /* __GTHREADS */ 93 94namespace __gnu_cxx 95{ 96 // 6.7[stmt.dcl]/4: If control re-enters the declaration (recursively) 97 // while the object is being initialized, the behavior is undefined. 98 99 // Since we already have a library function to handle locking, we might 100 // as well check for this situation and throw an exception. 101 // We use the second byte of the guard variable to remember that we're 102 // in the middle of an initialization. 103 class recursive_init_error: public std::exception 104 { 105 public: 106 recursive_init_error() throw() { } 107 virtual ~recursive_init_error() throw (); 108 }; 109 110 recursive_init_error::~recursive_init_error() throw() { } 111} 112 113namespace __cxxabiv1 114{ 115 static inline int 116 recursion_push (__guard* g) 117 { return ((char *)g)[1]++; } 118 119 static inline void 120 recursion_pop (__guard* g) 121 { --((char *)g)[1]; } 122 123 static int 124 acquire (__guard *g) 125 { 126 if (_GLIBCXX_GUARD_TEST (g)) 127 return 0; 128 129 if (recursion_push (g)) 130 { 131#ifdef __EXCEPTIONS 132 throw __gnu_cxx::recursive_init_error(); 133#else 134 // Use __builtin_trap so we don't require abort(). 135 __builtin_trap (); 136#endif 137 } 138 return 1; 139 } 140 141 extern "C" 142 int __cxa_guard_acquire (__guard *g) 143 { 144#ifdef __GTHREADS 145 // If the target can reorder loads, we need to insert a read memory 146 // barrier so that accesses to the guarded variable happen after the 147 // guard test. 148 if (_GLIBCXX_GUARD_TEST_AND_ACQUIRE (g)) 149 return 0; 150 151 if (__gthread_active_p ()) 152 { 153 // Simple wrapper for exception safety. 154 struct mutex_wrapper 155 { 156 bool unlock; 157 mutex_wrapper() : unlock(true) 158 { get_static_mutex().lock(); } 159 160 ~mutex_wrapper() 161 { 162 if (unlock) 163 static_mutex->unlock(); 164 } 165 }; 166 167 mutex_wrapper mw; 168 if (acquire (g)) 169 { 170 mw.unlock = false; 171 return 1; 172 } 173 174 return 0; 175 } 176#endif 177 178 return acquire (g); 179 } 180 181 extern "C" 182 void __cxa_guard_abort (__guard *g) 183 { 184 recursion_pop (g); 185#ifdef __GTHREADS 186 if (__gthread_active_p ()) 187 static_mutex->unlock(); 188#endif 189 } 190 191 extern "C" 192 void __cxa_guard_release (__guard *g) 193 { 194 recursion_pop (g); 195 _GLIBCXX_GUARD_SET_AND_RELEASE (g); 196#ifdef __GTHREADS 197 if (__gthread_active_p ()) 198 static_mutex->unlock(); 199#endif 200 } 201} 202