Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4383 Serge 1
// Copyright (C) 2002, 2004, 2006, 2008, 2009, 2010, 2011, 2012
2
// Free Software Foundation, Inc.
3
//
4
// This file is part of GCC.
5
//
6
// GCC is free software; you can redistribute it and/or modify
7
// it under the terms of the GNU General Public License as published by
8
// the Free Software Foundation; either version 3, or (at your option)
9
// any later version.
10
 
11
// GCC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
// GNU General Public License for more details.
15
 
16
// Under Section 7 of GPL version 3, you are granted additional
17
// permissions described in the GCC Runtime Library Exception, version
18
// 3.1, as published by the Free Software Foundation.
19
 
20
// You should have received a copy of the GNU General Public License and
21
// a copy of the GCC Runtime Library Exception along with this program;
22
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23
// .
24
 
25
// Written by Mark Mitchell, CodeSourcery LLC, 
26
// Thread support written by Jason Merrill, Red Hat Inc. 
27
 
28
#include 
29
#include 
30
#include 
31
#include 
32
#include 
33
#include 
34
#if defined(__GTHREADS) && defined(__GTHREAD_HAS_COND) \
35
  && (ATOMIC_INT_LOCK_FREE > 1) && defined(_GLIBCXX_HAVE_LINUX_FUTEX)
36
# include 
37
# include 
38
# include 
39
# define _GLIBCXX_USE_FUTEX
40
# define _GLIBCXX_FUTEX_WAIT 0
41
# define _GLIBCXX_FUTEX_WAKE 1
42
#endif
43
 
44
// The IA64/generic ABI uses the first byte of the guard variable.
45
// The ARM EABI uses the least significant bit.
46
 
47
// Thread-safe static local initialization support.
48
#ifdef __GTHREADS
49
# ifndef _GLIBCXX_USE_FUTEX
50
namespace
51
{
52
  // A single mutex controlling all static initializations.
53
  static __gnu_cxx::__recursive_mutex* static_mutex;
54
 
55
  typedef char fake_recursive_mutex[sizeof(__gnu_cxx::__recursive_mutex)]
56
  __attribute__ ((aligned(__alignof__(__gnu_cxx::__recursive_mutex))));
57
  fake_recursive_mutex fake_mutex;
58
 
59
  static void init()
60
  { static_mutex =  new (&fake_mutex) __gnu_cxx::__recursive_mutex(); }
61
 
62
  __gnu_cxx::__recursive_mutex&
63
  get_static_mutex()
64
  {
65
    static __gthread_once_t once = __GTHREAD_ONCE_INIT;
66
    __gthread_once(&once, init);
67
    return *static_mutex;
68
  }
69
 
70
  // Simple wrapper for exception safety.
71
  struct mutex_wrapper
72
  {
73
    bool unlock;
74
    mutex_wrapper() : unlock(true)
75
    { get_static_mutex().lock(); }
76
 
77
    ~mutex_wrapper()
78
    {
79
      if (unlock)
80
	static_mutex->unlock();
81
    }
82
  };
83
}
84
# endif
85
 
86
# if defined(__GTHREAD_HAS_COND) && !defined(_GLIBCXX_USE_FUTEX)
87
namespace
88
{
89
  // A single condition variable controlling all static initializations.
90
  static __gnu_cxx::__cond* static_cond;
91
 
92
  // using a fake type to avoid initializing a static class.
93
  typedef char fake_cond_t[sizeof(__gnu_cxx::__cond)]
94
  __attribute__ ((aligned(__alignof__(__gnu_cxx::__cond))));
95
  fake_cond_t fake_cond;
96
 
97
  static void init_static_cond()
98
  { static_cond =  new (&fake_cond) __gnu_cxx::__cond(); }
99
 
100
  __gnu_cxx::__cond&
101
  get_static_cond()
102
  {
103
    static __gthread_once_t once = __GTHREAD_ONCE_INIT;
104
    __gthread_once(&once, init_static_cond);
105
    return *static_cond;
106
  }
107
}
108
# endif
109
 
