1169691Skan// Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. 2117397Skan// 3117397Skan// This file is part of GCC. 4117397Skan// 5117397Skan// GCC is free software; you can redistribute it and/or modify 6117397Skan// it under the terms of the GNU General Public License as published by 7117397Skan// the Free Software Foundation; either version 2, or (at your option) 8117397Skan// any later version. 9117397Skan 10117397Skan// GCC is distributed in the hope that it will be useful, 11117397Skan// but WITHOUT ANY WARRANTY; without even the implied warranty of 12117397Skan// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13117397Skan// GNU General Public License for more details. 14117397Skan 15117397Skan// You should have received a copy of the GNU General Public License 16117397Skan// along with GCC; see the file COPYING. If not, write to 17169691Skan// the Free Software Foundation, 51 Franklin Street, Fifth Floor, 18169691Skan// Boston, MA 02110-1301, USA. 19117397Skan 20117397Skan// As a special exception, you may use this file as part of a free software 21117397Skan// library without restriction. Specifically, if other files instantiate 22117397Skan// templates or use macros or inline functions from this file, or you compile 23117397Skan// this file and link it with other files to produce an executable, this 24117397Skan// file does not by itself cause the resulting executable to be covered by 25117397Skan// the GNU General Public License. This exception does not however 26117397Skan// invalidate any other reasons why the executable file might be covered by 27117397Skan// the GNU General Public License. 28117397Skan 29117397Skan// Written by Mark Mitchell, CodeSourcery LLC, <mark@codesourcery.com> 30169691Skan// Thread support written by Jason Merrill, Red Hat Inc. <jason@redhat.com> 31117397Skan 32169691Skan#include <bits/c++config.h> 33117397Skan#include <cxxabi.h> 34169691Skan#include <exception> 35169691Skan#include <new> 36169691Skan#include <ext/atomicity.h> 37169691Skan#include <ext/concurrence.h> 38117397Skan 39169691Skan// The IA64/generic ABI uses the first byte of the guard variable. 40169691Skan// The ARM EABI uses the least significant bit. 41169691Skan 42169691Skan// Thread-safe static local initialization support. 43169691Skan#ifdef __GTHREADS 44169691Skannamespace 45169691Skan{ 46169691Skan // A single mutex controlling all static initializations. 47169691Skan static __gnu_cxx::__recursive_mutex* static_mutex; 48169691Skan 49169691Skan typedef char fake_recursive_mutex[sizeof(__gnu_cxx::__recursive_mutex)] 50169691Skan __attribute__ ((aligned(__alignof__(__gnu_cxx::__recursive_mutex)))); 51169691Skan fake_recursive_mutex fake_mutex; 52169691Skan 53169691Skan static void init() 54169691Skan { static_mutex = new (&fake_mutex) __gnu_cxx::__recursive_mutex(); } 55169691Skan 56169691Skan __gnu_cxx::__recursive_mutex& 57169691Skan get_static_mutex() 58169691Skan { 59169691Skan static __gthread_once_t once = __GTHREAD_ONCE_INIT; 60169691Skan __gthread_once(&once, init); 61169691Skan return *static_mutex; 62169691Skan } 63169691Skan} 64169691Skan 65169691Skan#ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE 66169691Skaninline bool 67169691Skan__test_and_acquire (__cxxabiv1::__guard *g) 68169691Skan{ 69169691Skan bool b = _GLIBCXX_GUARD_TEST (g); 70169691Skan _GLIBCXX_READ_MEM_BARRIER; 71169691Skan return b; 72169691Skan} 73169691Skan#define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __test_and_acquire (G) 74169691Skan#endif 75169691Skan 76169691Skan#ifndef _GLIBCXX_GUARD_SET_AND_RELEASE 77169691Skaninline void 78169691Skan__set_and_release (__cxxabiv1::__guard *g) 79169691Skan{ 80169691Skan _GLIBCXX_WRITE_MEM_BARRIER; 81169691Skan _GLIBCXX_GUARD_SET (g); 82169691Skan} 83169691Skan#define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __set_and_release (G) 84169691Skan#endif 85169691Skan 86169691Skan#else /* !__GTHREADS */ 87169691Skan 88169691Skan#undef _GLIBCXX_GUARD_TEST_AND_ACQUIRE 89169691Skan#undef _GLIBCXX_GUARD_SET_AND_RELEASE 90169691Skan#define _GLIBCXX_GUARD_SET_AND_RELEASE(G) _GLIBCXX_GUARD_SET (G) 91169691Skan 92169691Skan#endif /* __GTHREADS */ 93169691Skan 94169691Skannamespace __gnu_cxx 95169691Skan{ 96169691Skan // 6.7[stmt.dcl]/4: If control re-enters the declaration (recursively) 97169691Skan // while the object is being initialized, the behavior is undefined. 98169691Skan 99169691Skan // Since we already have a library function to handle locking, we might 100169691Skan // as well check for this situation and throw an exception. 101169691Skan // We use the second byte of the guard variable to remember that we're 102169691Skan // in the middle of an initialization. 103169691Skan class recursive_init_error: public std::exception 104169691Skan { 105169691Skan public: 106169691Skan recursive_init_error() throw() { } 107169691Skan virtual ~recursive_init_error() throw (); 108169691Skan }; 109169691Skan 110169691Skan recursive_init_error::~recursive_init_error() throw() { } 111169691Skan} 112169691Skan 113117397Skannamespace __cxxabiv1 114117397Skan{ 115169691Skan static inline int 116169691Skan recursion_push (__guard* g) 117169691Skan { return ((char *)g)[1]++; } 118169691Skan 119169691Skan static inline void 120169691Skan recursion_pop (__guard* g) 121169691Skan { --((char *)g)[1]; } 122169691Skan 123169691Skan static int 124169691Skan acquire (__guard *g) 125169691Skan { 126169691Skan if (_GLIBCXX_GUARD_TEST (g)) 127169691Skan return 0; 128169691Skan 129169691Skan if (recursion_push (g)) 130169691Skan { 131169691Skan#ifdef __EXCEPTIONS 132169691Skan throw __gnu_cxx::recursive_init_error(); 133169691Skan#else 134169691Skan // Use __builtin_trap so we don't require abort(). 135169691Skan __builtin_trap (); 136169691Skan#endif 137169691Skan } 138169691Skan return 1; 139169691Skan } 140169691Skan 141117397Skan extern "C" 142117397Skan int __cxa_guard_acquire (__guard *g) 143117397Skan { 144169691Skan#ifdef __GTHREADS 145169691Skan // If the target can reorder loads, we need to insert a read memory 146169691Skan // barrier so that accesses to the guarded variable happen after the 147169691Skan // guard test. 148169691Skan if (_GLIBCXX_GUARD_TEST_AND_ACQUIRE (g)) 149169691Skan return 0; 150169691Skan 151169691Skan if (__gthread_active_p ()) 152169691Skan { 153169691Skan // Simple wrapper for exception safety. 154169691Skan struct mutex_wrapper 155169691Skan { 156169691Skan bool unlock; 157169691Skan mutex_wrapper() : unlock(true) 158169691Skan { get_static_mutex().lock(); } 159169691Skan 160169691Skan ~mutex_wrapper() 161169691Skan { 162169691Skan if (unlock) 163169691Skan static_mutex->unlock(); 164169691Skan } 165169691Skan }; 166169691Skan 167169691Skan mutex_wrapper mw; 168169691Skan if (acquire (g)) 169169691Skan { 170169691Skan mw.unlock = false; 171169691Skan return 1; 172169691Skan } 173169691Skan 174169691Skan return 0; 175169691Skan } 176169691Skan#endif 177169691Skan 178169691Skan return acquire (g); 179117397Skan } 180117397Skan 181117397Skan extern "C" 182169691Skan void __cxa_guard_abort (__guard *g) 183117397Skan { 184169691Skan recursion_pop (g); 185169691Skan#ifdef __GTHREADS 186169691Skan if (__gthread_active_p ()) 187169691Skan static_mutex->unlock(); 188169691Skan#endif 189117397Skan } 190117397Skan 191117397Skan extern "C" 192169691Skan void __cxa_guard_release (__guard *g) 193117397Skan { 194169691Skan recursion_pop (g); 195169691Skan _GLIBCXX_GUARD_SET_AND_RELEASE (g); 196169691Skan#ifdef __GTHREADS 197169691Skan if (__gthread_active_p ()) 198169691Skan static_mutex->unlock(); 199169691Skan#endif 200117397Skan } 201117397Skan} 202