OSDN Git Service

2008-08-31 Aaron W. LaFramboise <aaronavay62@aaronwl.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / libsupc++ / guard.cc
1 // Copyright (C) 2002, 2004, 2006, 2008 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 #if defined(__GTHREADS) && defined(__GTHREAD_HAS_COND) \
39     && defined(_GLIBCXX_ATOMIC_BUILTINS_4) && defined(_GLIBCXX_HAVE_LINUX_FUTEX)
40 # include <climits>
41 # include <syscall.h>
42 # define _GLIBCXX_USE_FUTEX
43 # define _GLIBCXX_FUTEX_WAIT 0
44 # define _GLIBCXX_FUTEX_WAKE 1
45 #endif
46
47 // The IA64/generic ABI uses the first byte of the guard variable.
48 // The ARM EABI uses the least significant bit.
49
50 // Thread-safe static local initialization support.
51 #ifdef __GTHREADS
52 # ifndef _GLIBCXX_USE_FUTEX
53 namespace
54 {
55   // A single mutex controlling all static initializations.
56   static __gnu_cxx::__recursive_mutex* static_mutex;  
57
58   typedef char fake_recursive_mutex[sizeof(__gnu_cxx::__recursive_mutex)]
59   __attribute__ ((aligned(__alignof__(__gnu_cxx::__recursive_mutex))));
60   fake_recursive_mutex fake_mutex;
61
62   static void init()
63   { static_mutex =  new (&fake_mutex) __gnu_cxx::__recursive_mutex(); }
64
65   __gnu_cxx::__recursive_mutex&
66   get_static_mutex()
67   {
68     static __gthread_once_t once = __GTHREAD_ONCE_INIT;
69     __gthread_once(&once, init);
70     return *static_mutex;
71   }
72
73   // Simple wrapper for exception safety.
74   struct mutex_wrapper
75   {
76     bool unlock;
77     mutex_wrapper() : unlock(true)
78     { get_static_mutex().lock(); }
79
80     ~mutex_wrapper()
81     {
82       if (unlock)
83         static_mutex->unlock();
84     }
85   };
86 }
87 # endif
88
89 # if defined(__GTHREAD_HAS_COND) && !defined(_GLIBCXX_USE_FUTEX)
90 namespace
91 {
92   // A single conditional variable controlling all static initializations.
93   static __gnu_cxx::__cond* static_cond;  
94
95   // using a fake type to avoid initializing a static class.
96   typedef char fake_cond_t[sizeof(__gnu_cxx::__cond)]
97   __attribute__ ((aligned(__alignof__(__gnu_cxx::__cond))));
98   fake_cond_t fake_cond;
99
100   static void init_static_cond()
101   { static_cond =  new (&fake_cond) __gnu_cxx::__cond(); }
102
103   __gnu_cxx::__cond&
104   get_static_cond()
105   {
106     static __gthread_once_t once = __GTHREAD_ONCE_INIT;
107     __gthread_once(&once, init_static_cond);
108     return *static_cond;
109   }
110 }
111 # endif
112
113 # ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
114 inline bool
115 __test_and_acquire (__cxxabiv1::__guard *g)
116 {
117   bool b = _GLIBCXX_GUARD_TEST (g);
118   _GLIBCXX_READ_MEM_BARRIER;
119   return b;
120 }
121 #  define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __test_and_acquire (G)
122 # endif
123
124 # ifndef _GLIBCXX_GUARD_SET_AND_RELEASE
125 inline void
126 __set_and_release (__cxxabiv1::__guard *g)
127 {
128   _GLIBCXX_WRITE_MEM_BARRIER;
129   _GLIBCXX_GUARD_SET (g);
130 }
131 #  define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __set_and_release (G)
132 # endif
133
134 #else /* !__GTHREADS */
135
136 # undef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
137 # undef _GLIBCXX_GUARD_SET_AND_RELEASE
138 # define _GLIBCXX_GUARD_SET_AND_RELEASE(G) _GLIBCXX_GUARD_SET (G)
139
140 #endif /* __GTHREADS */
141
142 namespace __gnu_cxx
143 {
144   // 6.7[stmt.dcl]/4: If control re-enters the declaration (recursively)
145   // while the object is being initialized, the behavior is undefined.
146
147   // Since we already have a library function to handle locking, we might
148   // as well check for this situation and throw an exception.
149   // We use the second byte of the guard variable to remember that we're
150   // in the middle of an initialization.
151   class recursive_init_error: public std::exception
152   {
153   public:
154     recursive_init_error() throw() { }
155     virtual ~recursive_init_error() throw ();
156   };
157
158   recursive_init_error::~recursive_init_error() throw() { }
159 }
160
161 //
162 // Here are C++ run-time routines for guarded initiailization of static
163 // variables. There are 4 scenarios under which these routines are called:
164 //
165 //   1. Threads not supported (__GTHREADS not defined)
166 //   2. Threads are supported but not enabled at run-time.
167 //   3. Threads enabled at run-time but __gthreads_* are not fully POSIX.
168 //   4. Threads enabled at run-time and __gthreads_* support all POSIX threads
169 //      primitives we need here.
170 //
171 // The old code supported scenarios 1-3 but was broken since it used a global
172 // mutex for all threads and had the mutex locked during the whole duration of
173 // initlization of a guarded static variable. The following created a dead-lock
174 // with the old code.
175 //
176 //      Thread 1 acquires the global mutex.
177 //      Thread 1 starts initializing static variable.
178 //      Thread 1 creates thread 2 during initialization.
179 //      Thread 2 attempts to acuqire mutex to initialize another variable.
180 //      Thread 2 blocks since thread 1 is locking the mutex.
181 //      Thread 1 waits for result from thread 2 and also blocks. A deadlock.
182 //
183 // The new code here can handle this situation and thus is more robust. Howere,
184 // we need to use the POSIX thread conditional variable, which is not supported
185 // in all platforms, notably older versions of Microsoft Windows. The gthr*.h
186 // headers define a symbol __GTHREAD_HAS_COND for platforms that support POSIX
187 // like conditional variables. For platforms that do not support conditional
188 // variables, we need to fall back to the old code.
189
190 // If _GLIBCXX_USE_FUTEX, no global mutex or conditional variable is used,
191 // only atomic operations are used together with futex syscall.
192 // Valid values of the first integer in guard are:
193 // 0                              No thread encountered the guarded init
194 //                                yet or it has been aborted.
195 // _GLIBCXX_GUARD_BIT             The guarded static var has been successfully
196 //                                initialized.
197 // _GLIBCXX_GUARD_PENDING_BIT     The guarded static var is being initialized
198 //                                and no other thread is waiting for its
199 //                                initialization.
200 // (_GLIBCXX_GUARD_PENDING_BIT    The guarded static var is being initialized
201 //  | _GLIBCXX_GUARD_WAITING_BIT) and some other threads are waiting until
202 //                                it is initialized.
203
204 namespace __cxxabiv1 
205 {
206 #ifdef _GLIBCXX_USE_FUTEX
207   namespace
208   {
209     static inline int __guard_test_bit (const int __byte, const int __val)
210     {
211       union { int __i; char __c[sizeof (int)]; } __u = { 0 };
212       __u.__c[__byte] = __val;
213       return __u.__i;
214     }
215   }
216 #endif
217
218   static inline int
219   init_in_progress_flag(__guard* g)
220   { return ((char *)g)[1]; }
221
222   static inline void
223   set_init_in_progress_flag(__guard* g, int v)
224   { ((char *)g)[1] = v; }
225
226   static inline void
227   throw_recursive_init_exception()
228   {
229 #ifdef __EXCEPTIONS
230         throw __gnu_cxx::recursive_init_error();
231 #else
232         // Use __builtin_trap so we don't require abort().
233         __builtin_trap();
234 #endif
235   }
236
237   // acuire() is a helper function used to acquire guard if thread support is
238   // not compiled in or is compiled in but not enabled at run-time.
239   static int
240   acquire(__guard *g)
241   {
242     // Quit if the object is already initialized.
243     if (_GLIBCXX_GUARD_TEST(g))
244       return 0;
245
246     if (init_in_progress_flag(g))
247       throw_recursive_init_exception();
248
249     set_init_in_progress_flag(g, 1);
250     return 1;
251   }
252
253   extern "C"
254   int __cxa_guard_acquire (__guard *g) 
255   {
256 #ifdef __GTHREADS
257     // If the target can reorder loads, we need to insert a read memory
258     // barrier so that accesses to the guarded variable happen after the
259     // guard test.
260     if (_GLIBCXX_GUARD_TEST_AND_ACQUIRE (g))
261       return 0;
262
263 # ifdef _GLIBCXX_USE_FUTEX
264     // If __sync_* and futex syscall are supported, don't use any global
265     // mutex.
266     if (__gthread_active_p ())
267       {
268         int *gi = (int *) (void *) g;
269         const int guard_bit = _GLIBCXX_GUARD_BIT;
270         const int pending_bit = _GLIBCXX_GUARD_PENDING_BIT;
271         const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
272
273         while (1)
274           {
275             int old = __sync_val_compare_and_swap (gi, 0, pending_bit);
276             if (old == 0)
277               return 1; // This thread should do the initialization.
278
279             if (old == guard_bit)
280               return 0; // Already initialized.
281
282             if (old == pending_bit)
283               {
284                 int newv = old | waiting_bit;
285                 if (__sync_val_compare_and_swap (gi, old, newv) != old)
286                   continue;
287
288                 old = newv;
289               }
290
291             syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAIT, old, 0);
292           }
293       }
294 # else
295     if (__gthread_active_p ())
296       {
297         mutex_wrapper mw;
298
299         while (1)       // When this loop is executing, mutex is locked.
300           {
301 #  ifdef __GTHREAD_HAS_COND
302             // The static is already initialized.
303             if (_GLIBCXX_GUARD_TEST(g))
304               return 0; // The mutex will be unlocked via wrapper
305
306             if (init_in_progress_flag(g))
307               {
308                 // The guarded static is currently being initialized by
309                 // another thread, so we release mutex and wait for the
310                 // conditional variable. We will lock the mutex again after
311                 // this.
312                 get_static_cond().wait_recursive(&get_static_mutex());
313               }
314             else
315               {
316                 set_init_in_progress_flag(g, 1);
317                 return 1; // The mutex will be unlocked via wrapper.
318               }
319 #  else
320             // This provides compatibility with older systems not supporting
321             // POSIX like conditional variables.
322             if (acquire(g))
323               {
324                 mw.unlock = false;
325                 return 1; // The mutex still locked.
326               }
327             return 0; // The mutex will be unlocked via wrapper.
328 #  endif
329           }
330       }
331 # endif
332 #endif
333
334     return acquire (g);
335   }
336
337   extern "C"
338   void __cxa_guard_abort (__guard *g)
339   {
340 #ifdef _GLIBCXX_USE_FUTEX
341     // If __sync_* and futex syscall are supported, don't use any global
342     // mutex.
343     if (__gthread_active_p ())
344       {
345         int *gi = (int *) (void *) g;
346         const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
347         int old = __sync_lock_test_and_set (gi, 0);
348
349         if ((old & waiting_bit) != 0)
350           syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAKE, INT_MAX);
351         return;
352       }
353 #elif defined(__GTHREAD_HAS_COND)
354     if (__gthread_active_p())
355       { 
356         mutex_wrapper mw;
357
358         set_init_in_progress_flag(g, 0);
359
360         // If we abort, we still need to wake up all other threads waiting for
361         // the conditional variable.
362         get_static_cond().broadcast();
363         return;
364       } 
365 #endif
366
367     set_init_in_progress_flag(g, 0);
368 #if defined(__GTHREADS) && !defined(__GTHREAD_HAS_COND)
369     // This provides compatibility with older systems not supporting POSIX like
370     // conditional variables.
371     if (__gthread_active_p ())
372       static_mutex->unlock();
373 #endif
374   }
375
376   extern "C"
377   void __cxa_guard_release (__guard *g)
378   {
379 #ifdef _GLIBCXX_USE_FUTEX
380     // If __sync_* and futex syscall are supported, don't use any global
381     // mutex.
382     if (__gthread_active_p ())
383       {
384         int *gi = (int *) (void *) g;
385         const int guard_bit = _GLIBCXX_GUARD_BIT;
386         const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
387         int old = __sync_lock_test_and_set (gi, guard_bit);
388
389         if ((old & waiting_bit) != 0)
390           syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAKE, INT_MAX);
391         return;
392       }
393 #elif defined(__GTHREAD_HAS_COND)
394     if (__gthread_active_p())
395       {
396         mutex_wrapper mw;
397
398         set_init_in_progress_flag(g, 0);
399         _GLIBCXX_GUARD_SET_AND_RELEASE(g);
400
401         get_static_cond().broadcast();
402         return;
403       } 
404 #endif
405
406     set_init_in_progress_flag(g, 0);
407     _GLIBCXX_GUARD_SET_AND_RELEASE (g);
408
409 #if defined(__GTHREADS) && !defined(__GTHREAD_HAS_COND)
410     // This provides compatibility with older systems not supporting POSIX like
411     // conditional variables.
412     if (__gthread_active_p())
413       static_mutex->unlock();
414 #endif
415   }
416 }