110
# ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
111
inline bool
112
__test_and_acquire (__cxxabiv1::__guard *g)
113
{
114
  bool b = _GLIBCXX_GUARD_TEST (g);
115
  _GLIBCXX_READ_MEM_BARRIER;
116
  return b;
117
}
118
#  define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __test_and_acquire (G)
119
# endif
120
 
121
# ifndef _GLIBCXX_GUARD_SET_AND_RELEASE
122
inline void
123
__set_and_release (__cxxabiv1::__guard *g)
124
{
125
  _GLIBCXX_WRITE_MEM_BARRIER;
126
  _GLIBCXX_GUARD_SET (g);
127
}
128
#  define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __set_and_release (G)
129
# endif
130
 
131
#else /* !__GTHREADS */
132
 
133
# undef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
134
# undef _GLIBCXX_GUARD_SET_AND_RELEASE
135
# define _GLIBCXX_GUARD_SET_AND_RELEASE(G) _GLIBCXX_GUARD_SET (G)
136
 
137
#endif /* __GTHREADS */
138
 
139
//
140
// Here are C++ run-time routines for guarded initialization of static
141
// variables. There are 4 scenarios under which these routines are called:
142
//
143
//   1. Threads not supported (__GTHREADS not defined)
144
//   2. Threads are supported but not enabled at run-time.
145
//   3. Threads enabled at run-time but __gthreads_* are not fully POSIX.
146
//   4. Threads enabled at run-time and __gthreads_* support all POSIX threads
147
//      primitives we need here.
148
//
149
// The old code supported scenarios 1-3 but was broken since it used a global
150
// mutex for all threads and had the mutex locked during the whole duration of
151
// initialization of a guarded static variable. The following created a
152
// dead-lock with the old code.
153
//
154
//	Thread 1 acquires the global mutex.
155
//	Thread 1 starts initializing static variable.
156
//	Thread 1 creates thread 2 during initialization.
157
//	Thread 2 attempts to acquire mutex to initialize another variable.
158
//	Thread 2 blocks since thread 1 is locking the mutex.
159
//	Thread 1 waits for result from thread 2 and also blocks. A deadlock.
160
//
161
// The new code here can handle this situation and thus is more robust. However,
162
// we need to use the POSIX thread condition variable, which is not supported
163
// in all platforms, notably older versions of Microsoft Windows. The gthr*.h
164
// headers define a symbol __GTHREAD_HAS_COND for platforms that support POSIX
165
// like condition variables. For platforms that do not support condition
166
// variables, we need to fall back to the old code.
167
 
168
// If _GLIBCXX_USE_FUTEX, no global mutex or condition variable is used,
169
// only atomic operations are used together with futex syscall.
170
// Valid values of the first integer in guard are:
171
// 0				  No thread encountered the guarded init
172
//				  yet or it has been aborted.
173
// _GLIBCXX_GUARD_BIT		  The guarded static var has been successfully
174
//				  initialized.
175
// _GLIBCXX_GUARD_PENDING_BIT	  The guarded static var is being initialized
176
//				  and no other thread is waiting for its
177
//				  initialization.
178
// (_GLIBCXX_GUARD_PENDING_BIT    The guarded static var is being initialized
179
//  | _GLIBCXX_GUARD_WAITING_BIT) and some other threads are waiting until
180
//				  it is initialized.
181
 
