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