1296341Sdelphij// Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. 2110010Smarkm// 3110010Smarkm// This file is part of GCC. 4160819Ssimon// 5110010Smarkm// GCC is free software; you can redistribute it and/or modify 6110010Smarkm// it under the terms of the GNU General Public License as published by 7110010Smarkm// the Free Software Foundation; either version 2, or (at your option) 8110010Smarkm// any later version. 9110010Smarkm 10110010Smarkm// GCC is distributed in the hope that it will be useful, 11110010Smarkm// but WITHOUT ANY WARRANTY; without even the implied warranty of 12110010Smarkm// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13110010Smarkm// GNU General Public License for more details. 14110010Smarkm 15110010Smarkm// You should have received a copy of the GNU General Public License 16110010Smarkm// along with GCC; see the file COPYING. If not, write to 17110010Smarkm// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 18110010Smarkm// Boston, MA 02110-1301, USA. 19110010Smarkm 20215698Ssimon// As a special exception, you may use this file as part of a free software 21215698Ssimon// library without restriction. Specifically, if other files instantiate 22215698Ssimon// templates or use macros or inline functions from this file, or you compile 23215698Ssimon// this file and link it with other files to produce an executable, this 24215698Ssimon// file does not by itself cause the resulting executable to be covered by 25110010Smarkm// the GNU General Public License. This exception does not however 26110010Smarkm// invalidate any other reasons why the executable file might be covered by 27110010Smarkm// the GNU General Public License. 28110010Smarkm 29110010Smarkm// Written by Mark Mitchell, CodeSourcery LLC, <mark@codesourcery.com> 30110010Smarkm// Thread support written by Jason Merrill, Red Hat Inc. <jason@redhat.com> 31110010Smarkm 32110010Smarkm#include <bits/c++config.h> 33110010Smarkm#include <cxxabi.h> 34110010Smarkm#include <exception> 35110010Smarkm#include <new> 36110010Smarkm#include <ext/atomicity.h> 37110010Smarkm#include <ext/concurrence.h> 38110010Smarkm 39110010Smarkm// The IA64/generic ABI uses the first byte of the guard variable. 40110010Smarkm// The ARM EABI uses the least significant bit. 41279264Sdelphij 42279264Sdelphij// Thread-safe static local initialization support. 43110010Smarkm#ifdef __GTHREADS 44110010Smarkmnamespace 45215698Ssimon{ 46215698Ssimon // A single mutex controlling all static initializations. 47215698Ssimon static __gnu_cxx::__recursive_mutex* static_mutex; 48215698Ssimon 49160819Ssimon typedef char fake_recursive_mutex[sizeof(__gnu_cxx::__recursive_mutex)] 50215698Ssimon __attribute__ ((aligned(__alignof__(__gnu_cxx::__recursive_mutex)))); 51160819Ssimon fake_recursive_mutex fake_mutex; 52160819Ssimon 53279264Sdelphij static void init() 54279264Sdelphij { static_mutex = new (&fake_mutex) __gnu_cxx::__recursive_mutex(); } 55279264Sdelphij 56110010Smarkm __gnu_cxx::__recursive_mutex& 57279264Sdelphij get_static_mutex() 58279264Sdelphij { 59279264Sdelphij static __gthread_once_t once = __GTHREAD_ONCE_INIT; 60279264Sdelphij __gthread_once(&once, init); 61279264Sdelphij return *static_mutex; 62279264Sdelphij } 63215698Ssimon} 64279264Sdelphij 65279264Sdelphij#ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE 66279264Sdelphijinline bool 67279264Sdelphij__test_and_acquire (__cxxabiv1::__guard *g) 68279264Sdelphij{ 69215698Ssimon bool b = _GLIBCXX_GUARD_TEST (g); 70279264Sdelphij _GLIBCXX_READ_MEM_BARRIER; 71110010Smarkm return b; 72110010Smarkm} 73110010Smarkm#define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __test_and_acquire (G) 74110010Smarkm#endif 75110010Smarkm 76110010Smarkm#ifndef _GLIBCXX_GUARD_SET_AND_RELEASE 77110010Smarkminline void 78110010Smarkm__set_and_release (__cxxabiv1::__guard *g) 79110010Smarkm{ 80110010Smarkm _GLIBCXX_WRITE_MEM_BARRIER; 81110010Smarkm _GLIBCXX_GUARD_SET (g); 82110010Smarkm} 83110010Smarkm#define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __set_and_release (G) 84110010Smarkm#endif 85110010Smarkm 86110010Smarkm#else /* !__GTHREADS */ 87110010Smarkm 88110010Smarkm#undef _GLIBCXX_GUARD_TEST_AND_ACQUIRE 89110010Smarkm#undef _GLIBCXX_GUARD_SET_AND_RELEASE 90110010Smarkm#define _GLIBCXX_GUARD_SET_AND_RELEASE(G) _GLIBCXX_GUARD_SET (G) 91110010Smarkm 92110010Smarkm#endif /* __GTHREADS */ 93110010Smarkm 94110010Smarkmnamespace __gnu_cxx 95110010Smarkm{ 96110010Smarkm // 6.7[stmt.dcl]/4: If control re-enters the declaration (recursively) 97110010Smarkm // while the object is being initialized, the behavior is undefined. 98110010Smarkm 99110010Smarkm // Since we already have a library function to handle locking, we might 100110010Smarkm // as well check for this situation and throw an exception. 101110010Smarkm // We use the second byte of the guard variable to remember that we're 102110010Smarkm // in the middle of an initialization. 103110010Smarkm class recursive_init_error: public std::exception 104110010Smarkm { 105110010Smarkm public: 106110010Smarkm recursive_init_error() throw() { } 107110010Smarkm virtual ~recursive_init_error() throw (); 108110010Smarkm }; 109110010Smarkm 110110010Smarkm recursive_init_error::~recursive_init_error() throw() { } 111110010Smarkm} 112110010Smarkm 113110010Smarkmnamespace __cxxabiv1 114110010Smarkm{ 115110010Smarkm static inline int 116110010Smarkm recursion_push (__guard* g) 117110010Smarkm { return ((char *)g)[1]++; } 118110010Smarkm 119110010Smarkm static inline void 120110010Smarkm recursion_pop (__guard* g) 121110010Smarkm { --((char *)g)[1]; } 122110010Smarkm 123110010Smarkm static int 124110010Smarkm acquire (__guard *g) 125110010Smarkm { 126110010Smarkm if (_GLIBCXX_GUARD_TEST (g)) 127110010Smarkm return 0; 128110010Smarkm 129110010Smarkm if (recursion_push (g)) 130110010Smarkm { 131110010Smarkm#ifdef __EXCEPTIONS 132110010Smarkm throw __gnu_cxx::recursive_init_error(); 133160819Ssimon#else 134110010Smarkm // Use __builtin_trap so we don't require abort(). 135110010Smarkm __builtin_trap (); 136296341Sdelphij#endif 137215698Ssimon } 138215698Ssimon return 1; 139215698Ssimon } 140215698Ssimon 141110010Smarkm extern "C" 142110010Smarkm int __cxa_guard_acquire (__guard *g) 143110010Smarkm { 144110010Smarkm#ifdef __GTHREADS 145110010Smarkm // If the target can reorder loads, we need to insert a read memory 146110010Smarkm // barrier so that accesses to the guarded variable happen after the 147215698Ssimon // guard test. 148110010Smarkm if (_GLIBCXX_GUARD_TEST_AND_ACQUIRE (g)) 149110010Smarkm return 0; 150110010Smarkm 151110010Smarkm if (__gthread_active_p ()) 152110010Smarkm { 153110010Smarkm // Simple wrapper for exception safety. 154110010Smarkm struct mutex_wrapper 155110010Smarkm { 156110010Smarkm bool unlock; 157110010Smarkm mutex_wrapper() : unlock(true) 158110010Smarkm { get_static_mutex().lock(); } 159110010Smarkm 160110010Smarkm ~mutex_wrapper() 161110010Smarkm { 162110010Smarkm if (unlock) 163110010Smarkm static_mutex->unlock(); 164110010Smarkm } 165110010Smarkm }; 166110010Smarkm 167110010Smarkm mutex_wrapper mw; 168110010Smarkm if (acquire (g)) 169110010Smarkm { 170110010Smarkm mw.unlock = false; 171110010Smarkm return 1; 172110010Smarkm } 173110010Smarkm 174110010Smarkm return 0; 175110010Smarkm } 176110010Smarkm#endif 177110010Smarkm 178110010Smarkm return acquire (g); 179110010Smarkm } 180110010Smarkm 181110010Smarkm extern "C" 182110010Smarkm void __cxa_guard_abort (__guard *g) 183110010Smarkm { 184160819Ssimon recursion_pop (g); 185160819Ssimon#ifdef __GTHREADS 186110010Smarkm if (__gthread_active_p ()) 187110010Smarkm static_mutex->unlock(); 188110010Smarkm#endif 189110010Smarkm } 190110010Smarkm 191110010Smarkm extern "C" 192110010Smarkm void __cxa_guard_release (__guard *g) 193110010Smarkm { 194110010Smarkm recursion_pop (g); 195110010Smarkm _GLIBCXX_GUARD_SET_AND_RELEASE (g); 196110010Smarkm#ifdef __GTHREADS 197110010Smarkm if (__gthread_active_p ()) 198160819Ssimon static_mutex->unlock(); 199110010Smarkm#endif 200110010Smarkm } 201110010Smarkm} 202160819Ssimon