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