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 44 namespace 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 66 inline 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 77 inline 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 94 namespace __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 113 namespace __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