182
namespace __cxxabiv1
183
{
184
#ifdef _GLIBCXX_USE_FUTEX
185
  namespace
186
  {
187
    static inline int __guard_test_bit (const int __byte, const int __val)
188
    {
189
      union { int __i; char __c[sizeof (int)]; } __u = { 0 };
190
      __u.__c[__byte] = __val;
191
      return __u.__i;
192
    }
193
  }
194
#endif
195
 
196
  static inline int
197
  init_in_progress_flag(__guard* g)
198
  { return ((char *)g)[1]; }
199
 
200
  static inline void
201
  set_init_in_progress_flag(__guard* g, int v)
202
  { ((char *)g)[1] = v; }
203
 
204
  static inline void
205
  throw_recursive_init_exception()
206
  {
207
#ifdef __EXCEPTIONS
208
	throw __gnu_cxx::recursive_init_error();
209
#else
210
	// Use __builtin_trap so we don't require abort().
211
	__builtin_trap();
212
#endif
213
  }
214
 
215
  // acquire() is a helper function used to acquire guard if thread support is
216
  // not compiled in or is compiled in but not enabled at run-time.
217
  static int
218
  acquire(__guard *g)
219
  {
220
    // Quit if the object is already initialized.
221
    if (_GLIBCXX_GUARD_TEST(g))
222
      return 0;
223
 
224
    if (init_in_progress_flag(g))
225
      throw_recursive_init_exception();
226
 
227
    set_init_in_progress_flag(g, 1);
228
    return 1;
229
  }
230
 
231
  extern "C"
232
  int __cxa_guard_acquire (__guard *g)
233
  {
234
#ifdef __GTHREADS
235
    // If the target can reorder loads, we need to insert a read memory
236
    // barrier so that accesses to the guarded variable happen after the
237
    // guard test.
238
    if (_GLIBCXX_GUARD_TEST_AND_ACQUIRE (g))
239
      return 0;
240
 
241
# ifdef _GLIBCXX_USE_FUTEX
242
    // If __atomic_* and futex syscall are supported, don't use any global
243
    // mutex.
244
    if (__gthread_active_p ())
245
      {
246
	int *gi = (int *) (void *) g;
247
	const int guard_bit = _GLIBCXX_GUARD_BIT;
248
	const int pending_bit = _GLIBCXX_GUARD_PENDING_BIT;
249
	const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
250
 
251
	while (1)
252
	  {
253
	    int expected(0);
254
	    if (__atomic_compare_exchange_n(gi, &expected, pending_bit, false,
255
					    __ATOMIC_ACQ_REL,
256
					    __ATOMIC_ACQUIRE))
257
	      {
258
		// This thread should do the initialization.
259
		return 1;
260
	      }
261
 
262
	    if (expected == guard_bit)
263
	      {
264
		// Already initialized.
265
		return 0;
266
	      }
267
 
268
	     if (expected == pending_bit)
269
	       {
270
		 // Use acquire here.
271
		 int newv = expected | waiting_bit;
272
		 if (!__atomic_compare_exchange_n(gi, &expected, newv, false,
273
						  __ATOMIC_ACQ_REL,
274
						  __ATOMIC_ACQUIRE))
275
		   {
276
		     if (expected == guard_bit)
277
		       {
278
			 // Make a thread that failed to set the
279
			 // waiting bit exit the function earlier,
280
			 // if it detects that another thread has
281
			 // successfully finished initialising.
282
			 return 0;
283
		       }
284
		     if (expected == 0)
285
		       continue;
286
		   }
287
 
288
		 expected = newv;
289
	       }
290
 
291
	    syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAIT, expected, 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
		// condition 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 condition 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) throw ()
339
  {
340
#ifdef _GLIBCXX_USE_FUTEX
341
    // If __atomic_* 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 = __atomic_exchange_n (gi, 0, __ATOMIC_ACQ_REL);
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 condition 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
    // condition variables.
371
    if (__gthread_active_p ())
372
      static_mutex->unlock();
373
#endif
374
  }
375
 
376
  extern "C"
377
  void __cxa_guard_release (__guard *g) throw ()
378
  {
379
#ifdef _GLIBCXX_USE_FUTEX
380
    // If __atomic_* 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 = __atomic_exchange_n (gi, guard_bit, __ATOMIC_ACQ_REL);
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
    // condition variables.
412
    if (__gthread_active_p())
413
      static_mutex->unlock();
414
#endif
415
  }
416
}