OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libstdc++-v3/] [libsupc++/] [guard.cc] - Blame information for rev 749

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 742 jeremybenn
// 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
// <http://www.gnu.org/licenses/>.
24
 
25
// Written by Mark Mitchell, CodeSourcery LLC, <mark@codesourcery.com>
26
// Thread support written by Jason Merrill, Red Hat Inc. <jason@redhat.com>
27
 
28
#include <bits/c++config.h>
29
#include <cxxabi.h>
30
#include <exception>
31
#include <new>
32
#include <ext/atomicity.h>
33
#include <ext/concurrence.h>
34
#if defined(__GTHREADS) && defined(__GTHREAD_HAS_COND) \
35
  && (ATOMIC_INT_LOCK_FREE > 1) && defined(_GLIBCXX_HAVE_LINUX_FUTEX)
36
# include <climits>
37
# include <syscall.h>
38
# include <unistd.h>
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
        int expected(0);
248
        const int guard_bit = _GLIBCXX_GUARD_BIT;
249
        const int pending_bit = _GLIBCXX_GUARD_PENDING_BIT;
250
        const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
251
 
252
        while (1)
253
          {
254
            if (__atomic_compare_exchange_n(gi, &expected, pending_bit, false,
255
                                            __ATOMIC_ACQ_REL,
256
                                            __ATOMIC_RELAXED))
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
             if (expected == pending_bit)
268
               {
269
                 int newv = expected | waiting_bit;
270
                 if (!__atomic_compare_exchange_n(gi, &expected, newv, false,
271
                                                  __ATOMIC_ACQ_REL,
272
                                                  __ATOMIC_RELAXED))
273
                   continue;
274
 
275
                 expected = newv;
276
               }
277
 
278
            syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAIT, expected, 0);
279
          }
280
      }
281
# else
282
    if (__gthread_active_p ())
283
      {
284
        mutex_wrapper mw;
285
 
286
        while (1)       // When this loop is executing, mutex is locked.
287
          {
288
#  ifdef __GTHREAD_HAS_COND
289
            // The static is already initialized.
290
            if (_GLIBCXX_GUARD_TEST(g))
291
              return 0;  // The mutex will be unlocked via wrapper
292
 
293
            if (init_in_progress_flag(g))
294
              {
295
                // The guarded static is currently being initialized by
296
                // another thread, so we release mutex and wait for the
297
                // condition variable. We will lock the mutex again after
298
                // this.
299
                get_static_cond().wait_recursive(&get_static_mutex());
300
              }
301
            else
302
              {
303
                set_init_in_progress_flag(g, 1);
304
                return 1; // The mutex will be unlocked via wrapper.
305
              }
306
#  else
307
            // This provides compatibility with older systems not supporting
308
            // POSIX like condition variables.
309
            if (acquire(g))
310
              {
311
                mw.unlock = false;
312
                return 1; // The mutex still locked.
313
              }
314
            return 0; // The mutex will be unlocked via wrapper.
315
#  endif
316
          }
317
      }
318
# endif
319
#endif
320
 
321
    return acquire (g);
322
  }
323
 
324
  extern "C"
325
  void __cxa_guard_abort (__guard *g) throw ()
326
  {
327
#ifdef _GLIBCXX_USE_FUTEX
328
    // If __atomic_* and futex syscall are supported, don't use any global
329
    // mutex.
330
    if (__gthread_active_p ())
331
      {
332
        int *gi = (int *) (void *) g;
333
        const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
334
        int old = __atomic_exchange_n (gi, 0, __ATOMIC_ACQ_REL);
335
 
336
        if ((old & waiting_bit) != 0)
337
          syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAKE, INT_MAX);
338
        return;
339
      }
340
#elif defined(__GTHREAD_HAS_COND)
341
    if (__gthread_active_p())
342
      {
343
        mutex_wrapper mw;
344
 
345
        set_init_in_progress_flag(g, 0);
346
 
347
        // If we abort, we still need to wake up all other threads waiting for
348
        // the condition variable.
349
        get_static_cond().broadcast();
350
        return;
351
      }
352
#endif
353
 
354
    set_init_in_progress_flag(g, 0);
355
#if defined(__GTHREADS) && !defined(__GTHREAD_HAS_COND)
356
    // This provides compatibility with older systems not supporting POSIX like
357
    // condition variables.
358
    if (__gthread_active_p ())
359
      static_mutex->unlock();
360
#endif
361
  }
362
 
363
  extern "C"
364
  void __cxa_guard_release (__guard *g) throw ()
365
  {
366
#ifdef _GLIBCXX_USE_FUTEX
367
    // If __atomic_* and futex syscall are supported, don't use any global
368
    // mutex.
369
    if (__gthread_active_p ())
370
      {
371
        int *gi = (int *) (void *) g;
372
        const int guard_bit = _GLIBCXX_GUARD_BIT;
373
        const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
374
        int old = __atomic_exchange_n (gi, guard_bit, __ATOMIC_ACQ_REL);
375
 
376
        if ((old & waiting_bit) != 0)
377
          syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAKE, INT_MAX);
378
        return;
379
      }
380
#elif defined(__GTHREAD_HAS_COND)
381
    if (__gthread_active_p())
382
      {
383
        mutex_wrapper mw;
384
 
385
        set_init_in_progress_flag(g, 0);
386
        _GLIBCXX_GUARD_SET_AND_RELEASE(g);
387
 
388
        get_static_cond().broadcast();
389
        return;
390
      }
391
#endif
392
 
393
    set_init_in_progress_flag(g, 0);
394
    _GLIBCXX_GUARD_SET_AND_RELEASE (g);
395
 
396
#if defined(__GTHREADS) && !defined(__GTHREAD_HAS_COND)
397
    // This provides compatibility with older systems not supporting POSIX like
398
    // condition variables.
399
    if (__gthread_active_p())
400
      static_mutex->unlock();
401
#endif
402
  }
403
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.